diff --git a/CMakeLists.txt b/CMakeLists.txt index 30195f7..8c28e2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ target_include_directories(webcam PRIVATE target_compile_definitions(webcam PRIVATE __PLATFORM_WINDOWS__ - WIN32 + WIN64 _USRDLL _GS_DLL_EXPORT ) @@ -42,7 +42,7 @@ target_link_libraries(webcam PRIVATE platform engine framework - opencv_world300 + opencv_world345 extern Ws2_32 diff --git a/bin/opencv_world345.dll b/bin/opencv_world345.dll new file mode 100644 index 0000000..03d7a22 Binary files /dev/null and b/bin/opencv_world345.dll differ diff --git a/include/engine/automation/automated_property_provider.cpp b/include/engine/automation/automated_property_provider.cpp new file mode 100644 index 0000000..23be96f --- /dev/null +++ b/include/engine/automation/automated_property_provider.cpp @@ -0,0 +1,23 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "automation/automated_property_provider.h" + #include "math/quaternion.h" + + using namespace GS::Automation; + using GS::Core::MotionChannel; + + +//------------------------------------------------------------------------------ +bool IPropertyProvider::GetProperty(MotionChannel::Type, float &) +{ return false; } +bool IPropertyProvider::SetProperty(MotionChannel::Type, float) +{ return false; } +GS::Quaternion IPropertyProvider::GetRotation() const +{ return Quaternion(); } +bool IPropertyProvider::SetRotation(const GS::Quaternion &) +{ return false; } +//------------------------------------------------------------------------------ diff --git a/include/engine/automation/automation_player.cpp b/include/engine/automation/automation_player.cpp new file mode 100644 index 0000000..d5a2a5b --- /dev/null +++ b/include/engine/automation/automation_player.cpp @@ -0,0 +1,152 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #ifndef __PLATFORM_IOS__ + #include + #endif + #include "automation/automation_player.h" + #include "automation/automation_source.h" + #include "platform_config.h" + + using namespace GS::Automation; + + +//------------------------------------------------------------------------------ +Motion *Player::GetMotion(const char *id) const +{ + ListForeachPtr(Motion *, i, motions) + if (!String::Compare(i->name, id)) + return i; + return NULL; +} +Motion *Player::GetMotionFromIndex(uint index) const +{ return motions.ObjectAt(index); } +bool Player::AddMotion(Motion *motion) +{ return asbool(motions.Add(motion)); } +void Player::RemoveMotion(Motion *motion) +{ motions.Remove(motion); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Source *Player::StartAutomation(Source *source, float _blend, AddSourceMode mode, float _weight) +{ + if (!source) + return NULL; + + // Source blend. + switch (mode) + { + case SourceSet: // Dispose of all current sources. + ListForeachPtr(Source *, s, sources) + s->Dispose(_blend); + break; + + default: break; + } + + // Blend in source. + source->SetWeight(_weight, _blend); + sources.Add(source); + + switch (source->GetType()) + { + case Source::TypeMotion: + source->relative = flags.IsSet(FlagRelativeMotion); + break; + + default: break; + } + return source; +} +void Player::Evaluate(const GS::Time &dt_time) +{ + if (!sources.GetCount() || property_provider.IsNull()) + return; + + // Allocate weight table from stack. + weight_table = (float *)alloca(sizeof(float) * MotionChannel::Last); + for (int n = 0; n < MotionChannel::Last; ++n) + weight_table[n] = 0; + + // Update sources. + ListForeachPtr(Source *, s, sources) + { + s->Update(dt_time); + if (s->CanDispose()) + sources.Remove(s); + } + + // Mix rotation. + float w = 0; + Quaternion q, source_q = property_provider->GetRotation(); + + ListForeachPtr(Source *, s, sources) + if (s->GetWeight() > 0.01) + if (s->EvaluateRotation(source_q)) + { + if (w > 0.01) + q = Quaternion::Slerp(w / (w + s->GetWeight()), source_q, q); + else q = source_q; + + w += s->GetWeight(); + } + + if (w > 0) + property_provider->SetRotation(q); + + // Mix sources. + ListForeachPtr(Source *, s, sources) + if (s->GetWeight()) + s->Evaluate(*this); + + // Drop weight table. + weight_table = NULL; +} +void Player::BlendAutomatedProperty(MotionChannel::Type type, float _v, float _w) +{ + if (!_w || !weight_table) + return; + + float v, *w = &weight_table[(uint)type]; + + if (property_provider->GetProperty(type, v)) + { + v = (v * *w + _v * _w) / (*w + _w); + *w += _w; + property_provider->SetProperty(type, v); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Player::IsAutomated() const +{ return asbool(sources.GetCount()); } +bool Player::IsAutomationDone() const +{ + ListForeachPtr(Source *, s, GetSourceList()) + if (!s->IsDone()) + return false; + return true; +} +bool Player::GetAutomationActive() const +{ return active; } +void Player::SetAutomationActive(bool _active) +{ active = _active; } +void Player::DisposeAutomationSources() +{ sources.Clear(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Player::Player() +{ + active = true; + weight_table = NULL; +} +Player::~Player() +{ + DisposeAutomationSources(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/automation/automation_player_nml.cpp b/include/engine/automation/automation_player_nml.cpp new file mode 100644 index 0000000..08f33ea --- /dev/null +++ b/include/engine/automation/automation_player_nml.cpp @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "automation/automation_player.h" + #include "motion/motion.h" + #include "memory/memory.h" + #include "log/log.h" + + using namespace GS::Automation; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool Player::FromMetaTag(Tag &tag) +{ + if (tag.name != "MotionPlayer") + __ERR__(__LOG_E__ << "Could not parse motion player, incorrect root tag (" << tag.name << ").\n", false) + + NMLTagForeach(pt, tag) + { + if (pt->name == "Motions") + { + NMLTagForeach(pm, *pt) + if (pm->name == "Motion") + { + if (Motion *m = new Motion) + { + m->FromMetaTag(*pm); + motions.Add(m); + } + } + else __LOG_W__ << "Unknown tag '" << pm->name << "' in .\n"; + } + #if 1 + else if (pt->name == "Flag") + ; + #endif + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *Player::AsMetaTag() +{ + Tag *root = new Tag("MotionPlayer"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + // Dump all motions. + if (Tag *mtag = root->AddChild("Motions")) + ListForeachPtr(Motion *, m, motions) + mtag->AddChild(m->AsMetaTag()); + + if (!root->GetChildCount()) + _safe_delete(root); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/automation/automation_source.cpp b/include/engine/automation/automation_source.cpp new file mode 100644 index 0000000..8a53135 --- /dev/null +++ b/include/engine/automation/automation_source.cpp @@ -0,0 +1,81 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "automation/automation_source.h" + + using namespace GS::Automation; + + +//------------------------------------------------------------------------------ +void Source::Dispose(float blend) +{ + if (!dispose) + { + SetWeight(0, blend); + dispose = true; + } +} +bool Source::CanDispose() const +{ return asbool(dispose && (weight == 0)); } +void Source::Update(const GS::Time &dt_time) +{ + const Time scaled_dt(dt_time * time_scale); + + // Update weight. + if (weight_step) + { + weight += weight_step * dt_time.toSec(); + + if (weight_step > 0) + { + if (weight > weight_target) + { + weight = weight_target; + weight_step = 0; + } + } + else + { + if (weight < weight_target) + { + weight = weight_target; + weight_step = 0; + } + } + } + time += scaled_dt; +} +void Source::SetWeight(float _weight, float _blend) +{ + if (_weight < 0) + _weight = 0; + if (_blend < 0) + _blend = 0; + + if (_blend) + { + weight_target = _weight; + weight_step = (_weight - weight) / _blend; + } + else + { + weight = _weight; + weight_target = _weight; + weight_step = 0; + } +} +Source::Source() +{ + weight = 0; + weight_target = 1; + weight_step = 0; + + time_scale = 1; + + dispose = false; +} +Source::~Source() {} +//------------------------------------------------------------------------------ diff --git a/include/engine/automation/automation_source_group.cpp b/include/engine/automation/automation_source_group.cpp new file mode 100644 index 0000000..7bd49ab --- /dev/null +++ b/include/engine/automation/automation_source_group.cpp @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "automation/automation_source_group.h" + + using namespace GS::Automation; + + +//------------------------------------------------------------------------------ +void SourceGroup::Dispose(float blend) +{ ListForeachPtr(Source *, s, source_list) + s->Dispose(blend); } +void SourceGroup::SetTime(const GS::Time &t) +{ ListForeachPtr(Source *, s, source_list) + s->time = t; } +void SourceGroup::SetTimeScale(float scale) +{ ListForeachPtr(Source *, s, source_list) + s->time_scale = scale; } +void SourceGroup::SetWeight(float weight, float blend) +{ ListForeachPtr(Source *, s, source_list) + s->SetWeight(weight, blend); } +void SourceGroup::SetRelative(bool relative) +{ ListForeachPtr(Source *, s, source_list) + s->relative = relative; } +void SourceGroup::SetLoop(const GS::Time &start, const GS::Time &end) +{ ListForeachPtr(Source *, s, source_list) + s->SetLoop(start, end); } +void SourceGroup::SetLoopMode(GS::Curve::LoopMode mode) +{ ListForeachPtr(Source *, s, source_list) + s->SetLoopMode(mode); } +bool SourceGroup::IsDone() const +{ + ListForeachPtr(Source *, s, source_list) + if (!s->IsDone()) + return false; + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/ace.cpp b/include/engine/core/ace.cpp new file mode 100644 index 0000000..7be0872 --- /dev/null +++ b/include/engine/core/ace.cpp @@ -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 ::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 ::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) +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/ace_unit.cpp b/include/engine/core/ace_unit.cpp new file mode 100644 index 0000000..089fa8e --- /dev/null +++ b/include/engine/core/ace_unit.cpp @@ -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(); +} diff --git a/include/engine/core/cached_graphic_resource_factory.cpp b/include/engine/core/cached_graphic_resource_factory.cpp new file mode 100644 index 0000000..5484d29 --- /dev/null +++ b/include/engine/core/cached_graphic_resource_factory.cpp @@ -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 bool DoLoadResource(const char *name, T &t) +{ return NML::LoadFromFile(t, name); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template T *LoadResourceCommonSeq(const char *name, SharedList &list) +{ + if (!name) + return NULL; + + ListForeachPtr(T *, t, list) + if (t->name == name) + return t; + + AutoPtr 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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/cached_mixer_resource_factory.cpp b/include/engine/core/cached_mixer_resource_factory.cpp new file mode 100644 index 0000000..c29b86b --- /dev/null +++ b/include/engine/core/cached_mixer_resource_factory.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/cached_renderer_resource_factory.cpp b/include/engine/core/cached_renderer_resource_factory.cpp new file mode 100644 index 0000000..3a4e072 --- /dev/null +++ b/include/engine/core/cached_renderer_resource_factory.cpp @@ -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 static bool ResourceNameCompare(const T o, const String &name) { return String::Compare(o->name, name) == 0; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template T CheckCachedResourceCommonSeq(const char *uri, const SharedList *cache) +{ + if (!cache) + return NULL; + + String name(uri); + name.FileCleanName(); + + return ListFindEx(*cache, ResourceNameCompare , name); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Geometry *CachedRendererResourceFactory::LoadGeometry(const char *name, bool bypass_cache, Geometry *g) +{ + if (!bypass_cache && !g) + if (Geometry *r = CheckCachedResourceCommonSeq (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 (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 (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 (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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/camera.cpp b/include/engine/core/camera.cpp new file mode 100644 index 0000000..7cac4cb --- /dev/null +++ b/include/engine/core/camera.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/camera_nml.cpp b/include/engine/core/camera_nml.cpp new file mode 100644 index 0000000..7438565 --- /dev/null +++ b/include/engine/core/camera_nml.cpp @@ -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 .\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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/clock.cpp b/include/engine/core/clock.cpp new file mode 100644 index 0000000..d2ab5c7 --- /dev/null +++ b/include/engine/core/clock.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/core_profiler.cpp b/include/engine/core/core_profiler.cpp new file mode 100644 index 0000000..81b4b15 --- /dev/null +++ b/include/engine/core/core_profiler.cpp @@ -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 +} +//-------------------------------------------------------------------------- diff --git a/include/engine/core/embedded_resource_extractor.cpp b/include/engine/core/embedded_resource_extractor.cpp new file mode 100644 index 0000000..5b07ce1 --- /dev/null +++ b/include/engine/core/embedded_resource_extractor.cpp @@ -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/"); +} diff --git a/include/engine/core/embedded_resource_handler_interface.cpp b/include/engine/core/embedded_resource_handler_interface.cpp new file mode 100644 index 0000000..1110edc --- /dev/null +++ b/include/engine/core/embedded_resource_handler_interface.cpp @@ -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 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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/emitter.cpp b/include/engine/core/emitter.cpp new file mode 100644 index 0000000..c56a9fc --- /dev/null +++ b/include/engine/core/emitter.cpp @@ -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 &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 ::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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/emitter_nml.cpp b/include/engine/core/emitter_nml.cpp new file mode 100644 index 0000000..bf5fe05 --- /dev/null +++ b/include/engine/core/emitter_nml.cpp @@ -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 .\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 .\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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry.cpp b/include/engine/core/geometry.cpp new file mode 100644 index 0000000..17e5cd5 --- /dev/null +++ b/include/engine/core/geometry.cpp @@ -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 &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 &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 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 &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 &vtx_to_pol) const +{ + if (!pol || !vtx) + return; + + Array 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 &vtx_to_vtx, const Array *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 _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 &flag, const Array &pol_index, const Array &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 drop(material_table.GetCount()); + for (uint n = 0; n < material_table.GetCount(); ++n) + drop[n] = false; + + Array 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 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(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry_bih.cpp b/include/engine/core/geometry_bih.cpp new file mode 100644 index 0000000..4cce1e3 --- /dev/null +++ b/include/engine/core/geometry_bih.cpp @@ -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 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(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry_kdtree.cpp b/include/engine/core/geometry_kdtree.cpp new file mode 100644 index 0000000..2f4aea6 --- /dev/null +++ b/include/engine/core/geometry_kdtree.cpp @@ -0,0 +1,1141 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include + #include "core/geometry_kdtree.h" + #include "core/geometry.h" + #include "scene3d/mobject.h" + #include "scene3d/mlight.h" + #include "scene3d/mcamera.h" + #include "timing/benchmark.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Core; + + +GeometryKDTree::KDTreeNode::KDTreeNode(){m_KDTREE_NODE_ID_POLY = NULL; m_KDTREE_NODE_ID_VTX = NULL; memset(m_KDTREE_NODE_ID_ROPE, -1, sizeof(int)*6);}; + +#define KDTREE_MAX_DEPTH 20 +#define KDTREE_MAX_POLY_PER_NODE 5 + +#define X 0 +#define Y 1 +#define Z 2 + +#define CROSS(dest,v1,v2) \ + dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ + dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ + dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; + +#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) + +#define SUB(dest,v1,v2) \ + dest[0]=v1[0]-v2[0]; \ + dest[1]=v1[1]-v2[1]; \ + dest[2]=v1[2]-v2[2]; + +#define FINDMINMAX(x0,x1,x2,Min,Max) \ + Min = Max = x0; \ + if(x1Max) Max=x1;\ + if(x2Max) Max=x2; + + +//----------------------------------------------------------------------------------- +int GeometryKDTree::planeBoxOverlap(float normal[3], float vert[3], float maxbox[3]) +//----------------------------------------------------------------------------------- +{ + int q; + float vmin[3],vmax[3],v; + + for(q=X;q<=Z;q++) + { + v=vert[q]; + + if(normal[q]>0.0f) + { + vmin[q]=-maxbox[q] - v; + vmax[q]= maxbox[q] - v; + } + else + { + vmin[q]= maxbox[q] - v; + vmax[q]=-maxbox[q] - v; + } + } + + if(DOT(normal,vmin)>0.0f) + return 0; + + if(DOT(normal,vmax)>=0.0f) + return 1; + + return 0; + +} + +/*======================== X-tests ========================*/ + +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a*v0[Y] - b*v0[Z]; \ + p2 = a*v2[Y] - b*v2[Z]; \ + if(p0rad || max<-rad) return 0; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a*v0[Y] - b*v0[Z]; \ + p1 = a*v1[Y] - b*v1[Z]; \ + if(p0rad || max<-rad) return 0; + +/*======================== Y-tests ========================*/ + +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a*v0[X] + b*v0[Z]; \ + p2 = -a*v2[X] + b*v2[Z]; \ + if(p0rad || max<-rad) return 0; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a*v0[X] + b*v0[Z]; \ + p1 = -a*v1[X] + b*v1[Z]; \ + if(p0rad || max<-rad) return 0; + +/*======================== Z-tests ========================*/ +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a*v1[X] - b*v1[Y]; \ + p2 = a*v2[X] - b*v2[Y]; \ + if(p2rad || max<-rad) return 0; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a*v0[X] - b*v0[Y]; \ + p1 = a*v1[X] - b*v1[Y]; \ + if(p0rad || max<-rad) return 0; + +//------------------------------------------------------------------------------------------------------------------------- +int GeometryKDTree::triBoxOverlap(float boxcenter[3],float boxhalfsize[3],float Verts1[3],float Verts2[3],float Verts3[3]) +//------------------------------------------------------------------------------------------------------------------------- + +{ /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + + float v0[3],v1[3],v2[3]; + + // float axis[3]; + float min,max,p0,p1,p2,rad,fex,fey,fez; // -NJMP- "d" local variable removed + float normal[3],e0[3],e1[3],e2[3]; + + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + SUB(v0,Verts1,boxcenter); + SUB(v1,Verts2,boxcenter); + SUB(v2,Verts3,boxcenter); + + /* compute triangle edges */ + SUB(e0,v1,v0); /* tri edge 0 */ + SUB(e1,v2,v1); /* tri edge 1 */ + SUB(e2,v0,v2); /* tri edge 2 */ + + /* Bullet 3: */ + + /* test the 9 tests first (this was faster) */ + fex = fabsf(e0[X]); + fey = fabsf(e0[Y]); + fez = fabsf(e0[Z]); + + AXISTEST_X01(e0[Z], e0[Y], fez, fey); + AXISTEST_Y02(e0[Z], e0[X], fez, fex); + AXISTEST_Z12(e0[Y], e0[X], fey, fex); + + fex = fabsf(e1[X]); + fey = fabsf(e1[Y]); + fez = fabsf(e1[Z]); + + AXISTEST_X01(e1[Z], e1[Y], fez, fey); + AXISTEST_Y02(e1[Z], e1[X], fez, fex); + AXISTEST_Z0(e1[Y], e1[X], fey, fex); + + fex = fabsf(e2[X]); + fey = fabsf(e2[Y]); + fez = fabsf(e2[Z]); + + AXISTEST_X2(e2[Z], e2[Y], fez, fey); + AXISTEST_Y1(e2[Z], e2[X], fez, fex); + AXISTEST_Z12(e2[Y], e2[X], fey, fex); + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + /* test in X-direction */ + FINDMINMAX(v0[X],v1[X],v2[X],min,max); + + if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0; + + /* test in Y-direction */ + FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max); + + if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0; + + /* test in Z-direction */ + FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max); + + if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + + CROSS(normal,e0,e1); + + if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0; + + return 1; /* box and triangle overlaps */ +} + +//--------------------------------------------------------------------------------------------- +int GeometryKDTree::GetKDtreeSideAABB(float* _AABB, Vector4 &_EntryPoint, int &_LastEntrySide) +//--------------------------------------------------------------------------------------------- +{ + int l_AvoidSide = _LastEntrySide; + if(_LastEntrySide != -1) + { + if(_LastEntrySide%2) + l_AvoidSide = _LastEntrySide-1; + else + l_AvoidSide = _LastEntrySide+1; + } + + // check the nearest plane for the nearest rope + int l_SideChoose = -1; + float l_Dist = 3.402823466e+38F; + + float l_CheckDist = fabs(_AABB[KDTREE_SIDE_LEFT] - _EntryPoint.x); + if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_LEFT) + { + l_SideChoose = KDTREE_SIDE_LEFT; + l_Dist = l_CheckDist; + } + + l_CheckDist = fabs(_AABB[KDTREE_SIDE_RIGHT] - _EntryPoint.x); + if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_RIGHT) + { + l_SideChoose = KDTREE_SIDE_RIGHT; + l_Dist = l_CheckDist; + } + + l_CheckDist = fabs(_AABB[KDTREE_SIDE_BOTTOM] - _EntryPoint.y); + if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_BOTTOM) + { + l_SideChoose = KDTREE_SIDE_BOTTOM; + l_Dist = l_CheckDist; + } + + l_CheckDist = fabs(_AABB[KDTREE_SIDE_TOP] - _EntryPoint.y); + if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_TOP) + { + l_SideChoose = KDTREE_SIDE_TOP; + l_Dist = l_CheckDist; + } + + l_CheckDist = fabs(_AABB[KDTREE_SIDE_BACK] - _EntryPoint.z); + if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_BACK) + { + l_SideChoose = KDTREE_SIDE_BACK; + l_Dist = l_CheckDist; + } + + l_CheckDist = fabs(_AABB[KDTREE_SIDE_FRONT] - _EntryPoint.z); + if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_FRONT) + { + l_SideChoose = KDTREE_SIDE_FRONT; + l_Dist = l_CheckDist; + } + + _LastEntrySide = l_SideChoose; + + return l_SideChoose; +} + +//-------------------------------------------------------------------------------------------------------------------------------------------------------------------- +bool GeometryKDTree::IntersectTriangle(const Vector4 &s, const Vector4 &d, float* Vtx1, float* Vtx2, float* Vtx3, Vector4* _Edge1, Vector4* _Edge2, float &l_Dist, float &u, float &v, bool& _Backface) +//-------------------------------------------------------------------------------------------------------------------------------------------------------------------- +{ + const float EPSILON = 0.000001f; + l_Dist = 3.402823466e+38F; + + //test if inside the plane + + /* find vectors for two edges sharing vert0 */ + //nVector l_edge1(Vtx2[0] - Vtx1[0], Vtx2[1] - Vtx1[1], Vtx2[2] - Vtx1[2]); + //nVector l_edge2(Vtx3[0] - Vtx1[0], Vtx3[1] - Vtx1[1], Vtx3[2] - Vtx1[2]); + + /* begin calculating determinant - also used to calculate U parameter */ + //nVector l_pvec = d.Cross( *_Edge2); + Vector4 l_pvec(d.y * _Edge2->z - d.z * _Edge2->y, d.z * _Edge2->x - d.x * _Edge2->z, d.x * _Edge2->y - d.y * _Edge2->x); + + /* if determinant is near zero, ray lies in plane of triangle */ + float l_det = _Edge1->Dot( l_pvec); + + /* the non-culling branch */ + if (l_det <= -EPSILON || l_det >= EPSILON) + { + float l_inv_det = 1.0f / l_det; + + /* calculate distance from vert0 to ray origin */ + Vector4 l_tvec(s.x - Vtx1[0], s.y - Vtx1[1], s.z - Vtx1[2]); + + /* calculate U parameter and test bounds */ + float _u = l_tvec.Dot( l_pvec) * l_inv_det; + if (_u >= 0.0f && _u <= 1.0f) + { + /* prepare to test V parameter */ + Vector4 l_qvec = l_tvec.Cross( *_Edge1); + + /* calculate V parameter and test bounds */ + float _v = d.Dot( l_qvec) * l_inv_det; + if (_v >= 0.0f && _u + _v <= 1.0f) + { + /* calculate t, ray intersects triangle */ + l_Dist = _Edge2->Dot( l_qvec) * l_inv_det; + u = _u; + v = _v; + + if (l_det <= -EPSILON ) + _Backface = true; + + return true; + } + } + } + return false; +} + +//---------------------------------------------------------------------------------------------------------------- +bool GeometryKDTree::AABBIntersectRay(float* _AABB, const Vector4 &o, const Vector4 &d, float &tmin, float &tmax) +//---------------------------------------------------------------------------------------------------------------- +{ + tmin = 0; + tmax = 3.402823466e+38F; + + for (uint n = 0; n < 3; ++n) + if (Math::EqualZero(d[n])) + { + if ((o[n] < _AABB[n*2]) || (o[n] > _AABB[n*2+1])) + return false; + } + else + { + float ood = 1.f / d[n]; + float t0 = (_AABB[n*2] - o[n]) * ood; + float t1 = (_AABB[n*2+1] - o[n]) * ood; + + if (t0 > t1) + { float swp = t1; t1 = t0; t0 = swp; } + + tmin = tmin < t0 ? t0 : tmin; + tmax = tmax < t1 ? tmax : t1; + + if (tmin > tmax) + return false; + } + return true; +} + +//--------------------------------------------------- +int GeometryKDTree::InsideKdTreeNode(const Vector4 &s, bool CheckInside) +//--------------------------------------------------- +{ + 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: + if(s.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: + if(s.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: + if(s.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; + } + } + + if(!CheckInside || + (m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[0] <= s.x && s.x <= m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[1] && + m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[2] <= s.y && s.y <= m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[3] && + m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[4] <= s.z && s.z <= m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[5] )) + return l_CurrentNode; + else + return -1; +} + +//--------------------------------------------------------------------------------------------------------------- +void GeometryKDTree::RaytraceGeometry(GeometryTrace &trace, const Vector4 &s, const Vector4 &d, float dist_max) +//--------------------------------------------------------------------------------------------------------------- +{ + trace.has_i = false; + +// ray_count++; + trace.tri_test = 1; + + if(m_count_bih <= 0) + return; + + float l_DistEntry, l_DistExit; + + int l_CurrentNode = 0; + + // test the ray pass in this kdtree + if(!AABBIntersectRay(m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB, s, d, l_DistEntry, l_DistExit)) + return; + + // set the max distance + if(dist_max != -1.0f && dist_max < l_DistExit) + l_DistExit = dist_max; + + l_DistEntry *= 0.9999f; + + int l_LastEntrySide = -1; + Vector4 l_PointEntry; + float l_NearestDist = 3.402823466e+38F; + + while(l_DistEntry < l_DistExit) + { + l_PointEntry = s + d*l_DistEntry; + + 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 = l_PointEntry.x ; + if(l_X == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) +// { +// float l_TempDistEntry, l_TempDistExit; +// if(AABBIntersectRay(m_NodeTree[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT].m_KDTREE_NODE_AABB, s, d, l_TempDistEntry, l_TempDistExit)) +// { +// float l_TempDistEntry2, l_TempDistExit2; +// if(AABBIntersectRay(m_NodeTree[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT].m_KDTREE_NODE_AABB, s, d, l_TempDistEntry2, l_TempDistExit2)) +// { +// if(l_DistEntry < l_TempDistEntry2 ) +// 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; +// } +// else +// 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; +// } + l_X += d.x*0.001f; + //else + 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 = l_PointEntry.y ; + if(l_Y == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) + l_Y += d.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 = l_PointEntry.z; + if(l_Z == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) + l_Z += d.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; + } + } + + float l_CurrentDistEntry, l_CurrentDistExit; + if(AABBIntersectRay(m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB, s, d, l_CurrentDistEntry, l_CurrentDistExit)) + { + // it's a leaf continue by check the intersect triangle + int* l_TempPntVtx = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_VTX; + int l_CountPoly = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_COUNT_POLY; + for(int i=0; i< l_CountPoly; ++i) + { + float l_Dist = 0, u, v; + bool l_Backface = false; + if(IntersectTriangle(s, d, m_Vtx+(*(l_TempPntVtx))*4, m_Vtx+(*(l_TempPntVtx+1))*4, m_Vtx+(*(l_TempPntVtx+2))*4, &m_OptimizeEdgePoly[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_POLY[i]*2], &m_OptimizeEdgePoly[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_POLY[i]*2+1], l_Dist, u, v ,l_Backface) == 1) + {// intersection with this triangle , change the end entry + // the dist have to be between entry and exit + if(l_Dist >= 0 && l_Dist < l_NearestDist && l_CurrentDistEntry <= l_Dist*1.0001f && l_Dist* 0.9999f <= l_CurrentDistExit) + { + l_NearestDist = l_Dist; + + int ip = m_RealIdPoly[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_POLY[i]]; + if(geometry->pol_normal.GetCount() > ip && geometry->pol.GetCount() > ip) + { + float dnv = trace.d.Dot(geometry->pol_normal[ip]); + Material *m = material_table[geometry->pol[ip].material]; + + if(!l_Backface || (dnv >= 0.f && m && m->renderword & Material::Render_DoubleSided)) + { + l_DistExit = l_Dist; + + trace.g = geometry; + trace.m = m; + trace.bi = pol_index[ip]; + trace.ip = ip; + + trace.backface = false; + + trace.s = s; + trace.d = d; + + trace.has_i = true; + trace.i_t = l_Dist; + + trace.it = 0; + + if(geometry->pol[ip].vtx_count == 4 && ((uint)*(l_TempPntVtx+1)) == geometry->pol[ip].binding[3]) + { + trace.u = 1-u; + trace.v = 1-v; + } + else + { + trace.u = u; + trace.v = v; + } + trace.w = 1.0f - trace.u - trace.v; + + trace.backface = l_Backface; + } + } + } + } + l_TempPntVtx +=3; + } + } + + // found a hit so your job is done here ! for now... + // wrong idea, if a big triangle is in a node before another little triangle at the good place but in a cell later. + if(trace.has_i) + return; + + l_DistEntry = l_CurrentDistExit*1.0000001f; + + // l_CurrentNode = 0; + + // get the rope + l_PointEntry = s + d*l_CurrentDistExit; + int l_SideChoosen = GetKDtreeSideAABB(m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB, l_PointEntry, l_LastEntrySide); + + if(l_SideChoosen == -1) // if no node, no intersection + return; + else + l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_ROPE[l_SideChoosen]; + + // if no rope + if(l_CurrentNode < 0) + return; + } +} + +//------------------------------------------------------------------ +void GeometryKDTree::CreateRope(int &_CurrentNode, int *_RopeArray) +//------------------------------------------------------------------ +{ + if(m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF ) + { + // finish the depth + + int * l_TempRope = m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_ROPE; + + memcpy(l_TempRope, _RopeArray, sizeof(int)*6); + } + else + { + // copy the aabb to the child and change copy the right id into the left aabb and inverse + float* l_AABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB; + + // do an optimization + for (int i=0; i<6; ++i) + { + if(_RopeArray[i] != -1) + { + while(!m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_IS_LEAF) + { + char l_TempTypeSplitAxisRope = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_TYPE_SPLIT; + + // if the type axis is the same as the current node + if((int)(i*0.5f) == l_TempTypeSplitAxisRope) + { + // give the id node depend of the axis, if the rope is from the right, stay on the right + if(i%2) + _RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_LEFT; + else + _RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_RIGHT; + } + else + { + // check the nearest rope to this plane, and stop if there is 2 nearest plane + float l_ValueSplitRope = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_VALUE_SPLIT; + if(l_AABB[l_TempTypeSplitAxisRope*2] > l_ValueSplitRope) + _RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_RIGHT; + else + if(l_AABB[l_TempTypeSplitAxisRope*2+1] < l_ValueSplitRope) + _RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_LEFT; + else + break; //the split axis is just in the middle of the aabb so don't clip more + } + } + } + } + + char l_TempTypeSplitAxis = m_NodeTree[_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT; + + int l_IdChildLeft = m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT; + int l_IdChildRight = m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT; + + int * l_TempLeftChildRope = m_NodeTree[l_IdChildLeft].m_KDTREE_NODE_ID_ROPE; + int * l_TempRightChildRope = m_NodeTree[l_IdChildRight].m_KDTREE_NODE_ID_ROPE; + + memcpy(l_TempLeftChildRope, _RopeArray, sizeof(int)*6); + memcpy(l_TempRightChildRope, _RopeArray, sizeof(int)*6); + + l_TempLeftChildRope[l_TempTypeSplitAxis*2+1] = l_IdChildRight; + l_TempRightChildRope[l_TempTypeSplitAxis*2] = l_IdChildLeft; + + CreateRope(l_IdChildLeft, l_TempLeftChildRope); + CreateRope(l_IdChildRight, l_TempRightChildRope); + } +} + +//------------------------------------------------------------------- +void GeometryKDTree::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= 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 + _CountPoly*3 + _CountPoly)) + { + IncreaseSizeNodeKdtreeBuffer(10000 + _CountPoly*3 + _CountPoly); + } + + 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_POLY = _CountPoly; + + m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_POLY = new int[_CountPoly]; + memcpy( m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_POLY, _IdPoly, sizeof(int)*_CountPoly); + + m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_VTX = new int[_CountPoly*3]; + memcpy( m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_VTX, _IdVtx, sizeof(int)*_CountPoly*3); + + // set the new id to set back + ++_CurrentNode; + } + else + { + m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF = false; + + float l_TempValueSplit = 0.0f; + char l_TempTypeSplitAxis = m_NodeTree[_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT; + + int l_CountAveragePoly = 0; + int *l_TempIdPnt = _IdVtx; + + float l_ExtremeRight = -3.402823466e+38F; + float l_ExtremeLeft = 3.402823466e+38F; + for(int i=0; i<_CountPoly; ++i) + { + if(l_ExtremeRight < _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis]) + l_ExtremeRight = _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis]; + if(l_ExtremeRight < _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis]) + l_ExtremeRight = _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis]; + if(l_ExtremeRight < _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis]) + l_ExtremeRight = _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis]; + + if(l_ExtremeLeft > _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis]) + l_ExtremeLeft = _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis]; + if(l_ExtremeLeft > _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis]) + l_ExtremeLeft = _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis]; + if(l_ExtremeLeft > _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis]) + l_ExtremeLeft = _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis]; + + l_TempValueSplit += ( _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis] + + _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis] + + _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis]) + ; + ++l_CountAveragePoly; + + l_TempIdPnt += 3; + } + + if(l_CountAveragePoly) + l_TempValueSplit /= (l_CountAveragePoly*3.0f); + + // check if the extreme is better split + float l_MiddleAABB = (l_TempAABB[l_TempTypeSplitAxis*2] + l_TempAABB[l_TempTypeSplitAxis*2+1])*0.5f; + + if(l_ExtremeRight < l_MiddleAABB && l_ExtremeRight > l_TempAABB[l_TempTypeSplitAxis*2]) + l_TempValueSplit = l_ExtremeRight; + else + if(l_ExtremeLeft > l_MiddleAABB && l_ExtremeLeft < l_TempAABB[l_TempTypeSplitAxis*2+1]) + l_TempValueSplit = l_ExtremeLeft; + + if(l_TempValueSplit <= l_TempAABB[l_TempTypeSplitAxis*2] || + l_TempValueSplit >= l_TempAABB[l_TempTypeSplitAxis*2+1]) + l_TempValueSplit = l_MiddleAABB; + +// if(l_TempValueSplit < _CurrentNode->m_AABB[_CurrentNode->m_TypeSplitAxis*2] || l_TempValueSplit > _CurrentNode->m_AABB[_CurrentNode->m_TypeSplitAxis*2+1] ) +// int yo = 0; + + m_NodeTree[_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT = l_TempValueSplit; + + // create the 2 childs + //set new axis + int l_NewAxis = l_TempTypeSplitAxis+1; + if(l_NewAxis >= 3) + l_NewAxis = 0; + + // 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; + + m_NodeTree[l_NewIdChildLeft].m_KDTREE_NODE_TYPE_SPLIT = (char)(l_NewAxis); + + // 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_TempTypeSplitAxis*2+1] = l_TempValueSplit; + + int *l_IdLeftList = new int [_CountPoly*3]; + int *l_IdLeftPolyList = new int [_CountPoly]; + int l_IdLeftCount = 0; + + float l_LeftBoxCenter[3]; + l_LeftBoxCenter[0] = (l_TempAABBLeftChild[KDTREE_SIDE_RIGHT] + l_TempAABBLeftChild[KDTREE_SIDE_LEFT])*0.5f; + l_LeftBoxCenter[1] = (l_TempAABBLeftChild[KDTREE_SIDE_TOP] + l_TempAABBLeftChild[KDTREE_SIDE_BOTTOM])*0.5f; + l_LeftBoxCenter[2] = (l_TempAABBLeftChild[KDTREE_SIDE_FRONT] + l_TempAABBLeftChild[KDTREE_SIDE_BACK])*0.5f; + + float l_LeftHalfSize[3]; + l_LeftHalfSize[0] = fabs(l_TempAABBLeftChild[KDTREE_SIDE_RIGHT] - l_LeftBoxCenter[0])*1.001f; + l_LeftHalfSize[1] = fabs(l_TempAABBLeftChild[KDTREE_SIDE_TOP] - l_LeftBoxCenter[1])*1.001f; + l_LeftHalfSize[2] = fabs(l_TempAABBLeftChild[KDTREE_SIDE_FRONT] - l_LeftBoxCenter[2])*1.001f; + + l_TempIdPnt = _IdVtx; + for(int i=0; i<_CountPoly; ++i) + { + if(triBoxOverlap(l_LeftBoxCenter, l_LeftHalfSize, _Vtx+(*l_TempIdPnt)*4, + _Vtx+(*(l_TempIdPnt+1))*4, + _Vtx+(*(l_TempIdPnt+2))*4)) + { + l_IdLeftList[l_IdLeftCount*3] = (*l_TempIdPnt); + l_IdLeftList[l_IdLeftCount*3+1] = *(l_TempIdPnt+1); + l_IdLeftList[l_IdLeftCount*3+2] = *(l_TempIdPnt+2); + + l_IdLeftPolyList[l_IdLeftCount] = _IdPoly[i]; + + ++l_IdLeftCount; + } + + l_TempIdPnt += 3; + } + + // 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*3]; + memcpy(l_tempCopy, l_IdLeftList, sizeof(int)*l_IdLeftCount*3); + + delete []l_IdLeftList; + l_IdLeftList = l_tempCopy; + } + { + int* l_tempCopy = new int[l_IdLeftCount]; + memcpy(l_tempCopy, l_IdLeftPolyList, sizeof(int)*l_IdLeftCount); + + delete []l_IdLeftPolyList; + l_IdLeftPolyList = l_tempCopy; + } + + CreateNodeKdtree(l_NewIdChildLeft, l_IdLeftPolyList, l_IdLeftList, l_IdLeftCount, _Vtx, _CountVtx, _CurrentDepth+1); + + l_IdInBigArray = l_NewIdChildLeft; + + delete []l_IdLeftList; + delete []l_IdLeftPolyList; + } + + // 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; + + m_NodeTree[l_NewIdChildRight].m_KDTREE_NODE_TYPE_SPLIT = (char)(l_NewAxis); + + // 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_TempTypeSplitAxis*2] = l_TempValueSplit; + + int *l_IdRightList = new int [_CountPoly*3]; + int *l_IdRightPolyList = new int [_CountPoly]; + int l_IdRightCount = 0; + + float l_RightBoxCenter[3]; + l_RightBoxCenter[0] = (l_TempAABBRightChild[KDTREE_SIDE_RIGHT] + l_TempAABBRightChild[KDTREE_SIDE_LEFT])*0.5f; + l_RightBoxCenter[1] = (l_TempAABBRightChild[KDTREE_SIDE_TOP] + l_TempAABBRightChild[KDTREE_SIDE_BOTTOM])*0.5f; + l_RightBoxCenter[2] = (l_TempAABBRightChild[KDTREE_SIDE_FRONT] + l_TempAABBRightChild[KDTREE_SIDE_BACK])*0.5f; + + float l_RightHalfSize[3]; + l_RightHalfSize[0] = fabs(l_TempAABBRightChild[KDTREE_SIDE_RIGHT] - l_RightBoxCenter[0])*1.001f; + l_RightHalfSize[1] = fabs(l_TempAABBRightChild[KDTREE_SIDE_TOP] - l_RightBoxCenter[1])*1.001f; + l_RightHalfSize[2] = fabs(l_TempAABBRightChild[KDTREE_SIDE_FRONT] - l_RightBoxCenter[2])*1.001f; + + l_TempIdPnt = _IdVtx; + for(int i=0; i<_CountPoly; ++i) + { + if(triBoxOverlap(l_RightBoxCenter, l_RightHalfSize,_Vtx +(*l_TempIdPnt)*4, + _Vtx+(*(l_TempIdPnt+1))*4, + _Vtx+(*(l_TempIdPnt+2))*4)) + { + l_IdRightList[l_IdRightCount*3] = (*l_TempIdPnt); + l_IdRightList[l_IdRightCount*3+1] = *(l_TempIdPnt+1); + l_IdRightList[l_IdRightCount*3+2] = *(l_TempIdPnt+2); + + l_IdRightPolyList[l_IdRightCount] = _IdPoly[i]; + + ++l_IdRightCount; + } + + l_TempIdPnt += 3; + } + + // 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*3]; + memcpy(l_tempCopy, l_IdRightList, sizeof(int)*l_IdRightCount*3); + + delete []l_IdRightList; + l_IdRightList = l_tempCopy; + } + { + int* l_tempCopy = new int[l_IdRightCount]; + memcpy(l_tempCopy, l_IdRightPolyList, sizeof(int)*l_IdRightCount); + + delete []l_IdRightPolyList; + l_IdRightPolyList = l_tempCopy; + } + + CreateNodeKdtree(l_NewIdChildRight, l_IdRightPolyList, l_IdRightList, l_IdRightCount, _Vtx, _CountVtx, _CurrentDepth+1); + + //set the new id for the next node in the stack + _CurrentNode = l_NewIdChildRight; + + delete []l_IdRightList; + delete []l_IdRightPolyList; + } + } +} + +//-------------------------------------------------------------------------------- +bool GeometryKDTree::BuildFromGeometry(ResourceFactory &gf, Geometry *g) +//-------------------------------------------------------------------------------- +{ + Free(); + + __LOG__ << "Building KD-Tree...\n"; + Benchmark build_bench(true); + + geometry = g; + geometry->ComputePolygonIndex(pol_index); + + int l_CountVtx = 0; + int *l_IdVtx = NULL; + m_Vtx = NULL; + + if (!g->material_table.GetCount() || !g->pol.GetCount()) + return false; + + material_table.Allocate(g->material_table.GetCount()); + for (uint n = 0; n < material_table.GetCount(); ++n) + material_table[n] = gf.LoadMaterial(g->material_table[n].name); + + // create the optimize edge for the intersect ray + m_OptimizeEdgePoly = new Vector4[g->pol.GetCount() * 2*2]; + + // to keep the real id of the poly, in case of no triangle poly + m_RealIdPoly = new int[g->pol.GetCount()*2]; + + // Transfer topology. + m_count_bih = 0; + l_IdVtx = new int[g->pol.GetCount() * 3*2]; + int *l_TPointer = l_IdVtx; + for (uint n = 0; n < g->pol.GetCount(); ++n) + { + //nVector l_edge1(Vtx2[0] - Vtx1[0], Vtx2[1] - Vtx1[1], Vtx2[2] - Vtx1[2]); + //nVector l_edge2(Vtx3[0] - Vtx1[0], Vtx3[1] - Vtx1[1], Vtx3[2] - Vtx1[2]); + + Polygon &pol = g->pol[n]; + if(pol.vtx_count == 3) + { + m_RealIdPoly[m_count_bih] = n; + + l_TPointer[m_count_bih*3] = pol.binding[0]; + l_TPointer[m_count_bih*3+1] = pol.binding[1]; + l_TPointer[m_count_bih*3+2] = pol.binding[2]; + + m_OptimizeEdgePoly[m_count_bih*2] = g->vtx[pol.binding[1]] - g->vtx[pol.binding[0]]; + m_OptimizeEdgePoly[m_count_bih*2+1] = g->vtx[pol.binding[2]] - g->vtx[pol.binding[0]]; + + ++m_count_bih; + } + else + if(pol.vtx_count == 4) + { + m_RealIdPoly[m_count_bih] = n; + l_TPointer[m_count_bih*3] = pol.binding[0]; + l_TPointer[m_count_bih*3+1] = pol.binding[1]; + l_TPointer[m_count_bih*3+2] = pol.binding[2]; + + m_OptimizeEdgePoly[m_count_bih*2] = g->vtx[pol.binding[1]] - g->vtx[pol.binding[0]]; + m_OptimizeEdgePoly[m_count_bih*2+1] = g->vtx[pol.binding[2]] - g->vtx[pol.binding[0]]; + + ++m_count_bih; + + m_RealIdPoly[m_count_bih] = n; + l_TPointer[m_count_bih*3] = pol.binding[2]; + l_TPointer[m_count_bih*3+1] = pol.binding[3]; + l_TPointer[m_count_bih*3+2] = pol.binding[0]; + + m_OptimizeEdgePoly[m_count_bih*2] = g->vtx[pol.binding[3]] - g->vtx[pol.binding[2]]; + m_OptimizeEdgePoly[m_count_bih*2+1] = g->vtx[pol.binding[0]] - g->vtx[pol.binding[2]]; + + ++m_count_bih; + } + } + + // keep the good amount of memory + { + int* l_TempIdVtx = new int[m_count_bih * 3]; + memcpy(l_TempIdVtx, l_IdVtx, sizeof(int)*m_count_bih * 3); + delete []l_IdVtx; + l_IdVtx = l_TempIdVtx; + } + + { + Vector4* l_TempOptimizeEdgePoly = new Vector4[m_count_bih*2]; + memcpy(l_TempOptimizeEdgePoly, m_OptimizeEdgePoly, sizeof(Vector4)*m_count_bih * 2); + delete []m_OptimizeEdgePoly; + m_OptimizeEdgePoly = l_TempOptimizeEdgePoly; + } + { + int* l_TempRealIdPoly = new int[m_count_bih]; + memcpy(l_TempRealIdPoly, m_RealIdPoly, sizeof(int)*m_count_bih); + delete []m_RealIdPoly; + m_RealIdPoly = l_TempRealIdPoly; + } + + // Transfer vertice. + m_Vtx = new float[g->vtx.GetCount()*4]; + for (uint n = 0; n < g->vtx.GetCount(); ++n) + { + Vector4 l_Temp2Vtx = g->vtx[n]; + m_Vtx[n*4] = l_Temp2Vtx.x; + m_Vtx[n*4+1] = l_Temp2Vtx.y; + m_Vtx[n*4+2] = l_Temp2Vtx.z; + m_Vtx[n*4+3] = l_Temp2Vtx.w; + } + + l_CountVtx = g->vtx.GetCount(); + + //very not powerful kdtree construction + + m_SizeTree = m_count_bih*4; + m_NodeTree = new KDTreeNode[m_SizeTree]; + + int m_CurrentNode = 0; + + m_NodeTree[m_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT = KDTREE_X_AXIS; + + float * l_TempAABB = m_NodeTree[m_CurrentNode].m_KDTREE_NODE_AABB; + + l_TempAABB[KDTREE_SIDE_LEFT] = 3.402823466e+38F; + l_TempAABB[KDTREE_SIDE_BOTTOM] = 3.402823466e+38F; + l_TempAABB[KDTREE_SIDE_BACK] = 3.402823466e+38F; + l_TempAABB[KDTREE_SIDE_RIGHT] = -3.402823466e+38F; + l_TempAABB[KDTREE_SIDE_TOP] = -3.402823466e+38F; + l_TempAABB[KDTREE_SIDE_FRONT] = -3.402823466e+38F; + + float* l_TempVtx = m_Vtx; + for(int i=0; i l_TempAABB[KDTREE_SIDE_RIGHT]) + l_TempAABB[KDTREE_SIDE_RIGHT] = (*l_TempVtx); + + ++l_TempVtx; + if((*l_TempVtx) < l_TempAABB[KDTREE_SIDE_BOTTOM]) + l_TempAABB[KDTREE_SIDE_BOTTOM] = (*l_TempVtx); + if((*l_TempVtx) > l_TempAABB[KDTREE_SIDE_TOP]) + l_TempAABB[KDTREE_SIDE_TOP] = (*l_TempVtx); + + ++l_TempVtx; + if((*l_TempVtx) < l_TempAABB[KDTREE_SIDE_BACK]) + l_TempAABB[KDTREE_SIDE_BACK] = (*l_TempVtx); + if((*l_TempVtx) >l_TempAABB[KDTREE_SIDE_FRONT]) + l_TempAABB[KDTREE_SIDE_FRONT] = (*l_TempVtx); + + ++l_TempVtx; + ++l_TempVtx; + } + + + // to build the kdtree: id of the poly + int* l_IdPoly = new int[m_count_bih]; + for(int i=0; iname == "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 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 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 tag in .\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 .\n") + vtx_normal.Allocate(vt->GetInteger()); + + vt = pt->GetTag("Data;"); + if (!vt) + __ERRRAW__(__LOG_E__ << "No data tag in .\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 .\n") + vtx_tangent.Allocate(vt->GetInteger()); + + vt = pt->GetTag("Data;"); + if (!vt) + __ERRRAW__(__LOG_E__ << "No data tag in .\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 .\n") + rgb.Allocate(vt->GetInteger()); + + vt = pt->GetTag("Data;"); + if (!vt) + __ERRRAW__(__LOG_E__ << "No data tag in .\n") + + if (rgb) + { + uint rgb_count = 0; + + NMLTagForeach(rt, *vt) + { + if (rgb_count == rgb.GetCount()) + { + __LOG_E__ << "Too many 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 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 tag under 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 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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry_normal.cpp b/include/engine/core/geometry_normal.cpp new file mode 100644 index 0000000..6d3a3fb --- /dev/null +++ b/include/engine/core/geometry_normal.cpp @@ -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 &buffer, float msa) +{ + if (!pol.GetCount() || !vtx.GetCount()) + return false; + + if (!ComputePolygonNormal()) + return false; + + Array 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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry_reducer.cpp b/include/engine/core/geometry_reducer.cpp new file mode 100644 index 0000000..2786973 --- /dev/null +++ b/include/engine/core/geometry_reducer.cpp @@ -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; +} diff --git a/include/engine/core/geometry_rgb.cpp b/include/engine/core/geometry_rgb.cpp new file mode 100644 index 0000000..0c7767f --- /dev/null +++ b/include/engine/core/geometry_rgb.cpp @@ -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 pol_index; + ComputePolygonIndex(pol_index); + + Array vtx_to_vtx; + ComputeVertexToVertex(vtx_to_vtx); + + Array 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 ::Swap(rgb, dst); + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry_tangent.cpp b/include/engine/core/geometry_tangent.cpp new file mode 100644 index 0000000..6998831 --- /dev/null +++ b/include/engine/core/geometry_tangent.cpp @@ -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 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 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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry_template.cpp b/include/engine/core/geometry_template.cpp new file mode 100644 index 0000000..5c828eb --- /dev/null +++ b/include/engine/core/geometry_template.cpp @@ -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 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 SortVPP; + + Array raw_v(vtx_per_poly_count); + Array 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 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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/geometry_to_triangle_list.cpp b/include/engine/core/geometry_to_triangle_list.cpp new file mode 100644 index 0000000..282b77d --- /dev/null +++ b/include/engine/core/geometry_to_triangle_list.cpp @@ -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, 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 pol_index; + g.ComputePolygonIndex(pol_index); + + Array 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 vtx_to_pol; + g.ComputeVertexToPolygon(vtx_to_pol); + + // Triangle list are split by material. + Array 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; +} +//------------------------------------------------------------------------------- diff --git a/include/engine/core/iso_surface.cpp b/include/engine/core/iso_surface.cpp new file mode 100644 index 0000000..c753237 --- /dev/null +++ b/include/engine/core/iso_surface.cpp @@ -0,0 +1,964 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #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; idx + && 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 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 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 (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 (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 (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; +} + diff --git a/include/engine/core/item.cpp b/include/engine/core/item.cpp new file mode 100644 index 0000000..e8743b0 --- /dev/null +++ b/include/engine/core/item.cpp @@ -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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/item_nml.cpp b/include/engine/core/item_nml.cpp new file mode 100644 index 0000000..c3520ac --- /dev/null +++ b/include/engine/core/item_nml.cpp @@ -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 .\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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/light.cpp b/include/engine/core/light.cpp new file mode 100644 index 0000000..5c62c4d --- /dev/null +++ b/include/engine/core/light.cpp @@ -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(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/light_nml.cpp b/include/engine/core/light_nml.cpp new file mode 100644 index 0000000..5c32c4e --- /dev/null +++ b/include/engine/core/light_nml.cpp @@ -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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/material.cpp b/include/engine/core/material.cpp new file mode 100644 index 0000000..5032a56 --- /dev/null +++ b/include/engine/core/material.cpp @@ -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(); +} diff --git a/include/engine/core/material_channel.cpp b/include/engine/core/material_channel.cpp new file mode 100644 index 0000000..ef90c70 --- /dev/null +++ b/include/engine/core/material_channel.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/material_nml.cpp b/include/engine/core/material_nml.cpp new file mode 100644 index 0000000..7b6a154 --- /dev/null +++ b/include/engine/core/material_nml.cpp @@ -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 .\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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/material_to_shader_tree.cpp b/include/engine/core/material_to_shader_tree.cpp new file mode 100644 index 0000000..8cbb8f6 --- /dev/null +++ b/include/engine/core/material_to_shader_tree.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/object.cpp b/include/engine/core/object.cpp new file mode 100644 index 0000000..928ab17 --- /dev/null +++ b/include/engine/core/object.cpp @@ -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 &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) {} diff --git a/include/engine/core/object_nml.cpp b/include/engine/core/object_nml.cpp new file mode 100644 index 0000000..1386cf0 --- /dev/null +++ b/include/engine/core/object_nml.cpp @@ -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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/octree_renderable.cpp b/include/engine/core/octree_renderable.cpp new file mode 100644 index 0000000..4274750 --- /dev/null +++ b/include/engine/core/octree_renderable.cpp @@ -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 &list) +{ + AutoPtr 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 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 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 &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 &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 &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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/path_kdtree.cpp b/include/engine/core/path_kdtree.cpp new file mode 100644 index 0000000..eae3b9b --- /dev/null +++ b/include/engine/core/path_kdtree.cpp @@ -0,0 +1,446 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include + #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 &list_segment) +//------------------------------------------------------------------------------------------------------------------------ +{ + // go inside the quadtree + ArrayList 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= 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) +//------------------------------------------------------------------------------------------ +{ + 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; +} diff --git a/include/engine/core/physic_material.cpp b/include/engine/core/physic_material.cpp new file mode 100644 index 0000000..5ff5529 --- /dev/null +++ b/include/engine/core/physic_material.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/physic_material_nml.cpp b/include/engine/core/physic_material_nml.cpp new file mode 100644 index 0000000..466d5d1 --- /dev/null +++ b/include/engine/core/physic_material_nml.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/raster_font.cpp b/include/engine/core/raster_font.cpp new file mode 100644 index 0000000..a02cd07 --- /dev/null +++ b/include/engine/core/raster_font.cpp @@ -0,0 +1,193 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #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(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/render_data.cpp b/include/engine/core/render_data.cpp new file mode 100644 index 0000000..cef727d --- /dev/null +++ b/include/engine/core/render_data.cpp @@ -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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/renderer.cpp b/include/engine/core/renderer.cpp new file mode 100644 index 0000000..7ef6e0a --- /dev/null +++ b/include/engine/core/renderer.cpp @@ -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 &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 Renderer::GetOutputDimensions() const +{ + if (output_texture) + return tVector2 (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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/renderer_nml.cpp b/include/engine/core/renderer_nml.cpp new file mode 100644 index 0000000..b7a1b55 --- /dev/null +++ b/include/engine/core/renderer_nml.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/renderer_profiler.cpp b/include/engine/core/renderer_profiler.cpp new file mode 100644 index 0000000..38438ee --- /dev/null +++ b/include/engine/core/renderer_profiler.cpp @@ -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 (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 (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 (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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/renderer_resource_factory.cpp b/include/engine/core/renderer_resource_factory.cpp new file mode 100644 index 0000000..f5f342d --- /dev/null +++ b/include/engine/core/renderer_resource_factory.cpp @@ -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 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 (uri, *this, GeometryFactory, g, NULL); } +Material *RendererResourceFactory::LoadMaterial(const char *uri, bool, Material *m) +{ return LoadResourceCommonSeq (uri, *this, MaterialFactory, m, "@core/builtin/material/missing.nmm"); } +Texture *RendererResourceFactory::LoadTexture(const char *uri, bool, Texture *t) +{ return LoadResourceCommonSeq (uri, *this, TextureFactory, t, "@core/builtin/maps/missing_texture.png"); } +Shader *RendererResourceFactory::LoadShader(const char *uri, bool, Shader *s) +{ return LoadResourceCommonSeq (uri, *this, ShaderFactory, s, "@core/builtin/shader/missing_shader.nsa"); } +//------------------------------------------------------------------------------ diff --git a/include/engine/core/renderer_toolbox.cpp b/include/engine/core/renderer_toolbox.cpp new file mode 100644 index 0000000..dbceacf --- /dev/null +++ b/include/engine/core/renderer_toolbox.cpp @@ -0,0 +1,353 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #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 diff --git a/include/engine/core/resource_geometry_generator.cpp b/include/engine/core/resource_geometry_generator.cpp new file mode 100644 index 0000000..fc2e16d --- /dev/null +++ b/include/engine/core/resource_geometry_generator.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader.cpp b/include/engine/core/shader.cpp new file mode 100644 index 0000000..292929e --- /dev/null +++ b/include/engine/core/shader.cpp @@ -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 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 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(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; +} diff --git a/include/engine/core/shader_block.cpp b/include/engine/core/shader_block.cpp new file mode 100644 index 0000000..f1c70ce --- /dev/null +++ b/include/engine/core/shader_block.cpp @@ -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; } diff --git a/include/engine/core/shader_input.cpp b/include/engine/core/shader_input.cpp new file mode 100644 index 0000000..7cf4ce4 --- /dev/null +++ b/include/engine/core/shader_input.cpp @@ -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; +} diff --git a/include/engine/core/shader_isl_to_glsl.cpp b/include/engine/core/shader_isl_to_glsl.cpp new file mode 100644 index 0000000..99f15f2 --- /dev/null +++ b/include/engine/core/shader_isl_to_glsl.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_isl_to_hlsl.cpp b/include/engine/core/shader_isl_to_hlsl.cpp new file mode 100644 index 0000000..8289370 --- /dev/null +++ b/include/engine/core/shader_isl_to_hlsl.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_nml.cpp b/include/engine/core/shader_nml.cpp new file mode 100644 index 0000000..6468d54 --- /dev/null +++ b/include/engine/core/shader_nml.cpp @@ -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 buffer; + if (Platform::Get().io->FileLoad(pt->GetString(), buffer)) + vertex.Set(buffer, &buffer[buffer.GetCount()]); + } + else if ((pt->name == "Pixel") || (pt->name == "Fragment")) + { + Array buffer; + if (Platform::Get().io->FileLoad(pt->GetString(), buffer)) + pixel.Set(buffer, &buffer[buffer.GetCount()]); + } + else if (pt->name == "Geometry") + { + Array buffer; + if (Platform::Get().io->FileLoad(pt->GetString(), buffer)) + geometry.Set(buffer, &buffer[buffer.GetCount()]); + } + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_tree.cpp b/include/engine/core/shader_tree.cpp new file mode 100644 index 0000000..b32f45d --- /dev/null +++ b/include/engine/core/shader_tree.cpp @@ -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 &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 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(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_tree_compiler.cpp b/include/engine/core/shader_tree_compiler.cpp new file mode 100644 index 0000000..40494e3 --- /dev/null +++ b/include/engine/core/shader_tree_compiler.cpp @@ -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 ::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(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_tree_compiler_isl.cpp b/include/engine/core/shader_tree_compiler_isl.cpp new file mode 100644 index 0000000..2e6a663 --- /dev/null +++ b/include/engine/core/shader_tree_compiler_isl.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_tree_compiler_tinyc.cpp b/include/engine/core/shader_tree_compiler_tinyc.cpp new file mode 100644 index 0000000..14ebb0e --- /dev/null +++ b/include/engine/core/shader_tree_compiler_tinyc.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_tree_convert_static_texture_block_to_dynamic.cpp b/include/engine/core/shader_tree_convert_static_texture_block_to_dynamic.cpp new file mode 100644 index 0000000..d52df5f --- /dev/null +++ b/include/engine/core/shader_tree_convert_static_texture_block_to_dynamic.cpp @@ -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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_tree_nml.cpp b/include/engine/core/shader_tree_nml.cpp new file mode 100644 index 0000000..0b6caae --- /dev/null +++ b/include/engine/core/shader_tree_nml.cpp @@ -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 *ShaderBlock::BlockMapFromMetaTag(Tag &tag) +{ + if (tag.name != "Map") + return NULL; + + // Allocate block map. + Array *block_map = new Array (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 *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 *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 &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 &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 &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 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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/shader_tree_to_shader.cpp b/include/engine/core/shader_tree_to_shader.cpp new file mode 100644 index 0000000..f28aa54 --- /dev/null +++ b/include/engine/core/shader_tree_to_shader.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/simple_list_renderable.cpp b/include/engine/core/simple_list_renderable.cpp new file mode 100644 index 0000000..582a831 --- /dev/null +++ b/include/engine/core/simple_list_renderable.cpp @@ -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 &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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/skin.cpp b/include/engine/core/skin.cpp new file mode 100644 index 0000000..f570ac0 --- /dev/null +++ b/include/engine/core/skin.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/sound.cpp b/include/engine/core/sound.cpp new file mode 100644 index 0000000..48795f3 --- /dev/null +++ b/include/engine/core/sound.cpp @@ -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); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/terrain.cpp b/include/engine/core/terrain.cpp new file mode 100644 index 0000000..76b40d1 --- /dev/null +++ b/include/engine/core/terrain.cpp @@ -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 &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 &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(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/terrain_nml.cpp b/include/engine/core/terrain_nml.cpp new file mode 100644 index 0000000..c9ee142 --- /dev/null +++ b/include/engine/core/terrain_nml.cpp @@ -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 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 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 .\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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/terrain_shader_generator.cpp b/include/engine/core/terrain_shader_generator.cpp new file mode 100644 index 0000000..59bc045 --- /dev/null +++ b/include/engine/core/terrain_shader_generator.cpp @@ -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; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/texture_parm.cpp b/include/engine/core/texture_parm.cpp new file mode 100644 index 0000000..1f26018 --- /dev/null +++ b/include/engine/core/texture_parm.cpp @@ -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); } +//------------------------------------------------------------------------------ diff --git a/include/engine/core/triangle_list_optimizer.cpp b/include/engine/core/triangle_list_optimizer.cpp new file mode 100644 index 0000000..7482a91 --- /dev/null +++ b/include/engine/core/triangle_list_optimizer.cpp @@ -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 + #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 &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 &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 vertex(total_vtx_count); + Array triangle(total_tri_count); + + if (!vertex || !triangle) + __ERRRAW__(__LOG_E__ << "Failed to allocate vertex optimization array.\n"); + + // Process each list. + Array LRUCache(MaxSizeVertexCache); + Array 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); + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/core/trigger.cpp b/include/engine/core/trigger.cpp new file mode 100644 index 0000000..2a59c1e --- /dev/null +++ b/include/engine/core/trigger.cpp @@ -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; +} diff --git a/include/engine/gpu/gpu_core_shader.cpp b/include/engine/gpu/gpu_core_shader.cpp new file mode 100644 index 0000000..6f6b2a6 --- /dev/null +++ b/include/engine/gpu/gpu_core_shader.cpp @@ -0,0 +1,148 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "metafile/nml_object.h" + #include "log/log.h" + + using namespace GS::GPU; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +Tag *Renderer::GetPCFShaderTag() const +{ + const char *pcf_tag[] = { "PCF:3x3GaussianDithered;", "PCF:3x3;", "PCF:2x2;", "PCF:1x1;" }; + int pcf_q = GS::Types::Clamp(registry.GetInteger("ShadowMapping:PCF:Quality", 1), 0, 3); + return shader_dict.GetTag(pcf_tag[pcf_q]); +} +Tag *Renderer::GetPSMShaderTag() const +{ return shader_dict.GetTag("PSM;"); } +Tag *Renderer::GetPSSMShaderTag() const +{ + const char *pssm_tag[] = { "PSSM:2Split;", "PSSM:3Split;", "PSSM:4Split;" }; + int split_count = GS::Types::Clamp(registry.GetInteger("ShadowMapping:PSSM:Split", 3), 2, 4); + return shader_dict.GetTag(pssm_tag[split_count - 2]); +} +void Renderer::MarshallCoreShader(GS::String &source) +{ + if (Tag *t = shader_dict.GetTag("UnpackGBuffer:Float;")) + source.Replace("#(UnpackNormalDepth)", t->GetString()); + if (Tag *t = GetPCFShaderTag()) + source.Replace("#(ComputePCF)", t->GetString()); + if (Tag *t = GetPSSMShaderTag()) + source.Replace("#(DispatchPSSM)", t->GetString()); +} +Shader *Renderer::SetupCoreShader(const char *name) +{ + Core::Shader shader; + if (!NML::LoadFromFile(shader, name)) + return NULL; + + shader.name = name; + + // Note: Marshalling is only done on core shaders. + MarshallCoreShader(shader.vertex); + MarshallCoreShader(shader.pixel); + + AutoPtr gpu_shader((Shader *)NewShader()); + if (gpu_shader.IsNull() || !gpu_shader->Create(*core_resource_factory, shader)) + return NULL; + return gpu_shader.Detach(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::LoadCoreShaders(bool support_3d) +{ + __LOG_FUNC__ + + // Load the shader dictionaries. + if (!NML::Parser::Load("@core/shaders/gpu/dict.txt", shader_dict)) + __ERR__(__LOG_E__ << "Shader dictionnary missing.\n", false) + if (!NML::Parser::Load("@core/shaders/gpu/dict_material.txt", material_dict)) + __ERR__(__LOG_E__ << "Material dictionnary missing.\n", false) + + // Load core shaders. + single_texture_color_program = SetupCoreShader("@core/shaders/gpu/single_texture_color.nsa"); + single_texture_program = SetupCoreShader("@core/shaders/gpu/single_texture.nsa"); + single_color_program = SetupCoreShader("@core/shaders/gpu/single_color.nsa"); + simple_program = SetupCoreShader("@core/shaders/gpu/simple.nsa"); + + if (support_3d) + { + single_texture_cutoff_program = SetupCoreShader("@core/shaders/gpu/single_texture_cutoff.nsa"); + single_texture_fx_program = SetupCoreShader("@core/shaders/gpu/single_texture_fx.nsa"); + tone_mapping_program = SetupCoreShader("@core/shaders/gpu/tone_mapping.nsa"); + + ambient_program = SetupCoreShader("@core/shaders/gpu/ambient.nsa"); + + spotlight_program = SetupCoreShader("@core/shaders/gpu/deferred/spotlight.nsa"); + spotlight_shadow_program = SetupCoreShader("@core/shaders/gpu/deferred/spotlight_shadow.nsa"); + pointlight_program = SetupCoreShader("@core/shaders/gpu/deferred/pointlight.nsa"); + pointlight_shadow_program = SetupCoreShader("@core/shaders/gpu/deferred/pointlight_shadow.nsa"); + linearlight_program = SetupCoreShader("@core/shaders/gpu/deferred/linearlight.nsa"); + linearlight_shadow_program = SetupCoreShader("@core/shaders/gpu/deferred/linearlight_shadow.nsa"); + ds_fog_program = SetupCoreShader("@core/shaders/gpu/deferred/ds_fog.nsa"); + + fx_blur_program = SetupCoreShader("@core/shaders/gpu/fx_blur.nsa"); + noise_program = SetupCoreShader("@core/shaders/gpu/noise.nsa"); + sharpen_program = SetupCoreShader("@core/shaders/gpu/sharpen.nsa"); + hsl_program = SetupCoreShader("@core/shaders/gpu/hsl.nsa"); + chromatic_dispersion_program = SetupCoreShader("@core/shaders/gpu/chromatic_dispersion.nsa"); + + ssaa_program = SetupCoreShader("@core/shaders/gpu/ssaa.nsa"); + ssao_program = SetupCoreShader("@core/shaders/gpu/ssao.nsa"); + ssao_blur_program = SetupCoreShader("@core/shaders/gpu/ssao_blur.nsa"); + + motion_blur_program = SetupCoreShader("@core/shaders/gpu/motion_blur.nsa"); + radial_blur_program = SetupCoreShader("@core/shaders/gpu/radial_blur.nsa"); + + resolve_msaa_depth_program = SetupCoreShader("@core/shaders/gpu/resolve_msaa_depth.nsa"); + + skybox_program = SetupCoreShader("@core/shaders/gpu/skybox.nsa"); + } + return true; +} +void Renderer::UnloadCoreShaders() +{ + single_texture_color_program = NULL; + single_texture_program = NULL; + single_color_program = NULL; + simple_program = NULL; + + single_texture_cutoff_program = NULL; + single_texture_fx_program = NULL; + tone_mapping_program = NULL; + + ambient_program = NULL; + + spotlight_program = NULL; + spotlight_shadow_program = NULL; + pointlight_program = NULL; + pointlight_shadow_program = NULL; + linearlight_program = NULL; + linearlight_shadow_program = NULL; + ds_fog_program = NULL; + + fx_blur_program = NULL; + noise_program = NULL; + sharpen_program = NULL; + hsl_program = NULL; + chromatic_dispersion_program = NULL; + + ssaa_program = NULL; + ssao_program = NULL; + ssao_blur_program = NULL; + + motion_blur_program = NULL; + radial_blur_program = NULL; + + resolve_msaa_depth_program = NULL; + + skybox_program = NULL; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_display_list.cpp b/include/engine/gpu/gpu_display_list.cpp new file mode 100644 index 0000000..28749f4 --- /dev/null +++ b/include/engine/gpu/gpu_display_list.cpp @@ -0,0 +1,220 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_display_list.h" + #include "gpu/gpu_renderer.h" + #include "core/triangle_list.h" + #include "log/log.h" + + #define __USE_VBO__ 1 + + using namespace GS::GPU; + +namespace GS { + namespace Core { + bool ComputeVertexArrayMinMax(const Array &, MinMax &, const Matrix4 * = 0); + } +} + +//------------------------------------------------------------------------------ +bool DisplayList::Create(GS::Core::Trilist *trilist, GS::Render::Material *list_material) +{ + // Setup skin data. + bone.Clone(trilist->bone); + + // Setup triangle list indices. + index_count = trilist->idx.GetCount(); + +#if __USE_VBO__ + + if (!idx) + idx = renderer.NewVBO(); + if (!idx || !idx->Create(index_count * sizeof(ushort), VBO::Index, VBO::Static)) + return false; + +#endif + + if (!idx_map.Allocate(index_count)) + return false; + + for (size_t n = 0; n idx[(int)n]; + +#if __USE_VBO__ + + idx->Update(idx_map, 0, idx_map.GetSize()); + idx_map.Free(); + +#endif + + // Setup triangle list vertex. + stride = 0; + + // Vertex offset. + vertex_offset = stride; + stride += 3 * sizeof(hfloat); + + // Compute normal stream size. + if (trilist->nrm) + { + normal_offset = stride; + stride += 4 * sizeof(char); + } + + // Compute RGB stream size. + if (trilist->rgb) + { + rgb_offset = stride; + stride += 4 * sizeof(char); + } + + // Compute UV stream size. + for (int s = 0; s < __UV_PER_GEOMETRY__; ++s) + if (trilist->uv[s]) + { + uv_offset[s] = stride; + stride += 2 * sizeof(hfloat); + } + + // Compute tangent stream size. + if (trilist->tangent) + { + tangent_offset = stride; + stride += 4 * 2 * sizeof(char); + } + + // Compute skinning stream size. + if (trilist->skin) + { + skinning_offset = stride; + stride += 4 * 2 * sizeof(uchar); + } + + #define __GPU_PADSIZE 4 + + // Compute vertex padding. + int padding = 0; + padding = stride % __GPU_PADSIZE ? __GPU_PADSIZE - (stride % __GPU_PADSIZE) : 0; + if (padding) + __LOG__ << "Padding GPU vertex to " << __GPU_PADSIZE << "B by " << padding << "B (from " << (uint)stride << "B)\n"; + stride += padding; + + // Setup attribute streams. + size_t vtx_stream_size = stride * size_t(trilist->vtx.GetCount()); + +#if __USE_VBO__ + + if (!vtx) + vtx = renderer.NewVBO(); + if (!vtx || !vtx->Create(vtx_stream_size, VBO::Vertex, VBO::Static)) + return false; + +#endif + + if (!vtx_map.Allocate(vtx_stream_size)) + return false; + + char *p_stream = (char *)vtx_map.c_ptr(); + for (uint n = 0; n < trilist->vtx.GetCount(); ++n) + { + // Output vertex stream. + hfloat *p_vtx = (hfloat *)p_stream; + p_vtx[0] = Types::FloatToHFloat(trilist->vtx[n].x); + p_vtx[1] = Types::FloatToHFloat(trilist->vtx[n].y); + p_vtx[2] = Types::FloatToHFloat(trilist->vtx[n].z); + p_stream += 3 * sizeof(hfloat); + + // Output normal stream. + if (trilist->nrm) + { + schar *p_nrm = (schar *)p_stream; + p_nrm[0] = (schar)(trilist->nrm[n].x * 127.f); + p_nrm[1] = (schar)(trilist->nrm[n].y * 127.f); + p_nrm[2] = (schar)(trilist->nrm[n].z * 127.f); + p_stream += 4 * sizeof(schar); + } + + // Output RGB stream. + if (trilist->rgb) + { + uchar *p_rgb = (uchar *)p_stream; + p_rgb[0] = uchar(trilist->rgb[n].x * 255.f); + p_rgb[1] = uchar(trilist->rgb[n].y * 255.f); + p_rgb[2] = uchar(trilist->rgb[n].z * 255.f); + p_rgb[3] = uchar(trilist->rgb[n].w * 255.f); + p_stream += 4 * sizeof(uchar); + } + + // Output UV streams. + for (uint s = 0; s < __UV_PER_GEOMETRY__; ++s) + if (trilist->uv[s]) + { + hfloat *p_uv = (hfloat *)p_stream; + p_uv[0] = Types::FloatToHFloat(trilist->uv[s][n].x); + p_uv[1] = Types::FloatToHFloat(trilist->uv[s][n].y); + p_stream += 2 * sizeof(hfloat); + } + + // Output tangent stream. + if (trilist->tangent) + { + schar *p_tng = (schar *)p_stream; + p_tng[0] = schar(trilist->tangent[n].T.x * 127.f); + p_tng[1] = schar(trilist->tangent[n].T.y * 127.f); + p_tng[2] = schar(trilist->tangent[n].T.z * 127.f); + // Mind the gap! + p_tng[4] = schar(trilist->tangent[n].B.x * 127.f); + p_tng[5] = schar(trilist->tangent[n].B.y * 127.f); + p_tng[6] = schar(trilist->tangent[n].B.z * 127.f); + p_stream += 4 * 2 * sizeof(schar); + } + + // Output skinning stream. + if (trilist->skin) + { + uchar *p_skn = (uchar *)p_stream; + p_skn[0] = uchar(trilist->skin[n].bone_index[0]); + p_skn[1] = uchar(trilist->skin[n].bone_index[1]); + p_skn[2] = uchar(trilist->skin[n].bone_index[2]); + p_skn[3] = uchar(trilist->skin[n].bone_index[3]); + p_skn[4] = uchar(trilist->skin[n].w[0] * 255.f); + p_skn[5] = uchar(trilist->skin[n].w[1] * 255.f); + p_skn[6] = uchar(trilist->skin[n].w[2] * 255.f); + p_skn[7] = uchar(trilist->skin[n].w[3] * 255.f); + p_stream += 4 * 2 * sizeof(uchar); + } + + p_stream += padding; + } + +#if __USE_VBO__ + + vtx->Update(vtx_map, 0, vtx_map.GetSize()); + vtx_map.Free(); + +#else + + p_stream = (char *)vtx_map.c_ptr(); + + #define OffsetToAdress(_Offset) \ + if (_Offset != -1) _Offset += (size_t)p_stream; + + OffsetToAdress(vertex_offset) + OffsetToAdress(normal_offset) + OffsetToAdress(rgb_offset) + for (uint n = 0; n < __UV_PER_GEOMETRY__; ++n) + OffsetToAdress(uv_offset[n]) + OffsetToAdress(tangent_offset) + OffsetToAdress(skinning_offset) + +#endif + + Core::ComputeVertexArrayMinMax(trilist->vtx, minmax); + material = list_material; + + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_fbo.h b/include/engine/gpu/gpu_fbo.h index 7cfd634..8d06776 100644 --- a/include/engine/gpu/gpu_fbo.h +++ b/include/engine/gpu/gpu_fbo.h @@ -52,6 +52,7 @@ virtual void SetDepthTexture(Render::Texture *t) virtual void Blit(FBO *out, const iRect &src, const iRect &dst, bool color = true, bool depth = true) = 0; /// Transfer color pixels into a CPU based buffer, this buffer is expected to be big enough to hold the required region in RGBA format. virtual void ReadColorPixels(char *out, int x, int y, int w, int h) = 0; +virtual void ReadDepthPixels(float *out) = 0; /// Create FBO. virtual bool Create() = 0; diff --git a/include/engine/gpu/gpu_geometry.cpp b/include/engine/gpu/gpu_geometry.cpp new file mode 100644 index 0000000..0c74197 --- /dev/null +++ b/include/engine/gpu/gpu_geometry.cpp @@ -0,0 +1,109 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_geometry.h" + #include "gpu/gpu_renderer.h" + #include "core/geometry.h" + #include "core/geometry_to_triangle_list.h" + #include "core/triangle_list.h" + #include "log/log.h" + + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +bool Geometry::AllocateVBO(uint count) +{ + if (!vbo.Allocate(count)) + return false; + + for (uint n = 0; n < count; ++n) + vbo[n] = renderer.NewVBO(); + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Geometry::SetMaterial(uint index, GS::Render::Material *m) +{ + if (index >= material_table.GetCount()) + return false; + + // Update all display lists using this material index. + for (uint n = 0; n < display_list.GetCount(); ++n) + if (DisplayList *dlist = display_list[n]) + if (dlist->material == material_table[index]) + dlist->material = (GPU::Material *)m; + + // Update the material table. + material_table[index] = m; + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Geometry::ShouldReloadOnDependencyChange(const char *n) const +{ + for (uint i = 0; i < material_table.GetCount(); ++i) + if (material_table[i] && (material_table[i]->name == n)) + return true; + + return name == n; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Geometry::Create(GS::Render::ResourceFactory &rf, const GS::Core::Geometry &g) +{ + __LOG_H__ << "Setup geometry '" << g.name << "'.\n"; + name = g.name; + + using namespace Core; + + // Setup materials. + if (material_table.Allocate(g.material_table.GetCount())) + for (uint n = 0; n < g.material_table.GetCount(); ++n) + material_table[n] = rf.LoadMaterial(g.material_table[n].name, !g.material_table[n].use_cache); + + // Build geometry triangle list. + AutoList tlist; + if (!GeometryToTriangleList::Convert(g, tlist)) + return false; + + // Setup geometry display lists. + if (display_list.Allocate(tlist.GetCount())) + { + uint n = 0; + ListForeachPtr(Trilist *, t, tlist) + { + display_list[n] = renderer.NewDisplayList(); + display_list[n]->Create(t, material_table[t->mat]); + ++n; + } + } + flag = g.flag; + + // Skinning. + bone_bind_matrix.Clone(g.bone_bind_matrix); + g.ComputeBoneBoundingVolumes(bone_minmax); + + // Load proxies. + if (!g.lod_proxy.IsEmpty()) + lod_proxy = rf.LoadGeometry(g.lod_proxy); + lod_distance = g.lod_distance; + + if (!g.shadow_proxy.IsEmpty()) + shadow_proxy = rf.LoadGeometry(g.shadow_proxy); + + minmax = g.ComputeMinMax(); +// hotspot.Set(0, 0, 0); + hotspot = (minmax.mn + minmax.mx) * 0.5f; + + return true; +} +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/include/engine/gpu/gpu_half_float.cpp b/include/engine/gpu/gpu_half_float.cpp new file mode 100644 index 0000000..962d888 --- /dev/null +++ b/include/engine/gpu/gpu_half_float.cpp @@ -0,0 +1,128 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "gpu/gpu_types.h" + #include "gpu/gpu_renderer.h" + + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +#ifdef EGL_HALF_FLOAT_SUPPORT + +// -15 stored using a single precision bias of 127 +static const unsigned int HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP = 0x38000000; +// max exponent value in single precision that will be converted +// to Inf or Nan when stored as a half-float +static const unsigned int HALF_FLOAT_MAX_BIASED_EXP_AS_SINGLE_FP_EXP = 0x47800000; +// 255 is the max exponent biased value +static const unsigned int FLOAT_MAX_BIASED_EXP = (0xFF << 23); +static const unsigned int HALF_FLOAT_MAX_BIASED_EXP = (0x1F << 10); + +hfloat Types::FloatToHFloat(float f) +{ + unsigned int x = *(unsigned int *)&f; + unsigned int sign = (unsigned short)(x >> 31); + unsigned int mantissa; + unsigned int exp; + + hfloat hf; + + // get mantissa + mantissa = x & ((1 << 23) - 1); + + // get exponent bits + exp = x & FLOAT_MAX_BIASED_EXP; + + if (exp >= HALF_FLOAT_MAX_BIASED_EXP_AS_SINGLE_FP_EXP) + { + // check if the original single precision float number is a NaN + if (mantissa && (exp == FLOAT_MAX_BIASED_EXP)) + { + // we have a single precision NaN + mantissa = (1 << 23) - 1; + } + else + { + // 16-bit half-float representation stores number as Inf + mantissa = 0; + } + + hf = (((hfloat)sign) << 15) | (hfloat)(HALF_FLOAT_MAX_BIASED_EXP) | (hfloat)(mantissa >> 13); + } + // check if exponent is <= -15 + else if (exp <= HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP) + { + // store a denorm half-float value or zero. + exp = (HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP - exp) >> 23; + mantissa >>= (14 + exp); + hf = (((hfloat)sign) << 15) | (hfloat)(mantissa); + } + else + hf = (((hfloat)sign) << 15) | (hfloat)((exp - HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP) >> 13) | (hfloat)(mantissa >> 13); + + return hf; +} +float Types::HFloatToFloat(hfloat hf) +{ + unsigned int sign = (unsigned int)(hf >> 15); + unsigned int mantissa = (unsigned int)(hf & ((1 << 10) - 1)); + unsigned int exp = (unsigned int)(hf & HALF_FLOAT_MAX_BIASED_EXP); + unsigned int f; + + if (exp == HALF_FLOAT_MAX_BIASED_EXP) + { + // we have a half-float NaN or Inf + // half-float NaNs will be converted to a single precision NaN + // half-float Infs will be converted to a single precision Inf + exp = FLOAT_MAX_BIASED_EXP; + + if (mantissa) + mantissa = (1 << 23) - 1; // set all bits to indicate a NaN + } + else if (exp == 0x0) + { + // convert half-float zero/denorm to single precision value + if (mantissa) + { + mantissa <<= 1; + exp = HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP; + + // check for leading 1 in denorm mantissa + while ((mantissa & (1 << 10)) == 0) + { + // for every leading 0, decrement single precision exponent by 1 + // and shift half-float mantissa value to the left + mantissa <<= 1; + exp -= (1 << 23); + } + + // clamp the mantissa to 10-bits + mantissa &= ((1 << 10) - 1); + // shift left to generate single-precision mantissa of 23-bits + mantissa <<= 13; + } + } + else + { + // shift left to generate single-precision mantissa of 23-bits + mantissa <<= 13; + + // generate single precision biased exponent value + exp = (exp << 13) + HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP; + } + + f = (sign << 31) | exp | mantissa; + return *((float *)&f); +} + +#else // No half-float support. + +hfloat Types::FloatToHFloat(float f) { return f; } +float Types::HFloatToFloat(hfloat hf) { return hf; } + +#endif +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_helper.cpp b/include/engine/gpu/gpu_helper.cpp new file mode 100644 index 0000000..0c8d849 --- /dev/null +++ b/include/engine/gpu/gpu_helper.cpp @@ -0,0 +1,234 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_types.h" + #include "gpu/gpu_renderer.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::GPU; + +/* + 0 - - 3 + | | + | | + 1 - - 2 +*/ + +//------------------------------------------------------------------------------ +bool Renderer::BuildDirectVertexLayout(uint idx_count, const ushort *idx, const Vector4 *v, const Color *c, const Vector2 *uv, DirectVertexLayout &layout, VBO *idx_vbo, VBO *vtx_vbo) +{ + if (idx_vbo) + { + size_t size = idx_count * sizeof(ushort); + if (size > idx_vbo->GetSize()) + if (!idx_vbo->Create(size, VBO::Index, VBO::Dynamic)) + return false; + + if (void *p = idx_vbo->Map()) + { + Memory::Copy(p, idx, size); + idx_vbo->Unmap(); + } + } + + // Find vertex count. + ushort vtx_count = 0; + for (uint n = 0; n < idx_count; ++n) + vtx_count = GS::Types::Max(vtx_count, idx[n]); + ++vtx_count; + + // Build layout. + layout.stride = 0; + + if (v) + { + layout.vtx_offset = layout.stride; + layout.stride += 3 * sizeof(float); + } + if (c) + { + layout.color_offset = layout.stride; + layout.stride += 4 * sizeof(uchar); + } + if (uv) + { + layout.uv_offset = layout.stride; + layout.stride += 2 * sizeof(float); + } + + // Build interleaved vertex data. + if (vtx_vbo) + { + size_t size = vtx_count * layout.stride; + if (size > vtx_vbo->GetSize()) + if (!vtx_vbo->Create(size, VBO::Vertex, VBO::Dynamic)) + return false; + + if (char *p_data = (char *)vtx_vbo->Map()) + { + for (uint n = 0; n < vtx_count; ++n) + { + if (v) + { + float *p_vtx = (float *)(p_data + layout.vtx_offset); + p_vtx[0] = v[n].x; + p_vtx[1] = v[n].y; + p_vtx[2] = v[n].z; + } + if (c) + { + uchar *p_color = (uchar *)(p_data + layout.color_offset); + p_color[0] = uchar(c[n].x * 255.f); + p_color[1] = uchar(c[n].y * 255.f); + p_color[2] = uchar(c[n].z * 255.f); + p_color[3] = uchar(c[n].w * 255.f); + } + if (uv) + { + float *p_uv = (float *)(p_data + layout.uv_offset); + p_uv[0] = uv[n].x; + p_uv[1] = uv[n].y; + } + p_data += layout.stride; + } + vtx_vbo->Unmap(); + } + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::RenderFullscreenQuad(Shader &p, float k_x, float k_y, Render::Texture *t, Core::Light *l) +{ + __NTRACE("RenderFullscreenQuad") + + const size_t stride = sizeof(float) * 5; + if (gpu_config.tex_origin_is_top_left) + { + const float vtx[] = { -1, 1, 1, 0, k_y, -1, -1, 1, 0, 0, 1, -1, 1, k_x, 0, 1, 1, 1, k_x, k_y }; + helper_vtx_vbo->Update(vtx, 0, stride * 4); + } + else + { + const float vtx[] = { -1, 1, 1, 0, 1.f - k_y, -1, -1, 1, 0, 1, 1, -1, 1, k_x, 1, 1, 1, 1, k_x, 1.f - k_y }; + helper_vtx_vbo->Update(vtx, 0, stride * 4); + } + + SetDepthFunc(DepthAlways); + EnableDepthWrite(false); + + SetShaderProgram(&p); + SetIndexSource(helper_idx_vbo); + SetVertexSource(helper_vtx_vbo, sizeof(float) * 5); + + ShaderInput *vtx_parm = p.GetInput(Core::ShaderInput::Position), + *uv_parm = p.GetInput(Core::ShaderInput::UV0), + *texture_parm = p.GetInput(Core::ShaderInput::Texture2D); + + if (!texture_parm) // get cube map (TEMP HACK) + texture_parm = p.GetInput(Core::ShaderInput::TextureCube); + + if (vtx_parm) + p.Set(*vtx_parm->location, 3, Types::ValueFloat, false, stride, (const void *)0); + if (uv_parm) + p.Set(*uv_parm->location, 2, Types::ValueFloat, false, stride, (const void *)(sizeof(float) * 3)); + if (texture_parm && t) + texture_parm->SetValue(t); + + if (view_item && l) + p.SetLightInputs(*this, *view_item, *l); + + p.SetTransformInputs(Matrix4::IdentityMatrix(), Matrix4::IdentityMatrix(), Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + p.SetRendererInputs(*this); + p.SetConstantInputs(); + p.SetTextureInputs(); + p.CommitInputs(); + + DrawElements(Types::PrimitiveTriangle, 3 * 2, Types::ValueUShort); + + if (vtx_parm) + p.Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + if (uv_parm) + p.Set(*uv_parm->location, 0, Types::ValueLast, false, 0, NULL); + + EnableDepthWrite(true); + SetDepthFunc(DepthLess); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::RenderFullscreenQuad(Shader &p, const fRect &src_rect, const fRect &dst_rect, Render::Texture *t, Core::Light *l) +{ + __NTRACE("RenderFullscreenQuad (Region)") + + const size_t stride = sizeof(float) * 5; + + if (gpu_config.tex_origin_is_top_left) + { + const float vtx[] = + { + dst_rect.sx * 2.f - 1.f, dst_rect.sy * 2.f - 1.f, 1, src_rect.sx, src_rect.sy, + dst_rect.ex * 2.f - 1.f, dst_rect.sy * 2.f - 1.f, 1, src_rect.ex, src_rect.sy, + dst_rect.ex * 2.f - 1.f, dst_rect.ey * 2.f - 1.f, 1, src_rect.ex, src_rect.ey, + dst_rect.sx * 2.f - 1.f, dst_rect.ey * 2.f - 1.f, 1, src_rect.sx, src_rect.ey + }; + helper_vtx_vbo->Update(vtx, 0, stride * 4); + } + else + { + const float vtx[] = + { + dst_rect.sx * 2.f - 1.f, dst_rect.sy * 2.f - 1.f, 1, src_rect.sx, src_rect.ey, + dst_rect.ex * 2.f - 1.f, dst_rect.sy * 2.f - 1.f, 1, src_rect.ex, src_rect.ey, + dst_rect.ex * 2.f - 1.f, dst_rect.ey * 2.f - 1.f, 1, src_rect.ex, src_rect.sy, + dst_rect.sx * 2.f - 1.f, dst_rect.ey * 2.f - 1.f, 1, src_rect.sx, src_rect.sy + }; + helper_vtx_vbo->Update(vtx, 0, stride * 4); + } + + SetDepthFunc(DepthAlways); + EnableDepthWrite(false); + + SetShaderProgram(&p); + SetIndexSource(helper_idx_vbo); + SetVertexSource(helper_vtx_vbo, stride); + + ShaderInput *vtx_parm = p.GetInput(Core::ShaderInput::Position), + *uv_parm = p.GetInput(Core::ShaderInput::UV0), + *texture_parm = p.GetInput(Core::ShaderInput::Texture2D); + + if (!texture_parm) // get cube map (TEMP HACK) + texture_parm = p.GetInput(Core::ShaderInput::TextureCube); + + if (vtx_parm) + p.Set(*vtx_parm->location, 3, Types::ValueFloat, false, stride, (const void *)0); + if (uv_parm) + p.Set(*uv_parm->location, 2, Types::ValueFloat, false, stride, (const void *)(sizeof(float) * 3)); + if (texture_parm && t) + texture_parm->SetValue(t); + + if (view_item && l) + p.SetLightInputs(*this, *view_item, *l); + + p.SetTransformInputs(Matrix4::IdentityMatrix(), Matrix4::IdentityMatrix(), Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + p.SetRendererInputs(*this); + p.SetConstantInputs(); + p.SetTextureInputs(); + p.CommitInputs(); + + DrawElements(Types::PrimitiveTriangle, 3 * 2, Types::ValueUShort); + + if (vtx_parm) + p.Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + if (uv_parm) + p.Set(*uv_parm->location, 0, Types::ValueLast, false, 0, NULL); + + EnableDepthWrite(true); + SetDepthFunc(DepthLess); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_light_volume.cpp b/include/engine/gpu/gpu_light_volume.cpp new file mode 100644 index 0000000..10df7ea --- /dev/null +++ b/include/engine/gpu/gpu_light_volume.cpp @@ -0,0 +1,163 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "core/camera.h" + #include "core/light.h" + + using namespace GS; + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void Renderer::RenderFullscreenLight(Shader &p, Core::Light &l) +{ + SetDepthFunc(DepthAlways); + + const float h = 1.f, k = 100.f; + const float vtx[] = { -k, -k, h, k, -k, h, k, k, h, -k, k, h }; + + const size_t stride = sizeof(float) * 3; + helper_vtx_vbo->Update(vtx, 0, stride * 4); + + SetShaderProgram(&p); + SetIndexSource(helper_idx_vbo); + SetVertexSource(helper_vtx_vbo, stride); + + ShaderInput *vtx_parm = p.GetInput(Core::ShaderInput::Position); + if (vtx_parm) + p.Set(*vtx_parm->location, 3, Types::ValueFloat, false, stride, 0); + + p.SetTransformInputs(Matrix4::IdentityMatrix(), Matrix4::IdentityMatrix(), Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + p.SetLightInputs(*this, *view_item, l); + p.SetRendererInputs(*this); + p.CommitInputs(); + + DrawElements(Types::PrimitiveTriangle, 3 * 2, Types::ValueUShort); + + if (vtx_parm) + p.Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + + SetDepthFunc(DepthLess); +} +void Renderer::RenderSpotLight(Core::Light &l, const DrawContext &dc) +{ + if (!view_item) + return; + + Shader &p = (l.shadow == Core::Light::Shadow_Map) && gpu_config.enable_shadow ? *spotlight_shadow_program : *spotlight_program; + + if (!l.volume_range) + RenderFullscreenLight(p, l); + + else + { + const Vector4 *vtx = l.frustum.GetVertices(); + + const size_t stride = sizeof(float) * 4; + helper_vtx_vbo->Update(vtx, 0, stride * 8); + + SetShaderProgram(&p); + SetIndexSource(box_idx_vbo); + SetVertexSource(helper_vtx_vbo, stride); + + ShaderInput *vtx_parm = p.GetInput(Core::ShaderInput::Position); + if (vtx_parm) + p.Set(*vtx_parm->location, 3, Types::ValueFloat, false, stride, 0); + + p.SetTransformInputs(m_projection, m_view, m_iview, &Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + p.SetLightInputs(*this, *view_item, l); + p.SetRendererInputs(*this); + p.CommitInputs(); + + // TODO Boolean operation on light frustum and clipping planes. + Vector4 row = view_item->GetMatrix().GetRow(3); + Frustum::Visibility viscode = l.frustum.ClassifySet(1, &row, Units::Cm(50.f)); + + if (viscode != Frustum::Outside) + { + SetDepthFunc(DepthGreater); + SetCullFunc(CullBack); + } + + DrawElements(Types::PrimitiveTriangle, 3 * 2 * 6, Types::ValueUShort); + + if (vtx_parm) + p.Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + + if (viscode != Frustum::Outside) + { + SetDepthFunc(DepthLess); + SetCullFunc(CullFront); + } + } +} +void Renderer::RenderPointLight(Core::Light &l, const DrawContext &dc) +{ + if (!view_item) + return; + + Shader &p = (l.shadow == Core::Light::Shadow_Map) && gpu_config.enable_shadow ? *pointlight_shadow_program : *pointlight_program; + + if (!l.volume_range) + RenderFullscreenLight(p, l); + + else + { + float k = l.volume_range; + float pointlight_vtx[] = + { + -k, k, -k, k, k, -k, k, -k, -k, -k, -k, -k, + -k, k, k, k, k, k, k, -k, k, -k, -k, k + }; + + const size_t stride = sizeof(float) * 3; + helper_vtx_vbo->Update(pointlight_vtx, 0, stride * 8); + + SetShaderProgram(&p); + SetIndexSource(box_idx_vbo); + SetVertexSource(helper_vtx_vbo, stride); + + ShaderInput *vtx_parm = p.GetInput(Core::ShaderInput::Position); + if (vtx_parm) + p.Set(*vtx_parm->location, 3, Types::ValueFloat, false, stride, 0); + + p.SetTransformInputs(m_projection, m_view, m_iview, &l.GetMatrix(), &l.GetInverseMatrix()); + p.SetLightInputs(*this, *view_item, l); + p.SetRendererInputs(*this); + p.CommitInputs(); + + // + MinMax vminmax; + vminmax.SetFromPositionSize(l.GetMatrix().GetRow(3), Vector4(l.volume_range, l.volume_range, l.volume_range) * 2.1f); + + bool inside = vminmax.IsInside(view_item->GetMatrix().GetRow(3)); + + if (inside) + { + SetDepthFunc(DepthGreater); + SetCullFunc(CullBack); + } + else + { + SetDepthFunc(DepthLess); + SetCullFunc(CullFront); + } + + DrawElements(Types::PrimitiveTriangle, 3 * 12, Types::ValueUShort); + + if (vtx_parm) + p.Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + + SetDepthFunc(DepthLess); + SetCullFunc(CullFront); + } +} +void Renderer::RenderLinearLight(Core::Light &l, const DrawContext &dc) +{ + RenderFullscreenQuad((l.shadow == Core::Light::Shadow_Map) && gpu_config.enable_shadow ? *linearlight_shadow_program : *linearlight_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, NULL, &l); +} +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/include/engine/gpu/gpu_material.cpp b/include/engine/gpu/gpu_material.cpp new file mode 100644 index 0000000..8f7a593 --- /dev/null +++ b/include/engine/gpu/gpu_material.cpp @@ -0,0 +1,172 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_material.h" + #include "gpu/gpu_renderer.h" + #include "core/material_to_shader_tree.h" + #include "core/shader_tree_convert_static_texture_block_to_dynamic.h" + #include "core/shader_tree_to_shader.h" + #include "core/shader_tree.h" + #include "log/log.h" + + using namespace GS; + using namespace GPU; + + +//------------------------------------------------------------------------------ +bool Material::ShouldReloadOnDependencyChange(const char *n) const +{ return (name == n) || (shader->GetName() == n); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Material::LoadTextureTable(Render::ResourceFactory &rf, const Core::Material &m) +{ + bool r = true; + for (uint n = 0; n < Core::Material::max_texture_stage; ++n) + { + texture_table[n] = rf.LoadTexture(m.texstage[n].t); + if (texture_table[n].IsNull()) + r = false; + } + return r; +} +static bool LoadCoreShader(Render::ResourceFactory &rf, const Core::Material &m, Core::Shader &core_shader, const char *name) +{ + using namespace Core; + + if (name == NULL) + { + // TODO convert material to shader directly (avoid creating an AST). + ShaderTree shader_tree; + if (!MaterialToShaderTree::Convert(m, shader_tree) || !ConvertShaderTreeToShader(shader_tree, core_shader)) + return false; + } + else + { + using namespace NML; + + // Load shader/shader tree. + File file; + if (!Parser::Load(name, file)) + return false; + + if (Tag *tag = file.GetTag("Shader")) + { + if (!core_shader.FromMetaTag(*tag)) + return false; + core_shader.name = m.shader; + } + else if (Tag *tag = file.GetTag("ShaderMap")) + { + ShaderTree shader_tree; + if (!shader_tree.FromMetaTag(*tag)) + return false; + + ConvertStaticToDynamicTextureBlocks(shader_tree, m); + + if (!ConvertShaderTreeToShader(shader_tree, core_shader)) + return false; + } + else + __ERR__(__LOG_E__ << "No shader or shader tree definition found in '" << m.shader << "'.\n", false) + } + return true; +} +bool Material::Create(Render::ResourceFactory &rf, const Core::Material &m) +{ + __LOG_H__ << "Load render material '" << m.name << "'.\n"; + name = m.name; + + using namespace Core; + + // Transfer basic material informations to the render data. + *((BasicMaterial *)this) = ((BasicMaterial &)m); + + // Load texture table. + LoadTextureTable(rf, m); + + // Load core shader. + MaterialShaderStaticParm parm; + + parm.no_lighting = asbool(m.renderword & Core::Material::Render_Unlit); + parm.use_skinning = asbool(m.renderword & Core::Material::Render_Skinned); + parm.use_alpha_test = asbool(m.renderword & Core::Material::Render_AlphaTest); + parm.use_depth_bias = asbool(m.depth_bias); + + Core::Shader core_shader; + bool load_core_shader = LoadCoreShader(rf, m, core_shader, m.shader); + + // Drop current material shader. + shader = NULL; + + // Look for a compatible material shader in cache. + if (load_core_shader) + ListForeachPtr(MaterialShader *, s, renderer.material_shaders) + if ((s->GetName() == core_shader.name) && (s->GetStaticParm() == parm)) + { + __LOG_V__ << "Reusing cached material shader for material '" << m.name << "'.\n"; + + shader = s; + return true; + } + + // Build a new one otherwise. + shader = new MaterialShader(renderer); + if (shader.IsNull()) + return false; + + if (!load_core_shader || !shader->Create(rf, core_shader, parm)) + { + if (!LoadCoreShader(rf, m, core_shader, "@core/builtin/shader/shader_error.nsa")) + return false; + if (!shader->Create(rf, core_shader, parm)) + return false; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Render::Material *Material::Clone() const +{ + Material *cloned = new Material(renderer); + + // __LOG_W__ << "[MaterialClone] Step 1c: 'new' returned successfully!\n"; + if (!cloned) + { + __LOG_E__ << "[MaterialClone] ERROR: Failed to allocate memory for cloned material!\n"; + return NULL; + } + // __LOG_W__ << "[MaterialClone] Step 1: Material instance created at " << (void*)cloned << "\n"; + + // Copy name (with "_clone" suffix to distinguish it) + // __LOG_W__ << "[MaterialClone] Step 2: Copying name...\n"; + cloned->name = name + "_clone"; + // __LOG_W__ << "[MaterialClone] Step 2: Name copied: '" << cloned->name << "'\n"; + + // Copy basic material properties (diffuse, specular, self, ambient, glossiness, etc.) + // __LOG_W__ << "[MaterialClone] Step 3: Copying BasicMaterial properties...\n"; + *((Core::BasicMaterial *)cloned) = *((Core::BasicMaterial *)this); + // __LOG_W__ << "[MaterialClone] Step 3: BasicMaterial properties copied.\n"; + + // Copy shader reference + // __LOG_W__ << "[MaterialClone] Step 4: Copying shader reference...\n"; + cloned->shader = shader; + // __LOG_W__ << "[MaterialClone] Step 4: Shader reference copied.\n"; + + // Copy texture table (smart pointers, so textures are shared, not duplicated) + // __LOG_W__ << "[MaterialClone] Step 5: Copying texture table...\n"; + for (uint n = 0; n < Core::Material::max_texture_stage; ++n) + { + cloned->texture_table[n] = texture_table[n]; + } + // __LOG_W__ << "[MaterialClone] Step 5: Texture table copied.\n"; + + // __LOG_W__ << "[MaterialClone] SUCCESS: Material cloned successfully as '" << cloned->name << "'.\n"; + + return cloned; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_material_shader.cpp b/include/engine/gpu/gpu_material_shader.cpp new file mode 100644 index 0000000..bc6f525 --- /dev/null +++ b/include/engine/gpu/gpu_material_shader.cpp @@ -0,0 +1,429 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_material_shader.h" + #include "gpu/gpu_material.h" + #include "gpu/gpu_renderer.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::GPU; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool MaterialShader::SetUserUniformValue(const char *name, const Vector4 &v) +{ + uint match_count = 0; + for (uint n = 0; n < variants.GetCount(); ++n) + if (Shader *shader = variants[n].c_ptr()) + if (ShaderInput *input = shader->GetInput(name)) + { + input->parm_v = v; + ++match_count; + } + + return match_count > 0; +} +bool MaterialShader::SetUserUniformValue(const char *name, Render::Texture *t) +{ + uint match_count = 0; + for (uint n = 0; n < variants.GetCount(); ++n) + if (Shader *shader = variants[n].c_ptr()) + if (ShaderInput *input = shader->GetInput(name)) + { + input->parm_t = t; + ++match_count; + } + + return match_count > 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void MaterialShader::CompileForwardPointLight(Core::Shader &shader, bool shadow) +{ + shader.Define("_POINT_LIGHT", Core::ShaderInput::Pixel); + CompileShaderSection("OutputForwardLightModel", shader); + + if (shadow) + { + shader.Define("_CAST_SHADOW", Core::ShaderInput::Pixel); + + shader.DeclareInput("psm", Core::ShaderInput::DataTextureShadow, Core::ShaderInput::LightShadowMap0, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + for (int n = 0; n < 6; ++n) + shader.DeclareInput(String::Format("psm_%d_projection_matrix", n), Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0 + n), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_iss", Core::ShaderInput::Float, Core::ShaderInput::InverseShadowMapSize, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_lsb", Core::ShaderInput::Float, Core::ShaderInput::LightShadowBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_vtl", Core::ShaderInput::Matrix4, Core::ShaderInput::ViewToLightMatrix, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_noise", Core::ShaderInput::DataTexture2D, Core::ShaderInput::NoiseMap, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + + if (Tag *t = renderer.GetPCFShaderTag()) + shader.pixel_decl += t->GetString(); + if (Tag *t = renderer.GetPSMShaderTag()) + shader.pixel.Replace("%psm_pcf_evaluation%", t->GetString()); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void MaterialShader::CompileForwardSpotLight(Core::Shader &shader, bool shadow, bool projection_map) +{ + shader.Define("_SPOT_LIGHT", Core::ShaderInput::Pixel); + CompileShaderSection("OutputForwardLightModel", shader); + + if (shadow) + { + shader.Define("_CAST_SHADOW", Core::ShaderInput::Pixel); + + shader.DeclareInput("u_ssm", Core::ShaderInput::DataTextureShadow, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMap0), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_ssm_projection", Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_iss", Core::ShaderInput::Float, Core::ShaderInput::InverseShadowMapSize, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_lsb", Core::ShaderInput::Float, Core::ShaderInput::LightShadowBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_noise", Core::ShaderInput::DataTexture2D, Core::ShaderInput::NoiseMap, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + + if (Tag *t = renderer.GetPCFShaderTag()) + shader.pixel_decl += t->GetString(); + } + + if (projection_map) + { + shader.Define("_PROJECTION_MAP", Core::ShaderInput::Pixel); + shader.DeclareInput("u_pjm", Core::ShaderInput::DataTexture2D, Core::ShaderInput::Semantic(Core::ShaderInput::LightProjectionMap), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_pjm_projection", Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void MaterialShader::CompileForwardLinearLight(Core::Shader &shader, bool shadow) +{ + shader.Define("_LINEAR_LIGHT", Core::ShaderInput::Pixel); + CompileShaderSection("OutputForwardLightModel", shader); + + if (shadow) + { + shader.Define("_CAST_SHADOW", Core::ShaderInput::Pixel); + + shader.DeclareInput("pssm", Core::ShaderInput::DataTextureShadow, Core::ShaderInput::LightShadowMap0, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + for (int n = 0; n < renderer.registry.GetInteger("ShadowMapping:PSSM:Split", 3); ++n) + { + shader.DeclareInput(String::Format("pssm_%d_slice_distance", n), Core::ShaderInput::Float, Core::ShaderInput::Semantic(Core::ShaderInput::LightPSSMSliceDistance0 + n), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput(String::Format("pssm_%d_projection_matrix", n), Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0 + n), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + } + shader.DeclareInput("u_noise", Core::ShaderInput::DataTexture2D, Core::ShaderInput::NoiseMap, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_iss", Core::ShaderInput::Float, Core::ShaderInput::InverseShadowMapSize, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.DeclareInput("u_lsb", Core::ShaderInput::Float, Core::ShaderInput::LightShadowBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + + if (Tag *t = renderer.GetPCFShaderTag()) + shader.pixel_decl += t->GetString(); + + if (Tag *t = renderer.GetPSSMShaderTag()) + shader.pixel.Replace("%pssm_pcf_evaluation%", t->GetString()); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool MaterialShader::CompileShaderSection(const char *id, Core::Shader &shader) +{ + Tag *shader_tag = renderer.GetMaterialDict().GetTag(id); + if (!shader_tag) + __ERR__(__LOG_E__ << "Missing shader section '" << id << "'.\n", false) + + if (Tag *tag = shader_tag->GetTag("Input;")) + shader.ParseInputTag(tag); + if (Tag *tag = shader_tag->GetTag("Varying;")) + shader.ParseVaryingTag(tag); + if (Tag *tag = shader_tag->GetTag("Vertex;")) + shader.vertex += tag->GetString(); + if (Tag *tag = shader_tag->GetTag("Fragment;")) + shader.pixel += tag->GetString(); + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool MaterialShader::SetupMaterialProgram(Variant p, Core::Shader &shader) +{ + if (parm.use_alpha_test) + { + shader.DeclareInput("u_alpha_threshold", Core::ShaderInput::Float, Core::ShaderInput::MaterialAlphaThreshold, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + shader.pixel += "if (%opacity% < u_alpha_threshold) discard;\n"; + } + + if (parm.use_depth_bias) + shader.DeclareInput("u_depth_bias", Core::ShaderInput::Float, Core::ShaderInput::MaterialDepthBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + + if (parm.use_skinning) + { + shader.Define("_SKINNED", (Core::ShaderInput::Scope)(Core::ShaderInput::Vertex | Core::ShaderInput::Pixel)); + shader.DeclareInput("bone_mtx", Core::ShaderInput::Matrix4, Core::ShaderInput::BoneMatrix, Core::ShaderInput::Uniform, Core::ShaderInput::Vertex, __PL_BONE_LIMIT__); + shader.DeclareInput("bone_idx", Core::ShaderInput::Vector4, Core::ShaderInput::BoneIndex, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex); + shader.DeclareInput("bone_w", Core::ShaderInput::Vector4, Core::ShaderInput::BoneWeight, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex); + shader.DeclareVarying("v_skin_mtx", "mat4"); + } + + CompileShaderSection("InputPosition;", shader); + + // Assemble program shader. + switch (p) + { + case Depth: + CompileShaderSection("OutputDepth;", shader); + break; + + case FS_Constant: + CompileShaderSection("OutputForwardConstant;", shader); + break; + + case FS_PointLight: + case FS_PointLightShadowMapping: + CompileForwardPointLight(shader, p == FS_PointLightShadowMapping); + break; + + case FS_SpotLight: + case FS_SpotLightShadowMapping: + case FS_SpotLightProjection: + case FS_SpotLightProjectionShadowMapping: + CompileForwardSpotLight(shader, (p == FS_SpotLightShadowMapping) || (p == FS_SpotLightProjectionShadowMapping), (p == FS_SpotLightProjection) || (p == FS_SpotLightProjectionShadowMapping)); + break; + + case FS_LinearLight: + case FS_LinearLightShadowMapping: + CompileForwardLinearLight(shader, p == FS_LinearLightShadowMapping); + break; + + case DS_GBufferMRT4: + CompileShaderSection("OutputDeferred;", shader); + break; + + case PP_NormalDepth: + CompileShaderSection("OutputNormalDepth;", shader); + break; + + case PP_Velocity: + if (parm.use_skinning) + shader.DeclareInput("previous_bone_mtx", Core::ShaderInput::Matrix4, Core::ShaderInput::PreviousBoneMatrix, Core::ShaderInput::Uniform, Core::ShaderInput::Vertex, __PL_BONE_LIMIT__); + CompileShaderSection("OutputVelocity;", shader); + break; + + case Last: + break; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static bool FindVarAssignation(const String &src, const char *var) // TODO fix with proper regex, this is proof of concept code at best... +{ + if (src.FindString(String::Format("%s =", var))) + return true; + if (src.FindString(String::Format("%s\t=", var))) + return true; + + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static void DeclareVertexPosition(Core::Shader &shader, bool declare_varying) +{ + String decl = "vec4 %position%;\n"; + + if (!asbool(FindVarAssignation(shader.vertex, "%position%"))) + { + Core::ShaderInput *input = shader.DeclareInput("a_position", Core::ShaderInput::Vector3, Core::ShaderInput::Position, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex); + // Core::ShaderInput *input = shader.GetInput(Core::ShaderInput::Position); + decl << "%position% = vec4(" << input->name << ", 1.0);\n"; + } + shader.vertex = decl + shader.vertex; +} +static void DeclareVertexNormal(Core::Shader &shader) +{ + String decl = "vec3 %normal%;\n"; + + if (!asbool(FindVarAssignation(shader.vertex, "%normal%"))) + { + Core::ShaderInput *input = shader.DeclareInput("a_normal", Core::ShaderInput::Vector3, Core::ShaderInput::Normal, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex); + // Core::ShaderInput *input = shader.GetInput(Core::ShaderInput::Normal); + decl << "%normal% = " << input->name << ";\n"; + } + shader.vertex = decl + shader.vertex; +} +static void InitializeShader(Core::Shader &shader) +{ + // Position + { + bool pixel_consumes = asbool(shader.pixel.FindString("%in.position%")); + DeclareVertexPosition(shader, pixel_consumes); + } + + // Normal + { + bool pixel_consumes = asbool(shader.pixel.FindString("%in.normal%")); + bool pixel_provides = FindVarAssignation(shader.pixel, "%normal%"); + + if (pixel_consumes || !pixel_provides) + DeclareVertexNormal(shader); + + if (!pixel_provides) + shader.pixel << "%normal% = %in.normal%;\n"; + + shader.pixel = String("vec3 %normal%;\n") + shader.pixel; + } + + { + struct ShaderDefault + { + const char *type, *name, *var; + Core::ShaderInput::DataType data_type; + Core::ShaderInput::Semantic semantic; + }; + + static ShaderDefault ps_ic[] = + { + { "vec4", "%diffuse%", "_u_mat_diff", Core::ShaderInput::Vector4, Core::ShaderInput::MaterialDiffuse }, + { "vec4", "%specular%", "_u_mat_spec", Core::ShaderInput::Vector4, Core::ShaderInput::MaterialSpecular }, + { "float", "%glossiness%", "_u_mat_glos", Core::ShaderInput::Float, Core::ShaderInput::MaterialGlossiness }, + { "vec4", "%constant%", "_u_mat_const", Core::ShaderInput::Vector4, Core::ShaderInput::MaterialSelf }, + { "float", "%opacity%", "_u_mat_opac", Core::ShaderInput::Float, Core::ShaderInput::MaterialOpacity }, + { NULL, NULL, NULL } + }; + + // Declare mandatory outputs and set default value for unprovided entries. + String decl; + for (uint n = 0; ps_ic[n].type; ++n) + { + decl << ps_ic[n].type << " " << ps_ic[n].name << ";\n"; + + if (!FindVarAssignation(shader.pixel, ps_ic[n].name)) + { + Core::ShaderInput *input = shader.DeclareInput(ps_ic[n].var, ps_ic[n].data_type, ps_ic[n].semantic, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel); + decl << ps_ic[n].name << " = " << input->name << ";\n"; + } + } + shader.pixel = decl + shader.pixel; + } +} +static void FinalizeShader(Core::Shader &shader) +{ + if (asbool(shader.pixel.FindString("%in.position%"))) + { + shader.DeclareVarying("_v_position", "vec4"); + shader.vertex << "_v_position = %position%;\n"; + } + if (asbool(shader.pixel.FindString("%in.normal%"))) + { + shader.DeclareVarying("_v_normal", "vec3"); + shader.vertex << "_v_normal = %normal%;\n"; + } + + shader.pixel.ReplaceAll("%in.position%", "_v_position", true); + shader.pixel.ReplaceAll("%in.normal%", "_v_normal", true); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static const char *GetShaderVariantName(MaterialShader::Variant v) +{ + switch (v) + { + case MaterialShader::Depth: return "Depth"; + + case MaterialShader::DS_GBufferMRT4: return "DS_GBufferMRT4"; + case MaterialShader::FS_Constant: return "FS_Constant"; + + case MaterialShader::FS_PointLight: return "FS_PointLight"; + case MaterialShader::FS_PointLightShadowMapping: return "FS_PointLightShadowMapping"; + + case MaterialShader::FS_LinearLight: return "FS_LinearLight"; + case MaterialShader::FS_LinearLightShadowMapping: return "FS_LinearLightShadowMapping"; + + case MaterialShader::FS_SpotLight: return "FS_SpotLight"; + case MaterialShader::FS_SpotLightShadowMapping: return "FS_SpotLightShadowMapping"; + case MaterialShader::FS_SpotLightProjection: return "FS_SpotLightProjection"; + case MaterialShader::FS_SpotLightProjectionShadowMapping: return "FS_SpotLightProjectionShadowMapping"; + + case MaterialShader::PP_NormalDepth: return "PP_NormalDepth"; + case MaterialShader::PP_Velocity: return "PP_Velocity"; + + case MaterialShader::Last: + break; + } + return "UnknownVariant"; +} +bool MaterialShader::Create(Render::ResourceFactory &rf, const Core::Shader &shader, const MaterialShaderStaticParm &static_parm) +{ + __LOG_V__ << "Creating material shader '" << shader.name << "' variants.\n"; + + name = shader.name; + parm = static_parm; + + // Build variants. + if (!variants.Allocate(Last)) + return false; + + for (int n = 0; n < Last; ++n) + { + if (renderer.render_technique == Renderer::TechniqueDeferred) + if ((n >= FS_Constant) && (n <= FS_SpotLightProjectionShadowMapping)) + continue; // no forward + + if (renderer.render_technique == Renderer::TechniqueForward) + if (n == DS_GBufferMRT4) + continue; // no deferred + + if (!renderer.gpu_config.enable_shadow) + if ( + (n == Depth) || + (n == FS_PointLightShadowMapping) || + (n == FS_LinearLightShadowMapping) || + (n == FS_SpotLightShadowMapping) || + (n == FS_SpotLightProjectionShadowMapping) + ) + continue; // no shadow-mapping + + if (!renderer.gpu_config.use_rtt) + if ( + (n == PP_Velocity) || + (n == PP_NormalDepth) + ) + continue; // no post-processes + + if (parm.no_lighting) + if ((n > FS_Constant) && (n <= FS_SpotLightProjectionShadowMapping)) // keep constant! + continue; // no lighting pass + + // Specialize shader for this program. + Core::Shader shader_variant; + if (!shader.Clone(shader_variant)) + return false; + + InitializeShader(shader_variant); + if (!SetupMaterialProgram((Variant)n, shader_variant)) + return false; + FinalizeShader(shader_variant); + + shader_variant.name << "_" << GetShaderVariantName((MaterialShader::Variant)n); + + // Compile it. + if ((variants[n] = (Shader *)renderer.NewShader()) != NULL) + if (!variants[n]->Create(rf, shader_variant)) + return false; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MaterialShader::MaterialShader(Renderer &r) : renderer(r) +{ renderer.material_shaders.Add(this); } +MaterialShader::~MaterialShader() +{ renderer.material_shaders.Remove(this); } +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_post_process_chain.cpp b/include/engine/gpu/gpu_post_process_chain.cpp new file mode 100644 index 0000000..52c85c5 --- /dev/null +++ b/include/engine/gpu/gpu_post_process_chain.cpp @@ -0,0 +1,668 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "gpu/gpu_renderer.h" + #include "gpu/gpu_geometry.h" + #include "gpu/gpu_shader_object.h" + #include "gpu/gpu_draw_context.h" + #include "core/geometry.h" + #include "rand/rand.h" + #include "log/log.h" + + using namespace GS; + using namespace GPU; + + +//------------------------------------------------------------------------------ +static bool IsPostProcessExcluded(NML::Tag *exclusion_key, const char *tag) +{ + NML::Tag *__t = exclusion_key ? exclusion_key->GetTypedTag(tag, Variant::VariantBool) : NULL; + return __t && __t->GetBool(); +} +//------------------------------------------------------------------------------ + +//--------------------------------------------------------------- +#define _SwapTarget { tmp = t[0]; t[0] = t[1]; t[1] = tmp; } +//--------------------------------------------------------------- + +//------------------------------------------------------------------------------ +void Renderer::GetPostProcessNormalDepth(const Stack display_lists[2]) +{ + if (normal_depth_updated) + return; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + fRect old_viewport = GetViewport(); + + // Generate normal/depth buffer. + SetViewport(fRect(0, 0, (float)t_fx[2]->GetWidth(), (float)t_fx[2]->GetHeight())); + fx_fbo->SetColorTexture(t_fx[2]); + + if (render_technique == TechniqueDeferred) + { + SetCurrentFBO(fx_fbo); + RenderFullscreenQuad(*single_texture_program, old_viewport.GetWidth() / (float)dimensions.x, old_viewport.GetHeight() / (float)dimensions.y, t_gbuffer[0]); + } + else + { + fx_fbo->SetDepthTexture(t_fx_depth); + SetCurrentFBO(fx_fbo); + + Clear(0, 0, 0); + DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::PP_NormalDepth); + DrawList(display_lists[0], dc); + + fx_fbo->SetDepthTexture(NULL); + } + + SetViewport(old_viewport); + normal_depth_updated = true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::ApplyDirectionalBlur(Render::Texture *t[2], const Vector2 &d, float attn) +{ + if (!fx_blur_program) + return; + + Render::Texture *tmp; + + ShaderInput *u_pass = fx_blur_program->GetInput("u_pass"), + *u_blur_d = fx_blur_program->GetInput("u_blur_d"), + *u_attenuation = fx_blur_program->GetInput("u_attenuation"); + + SetShaderProgram(fx_blur_program); + u_blur_d->SetValue(d.x, d.y); + u_attenuation->SetValue(attn); + + fRect nviewport(viewport.sx / dimensions.x, viewport.sy / dimensions.y, viewport.ex / dimensions.x, viewport.ey / dimensions.y); + + for (int n = 0; n < 4; ++n) + { + fx_fbo->SetColorTexture(t[1]); + SetCurrentFBO(fx_fbo); + u_pass->SetValue(float(n)); + RenderFullscreenQuad(*fx_blur_program, nviewport, fRect(0, 0, 1, 1), t[0]); + _SwapTarget + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::ApplyBloomFilter(Render::Texture *t_in, float strength, float threshold, float exponent, float radius, float strength_white_screen) +{ + if (!strength || !single_texture_cutoff_program || !tone_mapping_program) + return; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + Render::Texture *t[] = { t_fx[0], t_fx[1] }; + ShaderInput *u_cutoff = single_texture_cutoff_program->GetInput("u_cutoff"), + *u_strength = tone_mapping_program->GetInput("u_strength"), + *u_strength_white_screen = tone_mapping_program->GetInput("u_strength_white_screen"); + + if (!u_cutoff || !u_strength || !u_strength_white_screen) + return; + + fRect old_viewport = GetViewport(); + + fRect nviewport(viewport.sx / dimensions.x, viewport.sy / dimensions.y, viewport.ex / dimensions.x, viewport.ey / dimensions.y); + fRect fx_viewport(old_viewport.sx / fx_scale, old_viewport.sy / fx_scale, old_viewport.ex / fx_scale, old_viewport.ey / fx_scale); + + //-------------------------------------------------------------------------- + #define CutoffFrameToBloomFX \ + { \ + SetViewport(fx_viewport); \ + \ + fx_fbo->SetColorTexture(t[0]); \ + SetCurrentFBO(fx_fbo);\ + SetShaderProgram(single_texture_cutoff_program); \ + u_cutoff->SetValue(threshold); \ + RenderFullscreenQuad(*single_texture_cutoff_program, nviewport, fRect(0, 0, 1, 1), t_in); \ + } + + + #define OutputBloomFXToFrame \ + { \ + SetViewport(old_viewport);\ + \ + EnableBlending(true); \ + SetBlendFunc(BlendOne, BlendOne); \ + \ + fx_fbo->SetColorTexture(t_in); \ + SetCurrentFBO(fx_fbo);\ + SetShaderProgram(tone_mapping_program); \ + u_strength->SetValue(strength * 1.25f); \ + u_strength_white_screen->SetValue(strength_white_screen); \ + RenderFullscreenQuad(*tone_mapping_program, nviewport, fRect(0, 0, 1, 1), t[0]); \ + \ + EnableBlending(false); \ + } + //-------------------------------------------------------------------------- + + if (view_registry->GetBool("PostProcess:Bloom:Streak:Enabled", false)) + { + float angle = view_registry->GetReal("PostProcess:Bloom:Streak:Angle"), + attn = view_registry->GetReal("PostProcess:Bloom:Streak:Attenuation", 0.975f); + + for (int n = 0; n < 2; ++n) + { + Vector2 d = Vector2(cos(angle), sin(angle)) * radius / 12.f; + + CutoffFrameToBloomFX + ApplyDirectionalBlur(t, d, attn); + OutputBloomFXToFrame + + if (!view_registry->GetBool("PostProcess:Bloom:Streak:CrossShaped", false)) + break; + + angle += Units::Deg(90.f); + } + } + else + { + CutoffFrameToBloomFX + ApplyDirectionalBlur(t, Vector2(radius / 64.f, 0)); + ApplyDirectionalBlur(t, Vector2(0, radius / 64.f)); + OutputBloomFXToFrame + } + + SetViewport(old_viewport); + SetClippingRect(&old_viewport); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplyNoiseFilter(Render::Texture *t_in, Render::Texture *t_out, float strength, float mono, float bias) +{ + if (!strength || !noise_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + ShaderInput *u_strength = noise_program->GetInput("u_strength"), + *u_mono = noise_program->GetInput("u_mono"), + *u_bias = noise_program->GetInput("u_bias"), + *u_random = noise_program->GetInput("u_random"); + + if (!u_strength || !u_mono || !u_bias || !u_random) + return false; + + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + + float random[2] = { Random::FRand(), Random::FRand() }; + + SetShaderProgram(noise_program); + u_strength->SetValue(strength); + u_mono->SetValue(mono); + u_bias->SetValue(bias); + u_random->SetValue(random[0], random[1]); + RenderFullscreenQuad(*noise_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplySSAAFilter(Render::Texture *t_in, Render::Texture *t_out) +{ + if (!ssaa_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + + SetShaderProgram(ssaa_program); + RenderFullscreenQuad(*ssaa_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in); + + return true; +} + +//------------------------------------------------------------------------------ +bool Renderer::ApplyResolveMSAADepth(Render::Texture *t_depth_msaa, Render::Texture *t_out) +{ + if (!t_depth_msaa || !t_out || !resolve_msaa_depth_program) + return false; + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + + ShaderInput *msaa_depth = resolve_msaa_depth_program->GetInput("u_depthMSAA"); + SetShaderProgram(resolve_msaa_depth_program); + msaa_depth->SetValue(t_depth_msaa); + + RenderFullscreenQuad(*resolve_msaa_depth_program,viewport.GetWidth() / (float)dimensions.x,viewport.GetHeight() / (float)dimensions.y); + + return true; +} +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplySSAOFilter(Render::Texture *t_in, Render::Texture *t_out, const Stack display_lists[2], float s, float r, float d, float blur_r) +{ + if (!s || !ssao_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + ShaderInput *u_strength = ssao_program->GetInput("u_strength"), + *u_radius = ssao_program->GetInput("u_radius"), + *u_distance_scale = ssao_program->GetInput("u_distance_scale"), + *u_iproj2d = ssao_program->GetInput("u_iproj2d"); + + if (!u_strength || !u_radius || !u_distance_scale) + return false; + + GetPostProcessNormalDepth(display_lists); + +#if 0 + // Normal/depth debug output. + fx_fbo->SetColorTexture(t_in); + SetCurrentFBO(fx_fbo); + RenderFullscreenQuad(single_texture_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_fx[2]); + return false; +#endif + + fRect old_viewport = GetViewport(); + SetViewport(fRect(0, 0, (float)t_fx[2]->GetWidth(), (float)t_fx[2]->GetHeight())); + + // Render raw SSAO to FX texture. + SetShaderProgram(ssao_program); + u_strength->SetValue(s); + u_radius->SetValue(r * (4 / fx_scale)); + u_distance_scale->SetValue(d); + + float iproj[] = { 1.f / m_projection.m[0][0], 1.f / m_projection.m[1][1] }; + if (!gpu_config.tex_origin_is_top_left) + iproj[1] = -iproj[1]; + u_iproj2d->SetValue(iproj[0], iproj[1]); + + EnableAlphaTest(false); + EnableBlending(false); + + int out_index = 0; + fx_fbo->SetColorTexture(t_fx[out_index]); + SetCurrentFBO(fx_fbo); + Clear(0, 0, 0, 0, 1, ClearColor); // FIXME this is USELESS, but something is killing fragments with 0 alpha in ssao_program and disabling alpha testing does not solves the issue. + RenderFullscreenQuad(*ssao_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_fx[2]); + + if (ssao_blur_program) + { + // SSAO blur. + if (blur_r > 0.f) + { + ShaderInput *u_blur_radius = ssao_blur_program->GetInput("u_blur_radius"), + *u_normal_depth = ssao_blur_program->GetInput("u_normal_depth"); // the normal depth texture is not always used, depending on the quality settings. + + if (u_blur_radius && u_normal_depth) + { + fx_fbo->SetColorTexture(t_fx[1 - out_index]); + SetCurrentFBO(fx_fbo); + Clear(0, 0, 0, 0, 1, ClearColor); // FIXME this is USELESS, but something is killing fragments with 0 alpha in ssao_program and disabling alpha testing does not solves the issue. + + SetShaderProgram(ssao_blur_program); + u_blur_radius->SetValue(blur_r); + u_normal_depth->SetValue(t_fx[2].c_ptr()); + RenderFullscreenQuad(*ssao_blur_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_fx[out_index]); + + out_index = 1 - out_index; + } + } + } + + // Composite back over input. + SetViewport(old_viewport); + + fx_fbo->SetColorTexture(t_in); + SetCurrentFBO(fx_fbo); + + EnableBlending(true); + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + RenderFullscreenQuad(*single_texture_program, 1, 1, t_fx[out_index]); + EnableBlending(false); + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplySharpenFilter(Render::Texture *t_in, Render::Texture *t_out, float strength) +{ + if (!strength || !sharpen_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + ShaderInput *u_strength = sharpen_program->GetInput("u_strength"); + if (!u_strength) + return false; + + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + + SetShaderProgram(sharpen_program); + u_strength->SetValue(strength); + RenderFullscreenQuad(*sharpen_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplyHSL(Render::Texture *t_in, Render::Texture *t_out, float H, float S, float L) +{ + if (((H == 1.f) && (S == 1.f) && (L == 1.f)) || !hsl_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + ShaderInput *u_H = hsl_program->GetInput("u_H"), + *u_S = hsl_program->GetInput("u_S"), + *u_L = hsl_program->GetInput("u_L"); + if (!u_H || !u_S || !u_L) + return false; + + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + + SetShaderProgram(hsl_program); + u_H->SetValue(H); + u_S->SetValue(S); + u_L->SetValue(L); + RenderFullscreenQuad(*hsl_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplyChromaticDispersion(Render::Texture *t_in, Render::Texture *t_out, float width) +{ + if ((width == 0.f) || !chromatic_dispersion_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + ShaderInput *u_width = chromatic_dispersion_program->GetInput("u_width"); + if (!u_width) + return false; + + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + + SetShaderProgram(chromatic_dispersion_program); + u_width->SetValue(width); + RenderFullscreenQuad(*chromatic_dispersion_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplyRadialBlur(Render::Texture *t_in, Render::Texture *t_out, float strength, float center_x, float center_y) +{ + if (!strength || !radial_blur_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + ShaderInput *u_strength = radial_blur_program->GetInput("u_strength"), + *u_center = radial_blur_program->GetInput("u_center"); + + if (!u_strength || !u_center) + return false; + + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + + SetShaderProgram(radial_blur_program); + u_strength->SetValue(strength); + float center[] = { center_x * viewport.GetWidth() / (float)dimensions.x, center_y * viewport.GetHeight() / (float)dimensions.y }; + u_center->SetValue(center[0], center[1]); + RenderFullscreenQuad(*radial_blur_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ApplyMotionBlur(Render::Texture *t_in, Render::Texture *t_out, const Stack display_lists[2], float strength, int quality) +{ + if (!strength || !quality || !motion_blur_program) + return false; + + ScopedPerfEvent event(this, __FUNCTION__, Color::Purple); + + float k_u = viewport.GetWidth() / dimensions.x, k_v = viewport.GetHeight() / dimensions.y; + + // Generate a velocity buffer from the opaque surface list. + fRect old_viewport = GetViewport(); + { + ScopedPerfEvent event(this, "Render Velocity Buffer", Color::Purple); + + SetViewport(fRect(0, 0, (float)t_fx[0]->GetWidth(), (float)t_fx[0]->GetHeight())); + + fx_fbo->SetColorTexture(t_fx[0]); + fx_fbo->SetDepthTexture(t_fx_depth); + SetCurrentFBO(fx_fbo); + + Clear(0, 0, 0); + + DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::PP_Velocity); + DrawList(display_lists[0], dc); + } + + // Vector field blur. +#if 0 + float k_blur = 0.5; + Render::Texture *t_pp_0[] = { t_fx[0], t_fx[1] }; + ApplyDirectionalBlur(t_pp_0, nVector2(k_blur, 0), 0.975f); + Render::Texture *t_pp_1[] = { t_fx[1], t_fx[0] }; + ApplyDirectionalBlur(t_pp_1, nVector2(0, k_blur), 0.975f); +#endif + + // Apply velocity field. + fx_fbo->SetDepthTexture(NULL); + + // Quality: 0 - No PP, 1 - Lores blur, 2 - Hires blur. + if (quality == 1) + { + fx_fbo->SetColorTexture(t_fx[1]); + SetCurrentFBO(fx_fbo); + SetShaderProgram(single_texture_program); + RenderFullscreenQuad(*single_texture_program, 1, 1, t_in); + } + else + { + fx_fbo->SetColorTexture(t_out); + SetCurrentFBO(fx_fbo); + SetViewport(old_viewport); + } + + ShaderInput *u_strength = motion_blur_program->GetInput("u_strength"), + *u_pow = motion_blur_program->GetInput("u_pow"), + *u_max = motion_blur_program->GetInput("u_max"), + *u_source = motion_blur_program->GetInput("u_source"), + *u_velocity = motion_blur_program->GetInput("u_velocity"); + + SetShaderProgram(motion_blur_program); + const float k = 1.f; // stats.bench_fps.GetFps() / 60.f; // Normalize to 60fps. + + u_strength->SetValue(strength * 32.f * k); + u_pow->SetValue(2.f); + u_max->SetValue(1.f / 128.f); // Works in normalized space, does not need to adjust for variable resolution. + + motion_blur_program->Set(*u_velocity->location, *t_fx[0], u_velocity->index); + + if (quality == 1) // low-res blur path + { + fx_fbo->SetColorTexture(t_fx[2]); + SetCurrentFBO(fx_fbo); + u_source->SetValue(t_fx[1].c_ptr()); + RenderFullscreenQuad(*motion_blur_program, 1, 1); + + fx_fbo->SetColorTexture(t_in); + SetCurrentFBO(fx_fbo); + SetViewport(old_viewport); + + EnableBlending(true); + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + SetShaderProgram(single_texture_program); + RenderFullscreenQuad(*single_texture_program, k_u, k_v, t_fx[2]); + EnableBlending(false); + return false; + } + + u_source->SetValue(t_in); + RenderFullscreenQuad(*motion_blur_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Render::Texture *Renderer::ApplyPostProcessChain(const Stack display_lists[2]) +{ + ScopedBenchmark bench(stats.bench_post_process); + ScopedPerfEvent event(this, "Apply Post-Processing Chain", Color::Green); + + if (!gpu_config.use_rtt) + return t_compose[0]; + + normal_depth_updated = false; + + NML::Tag *post_process_registry = view_registry ? view_registry->GetTag("PostProcess") : NULL; + if (!post_process_registry) + return t_compose[0]; + NML::Tag *exclusion_key = registry.GetTag("PostProcess:Exclusion"); + + fRect old_clipping = GetClippingRect(); + SetClippingRect(NULL); + + uint i_compose = 0; + NML::Tag *tag; + + // SSAO. +#if !(__PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__) + if (((tag = post_process_registry->GetTag("SSAO")) != NULL) && !IsPostProcessExcluded(exclusion_key, "SSAO")) + if (ApplySSAOFilter + ( + t_compose[i_compose], + t_compose[1 - i_compose], + display_lists, + view_registry->GetReal("PostProcess:SSAO:Strength", 1), + view_registry->GetReal("PostProcess:SSAO:Radius", 2), + view_registry->GetReal("PostProcess:SSAO:DistanceScale", 0.5), + view_registry->GetReal("PostProcess:SSAO:BlurRadius", 8) + )) + i_compose = 1 - i_compose; +#endif + + // Sharpen. + if (((tag = post_process_registry->GetTag("Sharpen")) != NULL) && !IsPostProcessExcluded(exclusion_key, "Sharpen")) + if (ApplySharpenFilter + ( + t_compose[i_compose], + t_compose[1 - i_compose], + view_registry->GetReal("PostProcess:Sharpen:Strength", 0.5f) + )) + i_compose = 1 - i_compose; + + // SSAA. + if (render_technique == TechniqueDeferred) + if (registry.GetBool("Antialiasing:Enable", false)) + if (ApplySSAAFilter + ( + t_compose[i_compose], + t_compose[1 - i_compose] + )) + i_compose = 1 - i_compose; + +#if !(__PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__) + // Motion blur. + if (((tag = post_process_registry->GetTag("MotionBlur")) != NULL) && !IsPostProcessExcluded(exclusion_key, "MotionBlur")) + if (ApplyMotionBlur + ( + t_compose[i_compose], + t_compose[1 - i_compose], + display_lists, + view_registry->GetReal("PostProcess:MotionBlur:Strength", 0.5), + registry.GetInteger("PostProcess:MotionBlur:Quality", 2) + )) + i_compose = 1 - i_compose; +#endif + + // Radial blur. + if (((tag = post_process_registry->GetTag("RadialBlur")) != NULL) && !IsPostProcessExcluded(exclusion_key, "RadialBlur")) + if (ApplyRadialBlur + ( + t_compose[i_compose], + t_compose[1 - i_compose], + view_registry->GetReal("PostProcess:RadialBlur:Strength", 0.5), + view_registry->GetReal("PostProcess:RadialBlur:CenterX", 0.5), + view_registry->GetReal("PostProcess:RadialBlur:CenterY", 0.5) + )) + i_compose = 1 - i_compose; + + // Bloom. + if (((tag = post_process_registry->GetTag("Bloom")) != NULL) && !IsPostProcessExcluded(exclusion_key, "Bloom")) + ApplyBloomFilter + ( + t_compose[i_compose], + view_registry->GetReal("PostProcess:Bloom:Strength", 1), + view_registry->GetReal("PostProcess:Bloom:Threshold", 0.95f), + view_registry->GetReal("PostProcess:Bloom:Exponent", 4), + view_registry->GetReal("PostProcess:Bloom:Radius", 12), + view_registry->GetReal("PostProcess:Sharpen:Strength", 0.5f) + ); + + // Noise. +#if !(__PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__) + // TODO mobile version of this. + if (((tag = post_process_registry->GetTag("Noise")) != NULL) && !IsPostProcessExcluded(exclusion_key, "Noise")) + if (ApplyNoiseFilter + ( + t_compose[i_compose], + t_compose[1 - i_compose], + view_registry->GetReal("PostProcess:Noise:Strength", 0.25f), + view_registry->GetReal("PostProcess:Noise:Monochromatic", 0.f), + view_registry->GetReal("PostProcess:Noise:LumaBias", 0.5f) + ) ) + i_compose = 1 - i_compose; +#endif + + // HSL. + if (((tag = post_process_registry->GetTag("HueSaturation")) != NULL) && !IsPostProcessExcluded(exclusion_key, "HueSaturation")) + if (ApplyHSL + ( + t_compose[i_compose], + t_compose[1 - i_compose], + view_registry->GetReal("PostProcess:HueSaturation:H", 1), + view_registry->GetReal("PostProcess:HueSaturation:S", 1), + view_registry->GetReal("PostProcess:HueSaturation:L", 1) + ) ) + i_compose = 1 - i_compose; + + // Chromatic dispersion. + if (((tag = post_process_registry->GetTag("ChromDisp")) != NULL) && !IsPostProcessExcluded(exclusion_key, "ChromDisp")) + if (ApplyChromaticDispersion + ( + t_compose[i_compose], + t_compose[1 - i_compose], + view_registry->GetReal("PostProcess:ChromDisp:Width", 1) + ) ) + i_compose = 1 - i_compose; + + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + + SetClippingRect(&old_clipping); + + SetIndexSource(NULL); + SetVertexSource(NULL, 0); + return t_compose[i_compose]; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_profiler.cpp b/include/engine/gpu/gpu_profiler.cpp new file mode 100644 index 0000000..7644f6b --- /dev/null +++ b/include/engine/gpu/gpu_profiler.cpp @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "core/core_profiler.h" + #include "core/raster_font.h" + + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void Renderer::DrawProfilerText(GS::Render::RasterFont *font[2], float &x, float &y) +{ + Color title_color(1.f, 0.9f, 0); + WriterConfig config(false); + + Write(*font[1], String::Format("%s - %s (v%s)\n\n", GetName(), GetDescription(), GetVersion()), x, y, config, 1, &title_color); + + Write(*font[0], String::Format("Device: %s\n", stats.adapter.c_str()), x, y, config); + Write(*font[0], String::Format("Vendor: %s\n\n", stats.vendor.c_str()), x, y, config); + + Write(*font[0], String::Format("Texture: %s Geometry: %s\n\n", Core::FormatNumber(stats.texture_memory, Core::MemorySize).c_str(), Core::FormatNumber(stats.geometry_memory, Core::MemorySize).c_str()), x, y, config); + + Render::Renderer::DrawProfilerText(font, x, y); + + Write(*font[1], "Batching System\n\n", x, y, config, 1, &title_color); + Write(*font[0], String::Format("Program change = %0.02f%% (%d)\n", gpu_stats.prg_change ? (gpu_stats.prg_change * 100.f) / stats.list_drawn : 0, gpu_stats.prg_change), x, y, config); + Write(*font[0], String::Format("List change = %0.02f%% (%d)\n", gpu_stats.dls_change ? (gpu_stats.dls_change * 100.f) / stats.list_drawn : 0, gpu_stats.dls_change), x, y, config); + Write(*font[0], String::Format("Material change = %0.02f%% (%d)\n", gpu_stats.mat_change ? (gpu_stats.mat_change * 100.f) / stats.list_drawn : 0, gpu_stats.mat_change), x, y, config); + Write(*font[0], String::Format("Item change = %0.02f%% (%d)\n\n", gpu_stats.item_change ? (gpu_stats.item_change * 100.f) / stats.list_drawn : 0, gpu_stats.item_change), x, y, config); + + Write(*font[1], "Terrain System\n\n", x, y, config, 1, &title_color); + Write(*font[0], String::Format("Cache miss = %0.02f%% (%d query/frame)\n\n", gpu_stats.terrain_page_query_count ? (gpu_stats.terrain_page_query_miss * 100.f) / gpu_stats.terrain_page_query_count : 0, gpu_stats.terrain_page_query_count), x, y, config); + + Write(*font[1], String::Format("Technique: %s\n\n", render_technique == TechniqueDeferred ? "Deferred" : "Forward"), x, y, config, 1, &title_color); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_registry.cpp b/include/engine/gpu/gpu_registry.cpp new file mode 100644 index 0000000..b891326 --- /dev/null +++ b/include/engine/gpu/gpu_registry.cpp @@ -0,0 +1,71 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + + using namespace GS; + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +RegistryRValue Renderer::ProcessMessage(RegistryMessage m, const Registry *registry, const void *parm) +{ + switch (m) + { + case RegistryMsg_StartKeyChangeBatch: + break; + + case RegistryMsg_EndKeyChangeBatch: + if (pending_shadow_map_refresh) + CreateShadowMaps(); + if (pending_core_shader_refresh) + LoadCoreShaders(); + + if (pending_technique_refresh) + SetRenderTechnique(); + if (pending_fx_refresh) + SetPostProcess(); + + pending_shadow_map_refresh = false; + pending_core_shader_refresh = false; + pending_technique_refresh = false; + pending_fx_refresh = false; + break; + + case RegistryMsg_KeyChange: + if (RegistryKeyChange *key = (RegistryKeyChange *)parm) + { + if ((key->key == "ShadowMapping:Enable") || (key->key == "ShadowMapping:Size")) + { + gpu_config.enable_shadow = registry->GetBool("ShadowMapping:Enable", true); + pending_shadow_map_refresh = true; + } + else if (key->key == "ShadowMapping:PSSM:Split") + { + pending_shadow_map_refresh = true; + pending_core_shader_refresh = true; + } + else if (key->key == "ShadowMapping:PCF:Quality") + pending_core_shader_refresh = true; + + else if (key->key == "Texture:Float:Enable") + pending_technique_refresh = true; + else if (key->key == "Technique") + pending_technique_refresh = true; + else if (key->key.StartsWith("Antialiasing")) + pending_technique_refresh = true; + + else if (key->key == "PostProcess:FX:Scale") + pending_fx_refresh = true; + } + break; + + default: + break; + } + return RegistryReturn_Ok; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_render_display_list.cpp b/include/engine/gpu/gpu_render_display_list.cpp new file mode 100644 index 0000000..a8cd8d8 --- /dev/null +++ b/include/engine/gpu/gpu_render_display_list.cpp @@ -0,0 +1,155 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "gpu/gpu_geometry.h" + #include "gpu/gpu_shader_object.h" + #include "gpu/gpu_draw_context.h" + #include "core/object.h" + #include "core/camera.h" + #include "core/geometry.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +#define ENABLE_PERFORMANCE_TOOLS + +#ifdef ENABLE_PERFORMANCE_TOOLS + #define _ProgramCacheMiss ++gpu_stats.prg_change; + #define _DisplayListCacheMiss ++gpu_stats.dls_change; + #define _MaterialCacheMiss ++gpu_stats.mat_change; + #define _ItemCacheMiss ++gpu_stats.item_change; + + #define _SetPerfWire if (performance_tools.show_wireframe) SetFillMode(FillWireframe); + #define _UnsetPerfWire if (performance_tools.show_wireframe) SetFillMode(FillSolid); +#else + #define _ProgramCacheMiss + #define _DisplayListCacheMiss + #define _MaterialCacheMiss + #define _ItemCacheMiss + + #define _SetPerfWire + #define _UnsetPerfWire +#endif +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::ResetDisplayListCache() +{ + if (dls_cache.dls) + SetDisplayList(NULL); + dls_cache.dls = NULL; + + if (dls_cache.mat) + UnsetMaterial(*dls_cache.mat, dls_cache.ctx); + dls_cache.mat = NULL; + + if (dls_cache.shd) + SetShaderProgram(NULL, dls_cache.shd); + dls_cache.shd = NULL; + + dls_cache.item = NULL; +} +bool Renderer::SetDrawContext(DisplayList &dls, const Core::Item &item, const DrawContext &dc) +{ + Material *mat = dls.material.IsValid() ? (Material *)dls.material.c_ptr() : NULL; + if (!mat || !mat->shader) + return false; + Shader *shd = mat->shader->variants[dc.ctx.variant]; + if (!shd) + return false; + + #define ProgramChange (1 << 0) + #define DisplayListChange (1 << 1) + #define MaterialChange (1 << 2) + #define ItemChange (1 << 3) + #define OpacityChange (1 << 4) + + uint change_mask = 0; + change_mask |= (shd != dls_cache.shd) ? ProgramChange : 0; + change_mask |= (&dls != dls_cache.dls) ? DisplayListChange : 0; + change_mask |= (mat != dls_cache.mat) ? MaterialChange : 0; + change_mask |= (&item != dls_cache.item) ? ItemChange : 0; + change_mask |= (item.opacity != dls_cache.opacity) ? OpacityChange : 0; + + if (change_mask & ProgramChange) + { + if (!SetShaderProgram(shd, dls_cache.shd)) + return false; + _ProgramCacheMiss + } + + if (change_mask & ProgramChange) + shd->SetConstantInputs(); + + if (change_mask & DisplayListChange) + { + SetDisplayList(&dls); + _DisplayListCacheMiss + } + if (change_mask & MaterialChange) + { + if (dls_cache.mat) + UnsetMaterial(*dls_cache.mat, dc.ctx); + SetMaterial(*mat, dc.ctx, asbool(item.opacity < 1.f)); + _MaterialCacheMiss + } + + // Program inputs. + if (change_mask & ProgramChange) + { + shd->SetRendererInputs(*this, mat); + if (dc.light) + shd->SetLightInputs(*this, *view_item, *dc.light); + } + if (change_mask & (ProgramChange | MaterialChange | OpacityChange)) + shd->SetMaterialOpacityInputs(*mat, item.opacity); + if (change_mask & (ProgramChange | MaterialChange)) + { + shd->SetMaterialInputs(*mat); + shd->SetTextureInputs(); + } + if (change_mask & (ProgramChange | DisplayListChange)) + shd->SetVertexStreamInputs(dls); + if (change_mask & (ProgramChange | ItemChange)) + { + shd->SetTransformInputs(m_projection, m_view, m_iview, &m_world, &m_iworld); + shd->SetPreviousTransformInputs(m_projection, m_previous_iview, &m_previous_world); + _ItemCacheMiss + } + if (change_mask & (ProgramChange | DisplayListChange | ItemChange)) + if (Core::Skin *skin = ((Core::Object &)item).GetSkin()) + shd->SetSkinInputs(dls, *skin); + + shd->CommitInputs(); + + // Sync cache. + dls_cache.ctx = dc.ctx; + dls_cache.shd = shd; + dls_cache.mat = mat; + dls_cache.dls = &dls; + dls_cache.item = &item; + dls_cache.opacity = item.opacity; + + return true; +} +void Renderer::DrawDisplayListCached(DisplayList &dls, const Core::Item &item, const DrawContext &dc) +{ + if (!SetDrawContext(dls, item, dc)) + return; + + // Draw. + _SetPerfWire + dls.Draw(); + _UnsetPerfWire + + stats.list_drawn++; + stats.triangle_drawn += dls.index_count / 3; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_render_queue.cpp b/include/engine/gpu/gpu_render_queue.cpp new file mode 100644 index 0000000..bb4048b --- /dev/null +++ b/include/engine/gpu/gpu_render_queue.cpp @@ -0,0 +1,298 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "gpu/gpu_renderer.h" + #include "gpu/gpu_geometry.h" + #include "core/renderer_environment_interface.h" + #include "core/terrain.h" + #include "core/geometry.h" + #include "sort/sort.h" + #include "container/container_sort.h" + #include "platform_config.h" + #include "log/log.h" + + using namespace GS; + using namespace GPU; + + +//------------------------------------------------------------------------------ +void Renderer::DrawList(const Stack &dl_list, const DrawContext &dc) +{ + ResetDisplayListCache(); + DecayTerrainCache(); + + m_previous_iview = view_item->GetPreviousMatrix().InversedFast(); + + for (uint n = 0; n < dl_list.GetCount(); ++n) + { + RenderPrimitive *dl = dl_list[n]; + + if (!dl->item) + continue; + + switch (dl->type) + { + case RenderPrimitive::TypeDisplayList: + if (dl->dlst) + { + m_previous_world = dl->item->GetPreviousMatrix(); + SetWorldMatrix(dl->item->GetMatrix(), &dl->item->GetInverseMatrix()); + DrawDisplayListCached(*dl->dlst, *dl->item, dc); + } + break; + + case RenderPrimitive::TypeTerrainPatch: + if (dl->patch) + RenderTerrainPatch(*dl->patch, *dl->item, dc); + break; + + case RenderPrimitive::TypeEmitter: + break; + } + } + + ResetDisplayListCache(); + stats.queue_pass++; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static inline uint GetRenderPrimitiveSortKey(RenderPrimitive *a) +{ + // Watch nRenderMaterial and nGPUDisplayList size in bytes so that this key stays optimal. + return ((((uint)a->dlst->material.c_ptr() >> 8) & 0xffff) << 16) + (((uint)a->dlst >> 7) & 0xffff); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::SortDisplayList(AutoStack &d_list) const +{ + const uint count = d_list.GetCount(); + if (count == 0) + return; + try { + // Byte sort list. + typedef Sort SortPrimitive; + Array sort_a(count), sort_b(count); + + for (uint n = 0; n < count; ++n) + { + sort_a[n].o = d_list[n]; + sort_a[n].v = GetRenderPrimitiveSortKey(d_list[n]); + } + Array *out = SortPrimitive::ByteSort(count, &sort_a, &sort_b); + + // Empty the source stack, prevent primitives cleanup... + d_list.DropContentOwnership(); + + // ...as we now insert them back in sorted order. + for (uint n = 0; n < count; ++n) + d_list.Push((*out)[n].o); + } + catch(char *e) + { + __LOG__ << "Failed to SortDisplayList.\n"; + } +} +static int GetMaterialDrawPassIndex(Render::Material *m, float opacity = 1.f) +{ + if (m->renderword & Core::Material::Render_UseFramebuffer) + return 2; + if ((m->blendop != Core::Material::Blend_None) || (opacity < 1.0)) + return 1; + return 0; +} +void Renderer::BuildDisplayLists(const AutoStack &p_list, AutoStack *d_list) const +{ + for (uint n = 0; n < p_list.GetCount(); ++n) + { + Render::Primitive *p = p_list[n]; + + switch (p->type) + { + case Render::Primitive::Type_Geometry: + if (Geometry *geo = (Geometry *)p->geometry.c_ptr()) + for (uint n = 0; n < geo->display_list.GetCount(); ++n) + { + DisplayList *dlist = geo->display_list[n]; + if (dlist->material.IsNull()) + continue; + + int draw_pass_index = GetMaterialDrawPassIndex(dlist->material, p->item->opacity); + d_list[draw_pass_index].Push(new RenderPrimitive(p->item, dlist)); + } + break; + + case Render::Primitive::Type_TerrainPatch: + if (p->patch->terrain->render_data->material.IsNull()) + continue; + d_list[GetMaterialDrawPassIndex(p->patch->terrain->render_data->material, p->patch->terrain->opacity)].Push(new RenderPrimitive(p->item, p->patch)); + break; + + case Render::Primitive::Type_Emitter: + break; + } + } + + for (int n = 0; n < 3; ++n) + SortDisplayList(d_list[n]); +} +void Renderer::RenderList() +{ + ScopedBenchmark bench(stats.bench_render); + PerfSetMarker("RenderList", Color::Green); + + // Build primitive list. + stats.renderable_processed += BuildRenderablePrimitiveList(*view_item, *view_item, frustum_rlist.primitive_list); + stats.renderable_drawn += frustum_rlist.primitive_list.GetCount(); + + // Build display lists. + BuildDisplayLists(frustum_rlist.primitive_list, frustum_rlist.display_lists); + + // Render opaque display lists. + switch (render_technique) + { + case TechniqueDeferred: + RenderListDeferred(frustum_rlist.display_lists[0]); + break; + + case TechniqueForward: + RenderListForward(frustum_rlist.display_lists[0], DrawContext::Opaque); + + if (environment_interface) // draw skybox + { + Render::Shader *user_skybox_shader = environment_interface->GetSkyboxShader(); + + Render::sTexture skybox_layers[2]; + if (environment_interface->GetSkyboxLayers(skybox_layers) || user_skybox_shader) + DrawSkybox(skybox_layers, user_skybox_shader); + } + break; + } + + // Render transparent display lists. + RenderListForward(frustum_rlist.display_lists[1], DrawContext::Alpha); + + // Render frame buffer dependent display lists. + if (gpu_config.use_rtt && ((frustum_rlist.display_lists[2].GetCount() > 0) || registry.GetBool("FrameBufferAsTexture;", false))) + { + GrabDisplay(t_fx[0]); + RenderListForward(frustum_rlist.display_lists[2], DrawContext::Opaque); + } + + // Render direct user primitives hook. + if (environment_interface) + environment_interface->OnRenderUser(this); + + // + switch (render_technique) + { + case TechniqueDeferred: + // Render fog. + if (environment_interface) + if (environment_interface->IsFogEnabled() && !performance_tools.disable_fog) + { + EnableBlending(true); + RenderFullscreenQuad(*ds_fog_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y); + EnableBlending(false); + } + break; + + case TechniqueForward: + // Resolve MSSA target. + if (gpu_config.enable_aa) + render_fbo->Blit(resolve_fbo, iRect(0, 0, dimensions.x, dimensions.y), iRect(0, 0, dimensions.x, dimensions.y), true, true); + break; + } + + // Post-processes. + if (gpu_config.use_rtt) + { + t_final = ApplyPostProcessChain(frustum_rlist.display_lists); + resolve_fbo->SetColorTexture(t_final); + } + + // Drop render list. + frustum_rlist.Clear(false); + + // Subsequent draws should render to the final texture. + if (gpu_config.use_rtt) + SetCurrentFBO(resolve_fbo); + render_fbo = resolve_fbo; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::BeginDrawList() +{ + PerfSetMarker("BeginDrawList", Color::Green); + + // Cache per-frame values for coherency. + frame_clock = environment_interface ? environment_interface->GetClock() : 0; + pcf_radius = registry.GetReal("ShadowMapping:PCF:Radius", 1.75f); + + if (environment_interface) + if (Core::Camera *c = environment_interface->GetCurrentCamera()) + { + SetCamera(c); + ApplyCamera(); + } + + /* + MSAA needs a special resolve step so we work on a different FBO which + will later be resolved to the resolve FBO. + */ + render_fbo = gpu_config.enable_aa ? buffer_fbo : resolve_fbo; + + if (render_technique == TechniqueForward) + { + if (gpu_config.use_rtt) + SetCurrentFBO(render_fbo); + + // Clear output, if a skybox is set it will be rendered after the opaque pass. + if (environment_interface) + { + Render::Shader *user_skybox_shader = environment_interface->GetSkyboxShader(); + + Render::sTexture skybox_layers[2]; + if (environment_interface->GetSkyboxLayers(skybox_layers) || user_skybox_shader) + Clear(0, 0, 0, 1, 1, ClearDepth); + else + { + Color bg = environment_interface->GetClearColor(); + Clear(bg.x, bg.y, bg.z); + } + } + } + + t_final = t_compose[0]; + return true; +} +void Renderer::EndDrawList() +{ + PerfSetMarker("EndDrawList", Color::Green); + + // when entering this function the current FBO is expected to be render_FBO. + if (gpu_config.use_rtt) + { + // Blit result to user output_fbo. + if (output_fbo) + render_fbo->Blit(output_fbo, viewport.AsInt(), output_fbo_rect, true, false); + + // Blit to frame buffer. + SetCurrentFBO(NULL); + fRect src(viewport.sx / dimensions.x, viewport.sy / dimensions.y, viewport.ex / dimensions.x, viewport.ey / dimensions.y); + RenderFullscreenQuad(*single_texture_program, src, fRect(0, 0, 1, 1), t_final); // viewport is already set for destination so use the full rect output + + // Restore default output. + resolve_fbo->SetColorTexture(t_final = t_compose[0]); + } + + SetIndexSource(NULL); + SetVertexSource(NULL, 0); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_render_queue_deferred.cpp b/include/engine/gpu/gpu_render_queue_deferred.cpp new file mode 100644 index 0000000..802f172 --- /dev/null +++ b/include/engine/gpu/gpu_render_queue_deferred.cpp @@ -0,0 +1,82 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "gpu/gpu_renderer.h" + #include "gpu/gpu_geometry.h" + #include "gpu/gpu_draw_context.h" + #include "core/renderer_environment_interface.h" + #include "core/camera.h" + #include "core/light.h" + + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void Renderer::RenderGBufferPass(const GS::Stack &display_lists) +{ + SetCurrentFBO(buffer_fbo); + Clear(0, 0, 0, 0); + + DrawContext dc(DrawContext::Deferred, DrawContext::Base, MaterialShader::DS_GBufferMRT4); + DrawList(display_lists, dc); +} +void Renderer::RenderDeferredLightPass(const GS::Stack &) +{ + SetCurrentFBO(resolve_fbo); + + DrawContext dc(DrawContext::Deferred, DrawContext::Light); + + // Clear to ambient. + EnableDepthWrite(false); + RenderFullscreenQuad(*ambient_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y); + EnableDepthWrite(true); + + // For each light in frustum, render affected primitives with a light specific shader. + SetBlendFunc(BlendOne, BlendOne); + + List light_list; + environment_interface->GetLightsInFrustum(view_item->GetMatrix().GetRow(3), frustum, light_list); + + ListForeachPtr(Core::Light *, l, light_list) + { + // Render shadow map. + if (gpu_config.enable_shadow && l->shadow == Core::Light::Shadow_Map) + { + if (PrepareShadowMap(*l, true)) // TODO move to job + RenderShadowMap(*l); + + SetCurrentFBO(resolve_fbo); + SetBlendFunc(BlendOne, BlendOne); + } + + // Compose light. + EnableDepthWrite(false); + EnableBlending(true); + + switch (l->model) + { + case Core::Light::Model_Point: RenderPointLight(*l, dc); break; + case Core::Light::Model_Linear: RenderLinearLight(*l, dc); break; + case Core::Light::Model_Spot: RenderSpotLight(*l, dc); break; + } + + EnableBlending(false); + EnableDepthWrite(true); + stats.light_processed++; + } + + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::RenderListDeferred(const GS::Stack &display_lists) +{ + RenderGBufferPass(display_lists); + if (environment_interface) + RenderDeferredLightPass(display_lists); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_render_queue_forward.cpp b/include/engine/gpu/gpu_render_queue_forward.cpp new file mode 100644 index 0000000..71ce9e3 --- /dev/null +++ b/include/engine/gpu/gpu_render_queue_forward.cpp @@ -0,0 +1,318 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "gpu/gpu_shader_object.h" + #include "gpu/gpu_geometry.h" + #include "gpu/gpu_draw_context.h" + #include "core/renderer_environment_interface.h" + #include "core/geometry.h" + #include "core/terrain.h" + #include "core/camera.h" + #include "core/light.h" + #include "async/job.h" + #include "alloc/ialloc.h" + #include "platform.h" + + using namespace GS; + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void Renderer::LightCullDisplayList(const Core::Light &light, const Stack &in, Stack &out) +{ + for (uint n = 0; n < in.GetCount(); ++n) + { + RenderPrimitive *dl = in[n]; + + switch (light.model) + { + case Core::Light::Model_Point: + if (light.range > 0) + { + MinMax &mm = dl->dlst->minmax; + Vector4 dl_lpos = light.GetMatrix().GetRow(3) * dl->item->GetInverseMatrix(); + + if ( ((dl_lpos.x - light.range) < mm.mx.x) && + ((dl_lpos.x + light.range) > mm.mn.x) && + ((dl_lpos.y - light.range) < mm.mx.y) && + ((dl_lpos.y + light.range) > mm.mn.y) && + ((dl_lpos.z - light.range) < mm.mx.z) && + ((dl_lpos.z + light.range) > mm.mn.z) ) + out.Push(dl); + } + else + out.Push(dl); + break; + + case Core::Light::Model_Spot: + if (light.frustum.ClassifyMinMax(dl->dlst->minmax, &dl->item->GetMatrix()) != Frustum::Outside) + out.Push(dl); + break; + + case Core::Light::Model_Linear: + default: + out.Push(dl); + break; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::SetupForwardContext(const DrawContext::Context &ctx) +{ + switch (ctx.draw) + { + case DrawContext::Base: + switch (ctx.render) + { + case DrawContext::Opaque: + EnableDepthTest(true); + break; + + case DrawContext::Alpha: + EnableDepthWrite(false); + EnableBlending(true); + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + break; + } + break; + + case DrawContext::Light: + switch (ctx.render) + { + case DrawContext::Opaque: + EnableBlending(true); + SetBlendFunc(BlendSrcAlpha, BlendOne); + break; + + case DrawContext::Alpha: + EnableDepthWrite(false); + EnableBlending(true); + SetBlendFunc(BlendSrcAlpha, BlendOne); + break; + } + break; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +class GPU::PrepareLightJob : public ASync::Job +{ + const Renderer &renderer; + const Core::Light &light; + + const Stack ∈ + Stack &out; + + DrawContext::Render rc; + +public: + + NPLACEMENT_NEW(RendererJob) + + bool use_shadow; + + bool CullPrimitive(const Render::Material *m, const MinMax &mm, const Core::Item *item) const + { + if (m->renderword & Core::Material::Render_Unlit) + return false; // exclude from lighting + + switch (light.model) + { + case Core::Light::Model_Point: + if (light.range > 0) + { + Vector4 dl_lpos = light.GetMatrix().GetRow(3) * item->GetInverseMatrix(); + + if ( ((dl_lpos.x - light.range) < mm.mx.x) && + ((dl_lpos.y - light.range) < mm.mx.y) && + ((dl_lpos.z - light.range) < mm.mx.z) && + ((dl_lpos.x + light.range) > mm.mn.x) && + ((dl_lpos.y + light.range) > mm.mn.y) && + ((dl_lpos.z + light.range) > mm.mn.z) ) + return true; + } + else + return true; + break; + + case Core::Light::Model_Spot: + if (light.frustum.ClassifyMinMax(mm, &item->GetMatrix()) != Frustum::Outside) + return true; + break; + + default: + case Core::Light::Model_Linear: + return true; + } + return false; + } + void Execute(uint) + { + for (uint n = 0; n < in.GetCount(); ++n) + { + RenderPrimitive *dl = in[n]; + + bool r = false; + switch (dl->type) + { + case RenderPrimitive::TypeDisplayList: + r = CullPrimitive(dl->dlst->material, dl->dlst->minmax, dl->item); + break; + case RenderPrimitive::TypeTerrainPatch: + r = CullPrimitive(dl->patch->terrain->render_data->material, dl->patch->minmax, dl->item); + break; + + default: + case RenderPrimitive::TypeEmitter: + break; + } + if (r) + out.Push(dl); + } + + // Prepare shadow map if required. + if (out.GetCount() == 0) + use_shadow = false; + + else + { + use_shadow = renderer.gpu_config.enable_shadow && (light.shadow == Core::Light::Shadow_Map); + if ((rc == DrawContext::Alpha) && (light.shadow_cast_all == false)) + use_shadow = false; + + bool use_shadow_matrix = false; + if ((light.model == Core::Light::Model_Spot) && !light.projection_texture.IsEmpty()) + use_shadow_matrix = true; + + if (use_shadow || use_shadow_matrix) + renderer.PrepareShadowMap(light, use_shadow); + } + } + + PrepareLightJob(const Renderer &_renderer, const Core::Light &_light, const Stack &_in, Stack &_out, DrawContext::Render _rc) : Job("Light Draw Setup"), renderer(_renderer), light(_light), in(_in), out(_out), rc(_rc) {} +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static MaterialShader::Variant DispatchLightShaderVariant(Core::Light::Model type, bool shadow, bool projection_map) +{ +static MaterialShader::Variant table[2][2][Core::Light::Model_Last] = + { + { + { MaterialShader::Last, MaterialShader::FS_PointLight, MaterialShader::FS_LinearLight, MaterialShader::FS_SpotLight }, + { MaterialShader::Last, MaterialShader::FS_PointLightShadowMapping, MaterialShader::FS_LinearLightShadowMapping, MaterialShader::FS_SpotLightShadowMapping } + }, + { + { MaterialShader::Last, MaterialShader::FS_PointLight, MaterialShader::FS_LinearLight, MaterialShader::FS_SpotLightProjection }, + { MaterialShader::Last, MaterialShader::FS_PointLightShadowMapping, MaterialShader::FS_LinearLightShadowMapping, MaterialShader::FS_SpotLightProjectionShadowMapping } + } + }; + return table[projection_map ? 1 : 0][shadow ? 1 : 0][type]; +} +void Renderer::DrawForwardBaseConstant(DrawContext::Render rc, const Stack &dl_list) +{ + ScopedPerfEvent event(this, __FUNCTION__, Color::Blue); + + DrawContext dc(rc, DrawContext::Base, MaterialShader::FS_Constant); + SetupForwardContext(dc.ctx); + DrawList(dl_list, dc); +} +void Renderer::DrawForwardLightContribution(DrawContext::Render rc, const List &light_list, const AutoStack &setup_jobs, const Array > &dl_list) +{ + ScopedPerfEvent event(this, "Render light contribution", Color::Blue); + + DrawContext dc(rc, DrawContext::Light, MaterialShader::FS_Constant); + SetupForwardContext(dc.ctx); + + EnableDepthWrite(false); + SetDepthFunc(DepthLessEqual); + + uint job_count = 0; + ListForeachPtr(Core::Light *, l, light_list) + { + if (l->model == Core::Light::Model_None) + continue; + + // Wait for the light setup job to complete. + Platform::Get().job_manager->JoinJob(setup_jobs[job_count]); + + if (dl_list[job_count].GetCount()) + { + bool use_shadow = setup_jobs[job_count]->use_shadow; + + if (use_shadow) + { + PerfBeginEvent("Render shadow map", Color::Yellow); + + EnableDepthWrite(true); + RenderShadowMap(*l); + EnableDepthWrite(false); + + SetCurrentFBO(gpu_config.use_rtt ? render_fbo : NULL); + SetupForwardContext(dc.ctx); + + PerfEndEvent(); + } + + // Add contribution. + dc.ctx.variant = DispatchLightShaderVariant(l->model, use_shadow, asbool(l->projection_texture)); + dc.light = l; + + DrawList(dl_list[job_count], dc); + } + + ++stats.light_processed; + ++job_count; + } +} +void Renderer::RenderListForward(Stack &dl_list, DrawContext::Render rc) +{ + ScopedPerfEvent event(this, __FUNCTION__, Color::Red); + + if (dl_list.GetCount() == 0) + return; + + // Setup all lights. + List frustum_light_list; + environment_interface->GetLightsInFrustum(view_item->GetMatrix().GetRow(3), frustum, frustum_light_list); + + Array > light_dl_list(frustum_light_list.GetCount()); + AutoStack light_setup_job(frustum_light_list.GetCount()); + + uint job_count = 0; + ListForeachPtr(Core::Light *, l, frustum_light_list) + { + if (l->model == Core::Light::Model_None) + continue; + + if (PrepareLightJob *job = new PrepareLightJob(*this, *l, dl_list, light_dl_list[job_count++], rc)) + { + light_setup_job.Push(job); + Platform::Get().job_manager->EnqueueJob(job); + } + } + + // Draw all passes. + DrawForwardBaseConstant(rc, dl_list); + DrawForwardLightContribution(rc, frustum_light_list, light_setup_job, light_dl_list); + + // + CollectJobsPerf(light_setup_job, job_count, stats.bench_prepare_light); + + // Restore default state. + SetCullFunc(CullFront); + + SetDepthFunc(DepthLess); + EnableDepthWrite(true); + + EnableBlending(false); + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_renderer.cpp b/include/engine/gpu/gpu_renderer.cpp new file mode 100644 index 0000000..7872156 --- /dev/null +++ b/include/engine/gpu/gpu_renderer.cpp @@ -0,0 +1,462 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "core/renderer_environment_interface.h" + #include "core/renderer_resource_factory.h" + #include "core/camera.h" + + using namespace GS; + using namespace GS::GPU; + using Render::TextureParm; + + +//------------------------------------------------------------------------------ +void Renderer::SetViewMatrix(const Matrix4 &m, const Matrix4 *inverse) +{ + m_view = m; + m_iview = inverse ? *inverse : m.InversedFast(); +} +void Renderer::SetProjectionMatrix(const Matrix4 &m) +{ m_projection = m; } +void Renderer::SetWorldMatrix(const Matrix4 &m, const Matrix4 *inverse) +{ + m_world = m; + m_iworld = inverse ? *inverse : m.InversedFast(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int Renderer::GetAnisotropySampleCount(TextureParm::Anisotropy aniso) const +{ + uint sample = 1; + + switch (aniso) + { + default: + sample = registry.GetInteger("Texture:Filtering:Sample", 4); + break; + + case TextureParm::AnisotropyNone: sample = 1; break; + case TextureParm::Anisotropy2x: sample = 2; break; + case TextureParm::Anisotropy4x: sample = 4; break; + case TextureParm::Anisotropy8x: sample = 8; break; + case TextureParm::Anisotropy16x: sample = 16; break; + } + + if (sample > gpu_config.max_anisotropy) + sample = gpu_config.max_anisotropy; + + return sample; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::SetDisplayList(DisplayList *dlist) +{ + SetIndexSource(dlist ? dlist->idx.c_ptr() : NULL); + SetVertexSource(dlist ? dlist->vtx.c_ptr() : NULL, dlist ? dlist->stride : 0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::SetMaterial(const GPU::Material &m, const DrawContext::Context &ctx, bool force_alpha) +{ + bool fog_enabled = (environment_interface != NULL) && environment_interface->IsFogEnabled(); + + if (m.renderword & Core::Material::Render_DoubleSided) + EnableCulling(false); + + if (m.renderword & Core::Material::Render_AlphaTest) + if (gpu_config.enable_aa) + EnableAlphaToCoverage(true); + + uint blendop = m.blendop; + if ((blendop == Core::Material::Blend_None) && force_alpha) + blendop = Core::Material::Blend_Alpha; + + switch (ctx.render) + { + case DrawContext::Deferred: + case DrawContext::Opaque: + break; + + case DrawContext::Alpha: + switch (ctx.draw) + { + case DrawContext::Base: + switch (blendop) + { + case Core::Material::Blend_Add: + if (fog_enabled) + SetBlendFunc(BlendSrcAlpha, BlendOne); + else + SetBlendFunc(BlendOne, BlendOne); + break; + + case Core::Material::Blend_Alpha: + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + break; + } + break; + + case DrawContext::Light: + switch (blendop) + { + case Core::Material::Blend_Add: + if (fog_enabled) + SetBlendFunc(BlendSrcAlpha, BlendOne); + else + SetBlendFunc(BlendOne, BlendOne); + break; + + case Core::Material::Blend_Alpha: + SetBlendFunc(BlendSrcAlpha, BlendOne); + break; + } + break; + } + } +} +void Renderer::UnsetMaterial(const GPU::Material &m, const DrawContext::Context &ctx) +{ + if (m.renderword & Core::Material::Render_DoubleSided) + EnableCulling(true); + + if (m.renderword & Core::Material::Render_AlphaTest) + if (gpu_config.enable_aa) + EnableAlphaToCoverage(false); + + switch (ctx.render) + { + case DrawContext::Deferred: + case DrawContext::Opaque: + break; + + case DrawContext::Alpha: + switch (ctx.draw) + { + case DrawContext::Base: + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + break; + + case DrawContext::Light: + SetBlendFunc(BlendSrcAlpha, BlendOne); + break; + } + break; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::DrawSetState(Core::Material::BlendOperator bo, Core::Material::RenderWord f) +{ + switch (bo) + { + default: + case Core::Material::Blend_None: + break; + + case Core::Material::Blend_Alpha: + EnableBlending(true); + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + break; + case Core::Material::Blend_Add: + EnableBlending(true); + SetBlendFunc(BlendSrcAlpha, BlendOne); + break; + } + + EnableDepthWrite(!asbool(f & Core::Material::Render_NoZWrite)); + EnableDepthTest(!asbool(f & Core::Material::Render_NoZTest)); + EnableCulling(!asbool(f & Core::Material::Render_DoubleSided)); +} +void Renderer::DrawRestoreState(Core::Material::BlendOperator bo, Core::Material::RenderWord f) +{ + EnableCulling(true); + EnableDepthTest(true); + EnableDepthWrite(true); + + if (bo != Core::Material::Blend_None) + { + EnableBlending(false); + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); + } +} +void Renderer::DrawLine(uint count, const Vector4 *v, const Color *c, Core::Material::BlendOperator bo, Core::Material::RenderWord f, Render::Shader *r_p) +{ + DrawSetState(bo, f); + + // Dispatch inputs to the correct program. + Shader *p = (Shader *)r_p; + + if (p == NULL) + { + p = c ? single_color_program : simple_program; + + if (!p) + return; + } + SetShaderProgram(p); + + ShaderInput *vtx_parm = p->GetInput(Core::ShaderInput::Position), + *color_parm = p->GetInput(Core::ShaderInput::VertexColor); + + SetIndexSource(NULL); // FIXME broken on the DirectX back-end + SetVertexSource(NULL, 0); // FIXME broken on the DirectX back-end + + if (vtx_parm) + p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, sizeof(Vector4), (const void *)v); + if (color_parm && c) + p->Set(*color_parm->location, 4, Types::ValueFloat, false, sizeof(Color), (const void *)c); + + p->SetRendererInputs(*this); + p->SetTransformInputs(m_projection, m_view, m_iview, &m_world, &m_iworld); + + DrawElements(Types::PrimitiveLine, 2 * count); + + if (vtx_parm) + p->Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + if (color_parm) + p->Set(*color_parm->location, 0, Types::ValueLast, false, 0, NULL); + + DrawRestoreState(bo, f); +} +void Renderer::DrawTriangle(uint count, const Vector4 *v, const ushort *idx, const Color *c, const Vector2 *uv, const Render::Texture *t, Core::Material::BlendOperator bo, Core::Material::RenderWord f, Render::Shader *r_p) +{ + DrawSetState(bo, f); + + // Dispatch inputs to the correct program. + Shader *p = (Shader *)r_p; + + if (p == NULL) + { + if (c) + p = t ? single_texture_color_program : single_color_program; + else + if (t) + p = single_texture_program; + + if (!p) + return; + } + SetShaderProgram(p); + + // If no indice were provided, assume a linear attribute array. + Array indice; + if (!idx) + if (indice.Allocate(count * 3)) + { + idx = indice; + for (uint n = 0; n < count * 3; ++n) + indice[n] = ushort(n); + } + + // Set program inputs. + ShaderInput *vtx_parm = p->GetInput(Core::ShaderInput::Position), + *uv_parm = p->GetInput(Core::ShaderInput::UV0), + *color_parm = p->GetInput(Core::ShaderInput::VertexColor), + *texture_parm = p->GetInput(Core::ShaderInput::Texture2D); + + if (gpu_config.can_stream_vertex_from_memory) + { + SetIndexSource(NULL); + SetVertexSource(NULL, 0); + + if (vtx_parm) + p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, sizeof(Vector4), (const void *)v); + if (uv_parm && uv) + p->Set(*uv_parm->location, 2, Types::ValueFloat, false, sizeof(Vector2), (const void *)uv); + if (color_parm && c) + p->Set(*color_parm->location, 4, Types::ValueFloat, false, sizeof(Color), (const void *)c); + } + else + { + DirectVertexLayout layout; + BuildDirectVertexLayout(count * 3, idx, v, c, uv, layout, direct_idx_vbo, direct_vtx_vbo); + + SetIndexSource(direct_idx_vbo); + SetVertexSource(direct_vtx_vbo, layout.stride); + + if (vtx_parm) + p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, layout.stride, (const void *)layout.vtx_offset); + if (uv_parm && uv) + p->Set(*uv_parm->location, 2, Types::ValueFloat, false, layout.stride, (const void *)layout.uv_offset); + if (color_parm && c) + p->Set(*color_parm->location, 4, Types::ValueUByte, true, layout.stride, (const void *)layout.color_offset); + } + + if (texture_parm && t) + p->Set(*texture_parm->location, *t, texture_parm->index); + + p->SetRendererInputs(*this); + p->SetTransformInputs(m_projection, m_view, m_iview, &m_world, &m_iworld); + p->CommitInputs(); + + DrawElements(Types::PrimitiveTriangle, count * 3, Types::ValueUShort, gpu_config.can_stream_vertex_from_memory ? idx : 0); + + if (vtx_parm) + p->Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + if (uv_parm) + p->Set(*uv_parm->location, 0, Types::ValueLast, false, 0, NULL); + if (color_parm) + p->Set(*color_parm->location, 0, Types::ValueLast, false, 0, NULL); + + DrawRestoreState(bo, f); + stats.triangle_drawn += count; +} +void Renderer::DrawSprite(uint count, const Vector4 *v, const Color *c, const float *s, const Render::Texture *t, float g_size, Core::Material::BlendOperator bo, Core::Material::RenderWord f, Render::Shader *r_p) +{ + Array sprite_p; + Array sprite_c; + Array sprite_uv; + Array sprite_idx; + + Shader *p = (Shader *)r_p; + + if (p == NULL) + p = simple_program; + + // Setup display list. + if (!sprite_p.Allocate(count * 4) || !sprite_idx.Allocate(count * 3 * 2)) + return; + + Vector4 *p_v = sprite_p.c_ptr(); + ushort *idx = sprite_idx.c_ptr(); + + Vector4 left = m_view.GetRow(0), + up = m_view.GetRow(1); + + if (s) + for (uint n = 0; n < count; ++n) + { + register float k = g_size * s[n]; + Vector4 uml = (up - left) * k; + Vector4 lpu = (left + up) * k; + Vector4 lmu = (left - up) * k; + *p_v++ = v[n] + uml; + *p_v++ = v[n] + lpu; + *p_v++ = v[n] + lmu; + *p_v++ = v[n] - lpu; + } + else + for (uint n = 0; n < count; ++n) + { + Vector4 uml = (up - left) * g_size; + Vector4 lpu = (left + up) * g_size; + Vector4 lmu = (left - up) * g_size; + *p_v++ = v[n] + uml; + *p_v++ = v[n] + lpu; + *p_v++ = v[n] + lmu; + *p_v++ = v[n] - lpu; + } + + for (ushort n = 0; n < count; ++n) + { + ushort s = (ushort)(n << 2); + *idx++ = s; *idx++ = s + 1; *idx++ = s + 2; + *idx++ = s; *idx++ = s + 2; *idx++ = s + 3; + } + + if (c) // Color. + { + if (!sprite_c.Allocate(count * 4)) + return; + + Color *p_c = sprite_c.c_ptr(); + for (uint n = 0; n < count; ++n) + { + const Color &cl = c[n]; + for (uint i = 0; i < 4; ++i) + *p_c++ = cl; + } + + p = single_color_program; + } + + if (t) // Texture. + { + if (!sprite_uv.Allocate(count * 4)) + return; + + Vector2 *p_uv = sprite_uv.c_ptr(); + for (uint n = 0; n < count; ++n) + { + p_uv[0].Set(0, 0); p_uv[1].Set(1, 0); + p_uv[2].Set(1, 1); p_uv[3].Set(0, 1); + p_uv += 4; + } + + p = c ? single_texture_color_program : single_texture_program; + } + + // Compute aspect ratio. + Matrix4 m_ar; + if (view_item) + m_ar = Matrix4::ScaleMatrix(view_item->ComputeAspectRatioCorrection(viewport)); + else m_ar = Matrix4::ScaleMatrix(Vector4(viewport.GetHeight() / viewport.GetWidth(), 1, 0, 1)); + + // Set program inputs. + DrawSetState(bo, f); + SetShaderProgram(p); + + ShaderInput *vtx_parm = p->GetInput(Core::ShaderInput::Position), + *uv_parm = p->GetInput(Core::ShaderInput::UV0), + *color_parm = p->GetInput(Core::ShaderInput::VertexColor), + *texture_parm = p->GetInput(Core::ShaderInput::Texture2D); + + if (vtx_parm) + p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, sizeof(Vector4), (const void *)sprite_p.c_ptr()); + if (uv_parm && t) + p->Set(*uv_parm->location, 2, Types::ValueFloat, false, sizeof(Vector2), (const void *)sprite_uv.c_ptr()); + if (color_parm && c) + p->Set(*color_parm->location, 4, Types::ValueFloat, false, sizeof(Color), (const void *)sprite_c.c_ptr()); + if (texture_parm && t) + p->Set(*texture_parm->location, *t, texture_parm->index); + + p->SetRendererInputs(*this); + p->SetTransformInputs(m_projection, m_view, m_iview, &m_world, &m_iworld); + p->CommitInputs(); + + DrawElements(Types::PrimitiveTriangle, sprite_idx.GetCount(), Types::ValueUShort, sprite_idx.c_ptr()); + + if (vtx_parm) + p->Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + if (uv_parm) + p->Set(*uv_parm->location, 0, Types::ValueLast, false, 0, NULL); + if (color_parm) + p->Set(*color_parm->location, 0, Types::ValueLast, false, 0, NULL); + + DrawRestoreState(bo, f); + stats.triangle_drawn += count * 2; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Renderer::Renderer() : terrain_patch_vtx(Alloc::RendererTerrain), terrain_patch_cache(Alloc::RendererTerrain) +{ + core_resource_factory = new Render::RendererResourceFactory(*this); + + pending_shadow_map_refresh = false; + pending_core_shader_refresh = false; + + render_technique = TechniqueForward; + + m_view = Matrix4::IdentityMatrix(); + m_iview = Matrix4::IdentityMatrix(); + m_world = Matrix4::IdentityMatrix(); + m_iworld = Matrix4::IdentityMatrix(); + + m_projection = Matrix4::IdentityMatrix(); + + pcf_radius = 1.75f; + frame_clock = 0.f; + + clipping.Set(-1, -1, -1, -1); + output_fbo = NULL; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_renderer.h b/include/engine/gpu/gpu_renderer.h index d244a74..b78182a 100644 --- a/include/engine/gpu/gpu_renderer.h +++ b/include/engine/gpu/gpu_renderer.h @@ -218,6 +218,7 @@ protected: radial_blur_program, motion_blur_program, + resolve_msaa_depth_program, skybox_program; /*! @@ -325,6 +326,7 @@ public: bool ApplySSAOFilter(Render::Texture *t_in, Render::Texture *t_out, const Stack [2], float strength, float radius, float clip_distance, float blur_radius); bool ApplyRadialBlur(Render::Texture *t_in, Render::Texture *t_out, float strength, float center_x, float center_y); bool ApplyMotionBlur(Render::Texture *t_in, Render::Texture *t_out, const Stack [2], float strength, int quality = 1); + bool ApplyResolveMSAADepth(Render::Texture *t_depth_msaa, Render::Texture *t_out); void GetPostProcessNormalDepth(const Stack display_lists[2]); diff --git a/include/engine/gpu/gpu_shader.cpp b/include/engine/gpu/gpu_shader.cpp new file mode 100644 index 0000000..524f59f --- /dev/null +++ b/include/engine/gpu/gpu_shader.cpp @@ -0,0 +1,674 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #ifndef __PLATFORM_IOS__ + #include + #endif + #include "gpu/gpu_renderer.h" + #include "core/renderer_environment_interface.h" + #include "core/light.h" + #include "core/camera.h" + #include "core/object.h" + #include "core/shader.h" + #include "container/narray.h" + #include "platform_config.h" + #include "platform.h" + #include "log/file_log.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void Shader::SetVertexStreamInputs(DisplayList &dls) +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryVertexStream].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryVertexStream][n]; + + switch (input->semantic) + { + case Core::ShaderInput::Position: + Set(*input->location, 3, Types::ValueHalfFloat, false, dls.stride, (const void *)dls.vertex_offset); + break; + case Core::ShaderInput::Normal: + Set(*input->location, 3, Types::ValueByte, true, dls.stride, (const void *)dls.normal_offset); + break; + case Core::ShaderInput::VertexColor: + Set(*input->location, 4, Types::ValueUByte, true, dls.stride, (const void *)dls.rgb_offset); + break; + + case Core::ShaderInput::Tangent: + Set(*input->location, 3, Types::ValueByte, true, dls.stride, (const void *)dls.tangent_offset); + break; + case Core::ShaderInput::Bitangent: + Set(*input->location, 3, Types::ValueByte, true, dls.stride, (const void *)(dls.tangent_offset + 4 * sizeof(char))); + break; + + case Core::ShaderInput::BoneIndex: + Set(*input->location, 4, Types::ValueUByte, false, dls.stride, (const void *)dls.skinning_offset); + break; + case Core::ShaderInput::BoneWeight: + Set(*input->location, 4, Types::ValueUByte, true, dls.stride, (const void *)(dls.skinning_offset + 4 * sizeof(char))); + break; + + case Core::ShaderInput::UV0: + case Core::ShaderInput::UV1: + case Core::ShaderInput::UV2: + { + int uv_index = (int)input->semantic - (int)Core::ShaderInput::UV0; + Set(*input->location, 2, Types::ValueHalfFloat, false, dls.stride, (const void *)dls.uv_offset[uv_index]); + } + break; + } + } +} +void Shader::SetSkinInputs(DisplayList &dls, Core::Skin &skin) +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategorySkin].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategorySkin][n]; + + switch (input->semantic) + { + case Core::ShaderInput::BoneMatrix: + if (float *m = (float *)alloca(4 * 4 * sizeof(float) * dls.bone.GetCount())) + { + float *p_m = m; + for (uint n = 0; n < dls.bone.GetCount(); ++n) + { + Memory::Copy(p_m, skin.bones_mtx[dls.bone[n]].m, 4 * 4 * sizeof(float)); + p_m += 4 * 4; + } + + Set(*input->location, (Matrix4 *)m, dls.bone.GetCount()); + } + break; + + case Core::ShaderInput::PreviousBoneMatrix: + if (float *m = (float *)alloca(4 * 4 * sizeof(float) * dls.bone.GetCount())) + { + float *p_m = m; + for (uint n = 0; n < dls.bone.GetCount(); ++n) + { + Memory::Copy(p_m, skin.previous_bones_mtx[dls.bone[n]].m, 4 * 4 * sizeof(float)); + p_m += 4 * 4; + } + + Set(*input->location, (Matrix4 *)m, dls.bone.GetCount()); + } + break; + } + } +} +void Shader::SetConstantInputs() +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryConstant].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryConstant][n]; + + switch (input->semantic) + { + case Core::ShaderInput::Constant: + switch (input->data_type) + { + default: + case Core::ShaderInput::Matrix3: + case Core::ShaderInput::Matrix4: + break; + + case Core::ShaderInput::DataTexture2D: + case Core::ShaderInput::DataTexture3D: + case Core::ShaderInput::DataTextureCube: + Set(*input->location, *input->parm_t, input->index); + break; + + case Core::ShaderInput::Int: + Set(*input->location, (int *)&input->parm_v.x); + break; + case Core::ShaderInput::Float: + Set(*input->location, &input->parm_v.x); + break; + case Core::ShaderInput::Vector2: + Set(*input->location, &input->parm_v.x, 2); + break; + case Core::ShaderInput::Vector3: + Set(*input->location, &input->parm_v.x, 3); + break; + case Core::ShaderInput::Vector4: + Set(*input->location, &input->parm_v.x, 4); + break; + } + break; + } + } +} +void Shader::SetTextureInputs() +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryTexture].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryTexture][n]; + + switch (input->semantic) + { + case Core::ShaderInput::Texture2D: + case Core::ShaderInput::Texture3D: + case Core::ShaderInput::TextureCube: + if (input->parm_t) + Set(*input->location, *input->parm_t, input->index); + break; + } + } +} +void Shader::SetRendererInputs(Renderer &r, Material *m) +{ + Color fog_color; + float fog_near = 0, fog_far = 0; + + bool fog_enabled = r.environment_interface ? r.environment_interface->GetFogConfiguration(fog_color, fog_near, fog_far) : false; + + if (r.performance_tools.disable_fog) + fog_enabled = false; + if (m && (m->blendop == Core::Material::Blend_Add)) + fog_enabled = false; + + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryRenderer].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryRenderer][n]; + + switch (input->semantic) + { + case Core::ShaderInput::Clock: + Set(*input->location, r.frame_clock); + break; + case Core::ShaderInput::TimeOfDay: + Set(*input->location, r.environment_interface->GetTimeOfDay()); + break; + + case Core::ShaderInput::ViewVector: + { + Vector4 tmp = r.GetCamera()->GetMatrix().GetRow(2); + Set(*input->location, &tmp.x, 3); + } + break; + case Core::ShaderInput::ViewPosition: + { + Vector4 tmp = r.GetCamera()->GetMatrix().GetRow(3); + Set(*input->location, &tmp.x, 4); + } + break; + case Core::ShaderInput::Viewport: + { + const fRect viewport = r.GetViewport(); + float v[4] = { viewport.sx, viewport.sy, viewport.GetWidth(), viewport.GetHeight() }; + Set(*input->location, v, 4); + } + break; + + case Core::ShaderInput::ZNear: + Set(*input->location, r.GetCamera()->GetNearClippingPlane()); + break; + case Core::ShaderInput::ZFar: + Set(*input->location, r.GetCamera()->GetFarClippingPlane()); + break; + case Core::ShaderInput::ZoomFactor: + Set(*input->location, r.GetCamera()->zoom_factor); + break; + + case Core::ShaderInput::DisplayBufferRatio: + { + float v[] = { r.GetOutputAspectRatio(), 1.f }; + Set(*input->location, v, 2); + } + break; + + case Core::ShaderInput::ViewportRatio: + { + float v[] = { r.GetViewport().GetHeight() / r.GetViewport().GetWidth(), 1.f }; + Set(*input->location, v, 2); + } + break; + + case Core::ShaderInput::FxScale: + Set(*input->location, float(r.fx_scale)); + break; + + case Core::ShaderInput::InverseBufferSize: + { + tVector2 d = r.GetOutputDimensions(); + float v[] = { 1.f / d.x, 1.f / d.y }; + Set(*input->location, v, 2); + } + break; + + case Core::ShaderInput::InverseViewportSize: + { + float v[] = { 1.f / r.GetViewport().GetWidth(), 1.f / r.GetViewport().GetHeight() }; + Set(*input->location, v, 2); + } + break; + + case Core::ShaderInput::ViewDepthOffset: + { + float k = 0.f; + Set(*input->location, &k); + } + break; + + case Core::ShaderInput::AmbientColor: + { + Color ambient = r.environment_interface->GetAmbientColor(); + Set(*input->location, &ambient.x, 3); + } + break; + + case Core::ShaderInput::FogColor: + Set(*input->location, &fog_color.x, 3); + break; + case Core::ShaderInput::FogNear: + Set(*input->location, fog_near); + break; + case Core::ShaderInput::FogFar: + Set(*input->location, fog_far); + break; + case Core::ShaderInput::FogInverseRange: + { + bool use_fog = fog_enabled && (fog_far > 0.0); + if (m && (m->renderword & Core::Material::Render_NoFog)) + use_fog = false; + + Set(*input->location, use_fog ? 1.f / (fog_far - fog_near) : -1.f); + } + break; + + case Core::ShaderInput::DepthBuffer: + if (r.render_technique == Renderer::TechniqueDeferred) + Set(*input->location, *r.t_gbuffer[0], input->index); + else Set(*input->location, *r.t_depth, input->index); + break; + + case Core::ShaderInput::FrameBuffer: + if (r.t_fx[0].IsValid()) + Set(*input->location, *r.t_fx[0], input->index); + break; + + case Core::ShaderInput::GBuffer0: + case Core::ShaderInput::GBuffer1: + case Core::ShaderInput::GBuffer2: + case Core::ShaderInput::GBuffer3: + Set(*input->location, *r.t_gbuffer[input->semantic - Core::ShaderInput::GBuffer0], input->index); + break; + + case Core::ShaderInput::NoiseMap: + if (r.t_noise.IsValid()) + Set(*input->location, *r.t_noise, input->index); + break; + } + } +} +void Shader::SetTransformInputs(const Matrix4 &v_pm, const Matrix4 &v_m, const Matrix4 &v_im, const Matrix4 *i_m, const Matrix4 *i_im, uint count) +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryTransform].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryTransform][n]; + + switch (input->semantic) + { + case Core::ShaderInput::NormalMatrix: + if (Matrix3 *n_m = (Matrix3 *)alloca(sizeof(Matrix3) * count)) + { + for (uint n = 0; n < count; ++n) + n_m[n] = Matrix3::FromMatrix4(i_m[n]).Normalized(); + Set(*input->location, n_m, count); + } + break; + case Core::ShaderInput::NormalViewMatrix: + if (Matrix3 *nv_m = (Matrix3 *)alloca(sizeof(Matrix3) * count)) + { + Matrix3 vn_m = Matrix3::FromMatrix4(v_m).Normalized().Transposed(); + for (uint n = 0; n < count; ++n) + nv_m[n] = vn_m * Matrix3::FromMatrix4(i_m[n]).Normalized(); + Set(*input->location, nv_m, count); + } + break; + + case Core::ShaderInput::ModelMatrix: + Set(*input->location, i_m, count); + break; + case Core::ShaderInput::ViewMatrix: + Set(*input->location, v_im); + break; + case Core::ShaderInput::ProjectionMatrix: + Set(*input->location, v_pm); + break; + case Core::ShaderInput::ModelViewMatrix: + if (Matrix4 *mv_m = (Matrix4 *)alloca(sizeof(Matrix4) * count)) + { + for (uint n = 0; n < count; ++n) + mv_m[n] = v_im * i_m[n]; + Set(*input->location, mv_m, count); + } + break; + + case Core::ShaderInput::ModelViewProjectionMatrix: + if (Matrix4 *mvp_m = (Matrix4 *)alloca(sizeof(Matrix4) * count)) + { + for (uint n = 0; n < count; ++n) + mvp_m[n] = v_pm * (v_im * i_m[n]); + Set(*input->location, mvp_m, count); + } + break; + + case Core::ShaderInput::InverseViewProjectionMatrix: + { + Matrix4 vpm = v_pm * v_im, ivpm; + vpm.Inverse(ivpm); + Set(*input->location, ivpm); + } + break; + + case Core::ShaderInput::InverseViewProjectionMatrixAtOrigin: + { + Matrix4 v_im_o = v_im; + v_im_o.SetRow(3, Vector4(0, 0, 0, 1)); + + Matrix4 vpm = v_pm * v_im_o, ivpm; + vpm.Inverse(ivpm); + Set(*input->location, ivpm); + } + break; + } + } +} +void Shader::SetPreviousTransformInputs(const Matrix4 &v_pm, const Matrix4 &v_im, const Matrix4 *i_m, uint count) +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryPreviousTransform].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryPreviousTransform][n]; + + switch (input->semantic) + { + case Core::ShaderInput::PreviousModelViewMatrix: + if (Matrix4 *mv_m = (Matrix4 *)alloca(sizeof(Matrix4) * count)) + { + for (uint n = 0; n < count; ++n) + mv_m[n] = v_im * i_m[n]; + Set(*input->location, mv_m, count); + } + break; + + case Core::ShaderInput::PreviousModelViewProjectionMatrix: + if (Matrix4 *mvp_m = (Matrix4 *)alloca(sizeof(Matrix4) * count)) + { + for (uint n = 0; n < count; ++n) + mvp_m[n] = v_pm * (v_im * i_m[n]); + Set(*input->location, mvp_m, count); + } + break; + } + } +} +void Shader::SetMaterialOpacityInputs(Material &m, float opacity) +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryMaterialOpacity].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryMaterialOpacity][n]; + + switch (input->semantic) + { + case Core::ShaderInput::MaterialOpacity: + Set(*input->location, m.opacity * opacity); + break; + } + } +} +void Shader::SetMaterialInputs(Material &m) +{ + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryMaterial].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryMaterial][n]; + + switch (input->semantic) + { + case Core::ShaderInput::MaterialDiffuse: + Set(*input->location, &m.diffuse.x, 4); + break; + case Core::ShaderInput::MaterialSpecular: + Set(*input->location, &m.specular.x, 4); + break; + case Core::ShaderInput::MaterialAmbient: + Set(*input->location, &m.ambient.x, 4); + break; + case Core::ShaderInput::MaterialSelf: + Set(*input->location, &m.self.x, 4); + break; + case Core::ShaderInput::MaterialGlossiness: + Set(*input->location, m.glossiness); + break; + case Core::ShaderInput::MaterialReflection: + Set(*input->location, m.reflection); + break; + case Core::ShaderInput::MaterialAlphaThreshold: + Set(*input->location, m.athreshold); + break; + case Core::ShaderInput::MaterialDepthBias: + Set(*input->location, m.depth_bias); + break; + + case Core::ShaderInput::MaterialTexture0: + case Core::ShaderInput::MaterialTexture1: + case Core::ShaderInput::MaterialTexture2: + case Core::ShaderInput::MaterialTexture3: + case Core::ShaderInput::MaterialTexture4: + case Core::ShaderInput::MaterialTexture5: + case Core::ShaderInput::MaterialTexture6: + case Core::ShaderInput::MaterialTexture7: + if (Render::Texture *t = m.texture_table[input->semantic - Core::ShaderInput::MaterialTexture0]) + Set(*input->location, *t, input->index); + break; + } + } +} +void Shader::SetLightInputs(Renderer &r, Core::Camera &view_item, Core::Light &l) +{ + float k_clip_fade = 1.f; + + if (l.range > 0.f) // [EJ] fade on last 10% of clip range + { + float c = l.clip_distance + l.range; + float d = Vector4::Dist(view_item.GetMatrix().GetRow(3), l.GetMatrix().GetRow(3)); + + k_clip_fade = 1.f - GS::Types::Clamp((d - c * 0.9f) / (c * 0.1f)); + } + + if (Core::Light::RenderData *light_render_data = (Core::Light::RenderData *)l.render_data.c_ptr()) + for (uint n = 0; n < input_list[Core::ShaderInput::CategoryLight].GetCount(); ++n) + { + ShaderInput *input = &input_list[Core::ShaderInput::CategoryLight][n]; + + switch (input->semantic) + { + case Core::ShaderInput::LightRange: + Set(*input->location, l.range); + break; + case Core::ShaderInput::LightSpotEdge: + Set(*input->location, Math::Cos(l.edge_angle + l.cone_angle)); + break; + case Core::ShaderInput::LightSpotCone: + Set(*input->location, Math::Cos(l.cone_angle)); + break; + case Core::ShaderInput::LightShadowBias: + Set(*input->location, l.shadow_bias); + break; + + case Core::ShaderInput::LightDiffuseColor: + { + Color c = l.diffuse_color * l.diffuse_intensity * k_clip_fade; + Set(*input->location, &c.x, 3); + } + break; + + case Core::ShaderInput::LightSpecularColor: + { + Color c = l.specular_color * l.specular_intensity * k_clip_fade; + Set(*input->location, &c.x, 3); + } + break; + + case Core::ShaderInput::LightShadowColor: + Set(*input->location, &l.shadow_color.x, 3); + break; + + case Core::ShaderInput::LightViewPosition: + { + Vector4 p = l.GetMatrix().GetRow(3) * view_item.GetInverseMatrix(); + Set(*input->location, &p.x, 3); + } + break; + + case Core::ShaderInput::LightViewDirection: + { + Vector4 d = l.GetMatrix().GetRow(2) * Matrix3::FromMatrix4(view_item.GetMatrix()).Normalized().Transposed(); + Set(*input->location, &d.x, 3); + } + break; + + case Core::ShaderInput::LightShadowMatrix0: + case Core::ShaderInput::LightShadowMatrix1: + case Core::ShaderInput::LightShadowMatrix2: + case Core::ShaderInput::LightShadowMatrix3: + case Core::ShaderInput::LightShadowMatrix4: + case Core::ShaderInput::LightShadowMatrix5: + { + uint n = input->semantic - Core::ShaderInput::LightShadowMatrix0; + if (n < light_render_data->shadow_data.GetCount()) + Set(*input->location, light_render_data->shadow_data[n].pmatrix * (light_render_data->shadow_data[n].imatrix * view_item.GetMatrix())); + } + break; + + case Core::ShaderInput::InverseShadowMapSize: + { + float k = r.pcf_radius / r.gpu_config.shadow_size; + Set(*input->location, k); + } + break; + + case Core::ShaderInput::LightShadowMap0: + case Core::ShaderInput::LightShadowMap1: + case Core::ShaderInput::LightShadowMap2: + case Core::ShaderInput::LightShadowMap3: + case Core::ShaderInput::LightShadowMap4: + case Core::ShaderInput::LightShadowMap5: + Set(*input->location, *r.shadow_map, input->index); + break; + + case Core::ShaderInput::LightPSSMSliceDistance0: + case Core::ShaderInput::LightPSSMSliceDistance1: + case Core::ShaderInput::LightPSSMSliceDistance2: + case Core::ShaderInput::LightPSSMSliceDistance3: + if (light_render_data->shadow_data) + Set(*input->location, light_render_data->shadow_data[input->semantic - Core::ShaderInput::LightPSSMSliceDistance0].slice_distance); + break; + + case Core::ShaderInput::ViewToLightMatrix: + Set(*input->location, l.GetInverseMatrix() * view_item.GetMatrix()); + break; + + case Core::ShaderInput::LightProjectionMap: + if (light_render_data->projection_texture.IsValid()) + Set(*input->location, *light_render_data->projection_texture, input->index); + break; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Shader::GetSemanticInputList(Core::ShaderInput::Semantic semantic) +{ + return Core::ShaderInput::semantic_desc[semantic].category; +} +ShaderInput *Shader::GetInput(Core::ShaderInput::Semantic semantic) const +{ + uint cat = GetSemanticInputList(semantic); + for (uint n = 0; n < input_list[cat].GetCount(); ++n) + if (input_list[cat][n].semantic == semantic) + return &input_list[cat][n]; + return NULL; +} +ShaderInput *Shader::GetInput(const char *n) const +{ + String name(n); + for (uint l = 0; l < Core::ShaderInput::CategoryLast; ++l) // need to check all categories here + for (uint n = 0; n < input_list[l].GetCount(); ++n) + if (!input_list[l][n].name.IsEmpty() && (input_list[l][n].name == name)) + return &input_list[l][n]; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Shader::Create(Render::ResourceFactory &rf, const Core::Shader &shader) +{ + Free(); + + __RASSERT_MSG__(renderer.shader_compiler != NULL, String::Format("No shader compiler available for this renderer ('%s').", renderer.GetName())); + + if (!renderer.shader_compiler->Compile(shader, *this)) + return false; + + // Solve uniforms and attributes. + Array > locations(shader.input_list.GetCount()); + + uint solved_count[Core::ShaderInput::CategoryLast], n = 0; + Memory::Set(solved_count, 0, sizeof(uint) * Core::ShaderInput::CategoryLast); + ListForeachPtr(Core::ShaderInput *, input, shader.input_list) + { + uint input_index = GetSemanticInputList(input->semantic); + + locations[n] = NewGPUShaderLocation(); + if (GetLocation(input->name, *locations[n], input->type)) + solved_count[input_index]++; + else + locations[n] = NULL; + + ++n; + } + + uint texture_count = 0; + for (uint l = 0; l < Core::ShaderInput::CategoryLast; ++l) + { + uint n = 0, i = 0; + + if (input_list[l].Allocate(solved_count[l])) + ListForeachPtr(Core::ShaderInput *, input, shader.input_list) + { + if ((l != GetSemanticInputList(input->semantic)) || locations[i].IsNull()) + { + ++i; + continue; + } + + ShaderInput *gpu_input = &input_list[l][n]; + gpu_input->location = locations[i].Detach(); + gpu_input->Set(input); + + // Allocate texture unit index and load render resource. + if (input->type == Core::ShaderInput::Uniform) + if (input->ConsumesTextureUnit()) + { + if (!input->parm_t.IsEmpty()) + gpu_input->parm_t = rf.LoadTexture(input->parm_t); + gpu_input->index = texture_count++; + } + + ++i; ++n; + } + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_shader_compiler.cpp b/include/engine/gpu/gpu_shader_compiler.cpp new file mode 100644 index 0000000..5522570 --- /dev/null +++ b/include/engine/gpu/gpu_shader_compiler.cpp @@ -0,0 +1,65 @@ +/* ----------------------------------------------------------------------------- + nEngine - GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_shader_compiler.h" + #include "gpu/gpu_renderer.h" + #include "log/file_log.h" + #include "log/log.h" + + using namespace GS; + using namespace GPU; + + +//------------------------------------------------------------------------------ +bool IShaderCompiler::Compile(const Core::Shader &shader, Shader &gpu_shader, const char *binary_cache_id) +{ + if (!shader.name.IsEmpty()) + __LOG_V__ << "Creating shader '" << shader.name << "'...\n"; + gpu_shader.name = shader.name; + + // Compile shader objects. + String vertex_source, pixel_source; + if (!renderer.TranslateShader(shader, vertex_source, pixel_source)) + return false; + + gpu_shader.vertex = renderer.NewGPUShaderObject(); + gpu_shader.pixel = renderer.NewGPUShaderObject(); + if (gpu_shader.vertex.IsNull() || gpu_shader.pixel.IsNull()) + return false; + + String vertex_error, pixel_error; + if ( + !CompileObject(vertex_source, *gpu_shader.vertex, ShaderObject::Vertex, shader.name, &vertex_error) || + !CompileObject(pixel_source, *gpu_shader.pixel, ShaderObject::Pixel, shader.name, &pixel_error) + ) + { + __LOG_E__ << "Shader '" << shader.name << "' failed to compile.\n"; + +//#ifdef _DEBUG + FileLog file_log("c:/shader_error.log"); + file_log << "--------------------------------------------------------------------------------\n"; + file_log << "Failed to compile shader '" << shader.name << "'.\n\n"; + file_log << "Vertex error:" << vertex_error << "\n\n"; + file_log << "Pixel error:" << pixel_error << "\n\n"; + file_log << "--------------------------------------------------------------------------------\n"; + file_log << "\n"; + file_log << "VERTEX:\n"; + file_log << "\n"; + file_log << vertex_source.NormalizedEOL(String::EOLUnix); + file_log << "\n"; + file_log << "PIXEL:\n"; + file_log << "\n"; + file_log << pixel_source.NormalizedEOL(String::EOLUnix); + file_log << "\n"; + file_log << "--------------------------------------------------------------------------------\n"; + file_log << "\n"; +//#endif + return false; + } + + return Link(shader, gpu_shader); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_shadow_map.cpp b/include/engine/gpu/gpu_shadow_map.cpp new file mode 100644 index 0000000..39d3139 --- /dev/null +++ b/include/engine/gpu/gpu_shadow_map.cpp @@ -0,0 +1,376 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "gpu/gpu_renderer.h" + #include "core/light.h" + #include "log/log.h" + + using namespace GS::Core; + using namespace GS::GPU; + + +struct UVOffset +{ float x, y; }; + +//------------------------------------------------------------------------------ +void Renderer::CreateShadowMaps() +{ + gpu_config.enable_shadow = registry.GetBool("ShadowMapping:Enable", true); + gpu_config.shadow_size = registry.GetInteger("ShadowMapping:Size", 1024); + + __LOG__ << "Creating shadow maps (" << gpu_config.shadow_size << "x" << gpu_config.shadow_size << ").\n"; + + if (gpu_config.enable_shadow) + { + shadow_map = NewTexture("shadow_map"); + shadow_map->Create(NULL, gpu_config.shadow_size, gpu_config.shadow_size, Render::Texture::FormatDepth, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + shadow_map->ConfigureAsShadowMap(); + + shadow_map_fbo->SetDepthTexture(shadow_map); + } +} +void Renderer::FreeShadowMaps() +{ + shadow_map = NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +struct ShadowRenderData : public Light::RenderData::ShadowRenderData +{ + Renderer::ShadowMapSplit split; +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static float ComputeSplitZBoundary(const Camera &lod_view, const Light &light, int index, int count) +{ + if (index <= 0) + return lod_view.GetNearClippingPlane(); + + float k = float(index) / count; + + float z_log = lod_view.GetNearClippingPlane() * powf(light.shadow_range / lod_view.GetNearClippingPlane(), k); + float z_lin = lod_view.GetNearClippingPlane() + (light.shadow_range - lod_view.GetNearClippingPlane()) * k; + + return z_log * light.shadow_distribution + z_lin * (1.f - light.shadow_distribution); +} +static void FitViewToFrustum(Camera &view, const GS::Frustum &slice, float d) +{ + using namespace GS; + + /* + Compute split view item properties so that the split view frustum act as + a perfect fit for the split frustum. + */ + const Vector4 *fv = slice.GetVertices(); + + Vector4 vfv[8]; + view.GetInverseMatrix().Apply(vfv, fv, 8); + const Matrix4 &m = view.GetMatrix(); + + Vector4 mm[2]; + mm[0] = mm[1] = vfv[0]; + for (int n = 1; n < 8; ++n) + { + mm[0] = Vector4::Minimum(mm[0], vfv[n]); + mm[1] = Vector4::Maximum(mm[1], vfv[n]); + } + Vector4 focus = ((mm[0] + mm[1]) * 0.5) * m; + + // Position the shadow map light item, + view.SetPosition(focus - m.GetRow(2) * d); + + // View clipping planes. + Vector4 view_front = m.GetRow(2); + view.z_far = view_front.Dot(fv[0] - view.GetPosition()); + for (int n = 1; n < 8; ++n) + view.z_far = GS::Types::Max(view.z_far, view_front.Dot(fv[n] - view.GetPosition())); + + // View dimensions. + Vector4 view_left = view.GetMatrix().GetRow(0), + view_top = view.GetMatrix().GetRow(1); + + Vector4 dt = fv[0] - view.GetPosition(); + float h_width = std::fabs(view_left.Dot(dt)), + h_height = std::fabs(view_top.Dot(dt)); + + for (int n = 1; n < 8; ++n) + { + dt = fv[n] - view.GetPosition(); + h_width = GS::Types::Max (h_width, std::fabs(view_left.Dot(dt))); + h_height = GS::Types::Max (h_height, std::fabs(view_top.Dot(dt))); + } + view.ortho_w = h_width * 2.f; + view.ortho_h = h_height * 2.f; +} +bool Renderer::LightPreparePSSM(const Light &l, bool build_dlist) const +{ + Light::RenderData *light_render_data = (Light::RenderData *)l.render_data.c_ptr(); + if (!light_render_data || !light_render_data->shadow_data.Allocate(4)) + return false; + + int split_count = registry.GetInteger("ShadowMapping:PSSM:Split", 3); + + for (int n = 0; n < split_count; ++n) + { + Light::RenderData::ShadowData &data = light_render_data->shadow_data[n]; + + if (data.render_data.IsNull()) + data.render_data = new ShadowRenderData; + ShadowRenderData *pssm_data = (ShadowRenderData *)data.render_data.c_ptr(); + + ShadowMapSplit &split = pssm_data->split; + + static UVOffset split_offset[] = { { 0.0, 0.0 }, { 0.5, 0.0 }, { 0.0, 0.5 }, { 0.5, 0.5 } }; + split.rect = fRect::FromWidthHeight(split_offset[n].x * gpu_config.shadow_size, split_offset[n].y * gpu_config.shadow_size, gpu_config.shadow_size / 2.f, gpu_config.shadow_size / 2.f); + + // Compute frustum slice. + Frustum slice; + float znear = ComputeSplitZBoundary(*view_item, l, n, split_count), zfar = ComputeSplitZBoundary(*view_item, l, n + 1, split_count); + view_item->ComputeFrustum(slice, GetViewport(), znear, zfar); + + // Adjust view item. + split.view.is_orthographic = true; + split.view.aspect_ratio = 1; + split.view.SnapshotTransformation(l.GetMatrix()); + + FitViewToFrustum(split.view, slice, l.shadow_range * 4.f); + split.view.ComputeFrustum(split.view.frustum, split.rect); + + // Cull. + if (build_dlist) + { + BuildRenderablePrimitiveList(split.view, *view_item, split.list.primitive_list, Renderable::Context_Shadow); + BuildDisplayLists(split.list.primitive_list, split.list.display_lists); + } + + // Store slice view to light matrix. + data.slice_distance = zfar; + data.imatrix = split.view.GetInverseMatrix(); + split.view.ComputeProjectionMatrix(split.rect, data.pmatrix); + if (!gpu_config.tex_origin_is_top_left) + data.pmatrix = Matrix4::ScaleMatrix(Vector4(1.0, -1.0, 1.0)) * data.pmatrix; + data.pmatrix = Matrix4::ScaleMatrix(Vector4(0.5, 0.5, 0.5)) * Matrix4::TranslationMatrix(Vector4(1, 1, 1)) * data.pmatrix; + + // Crop on PSSM region. + data.pmatrix = Matrix4::TranslationMatrix(Vector4(split_offset[n].x, split_offset[n].y, 0.0)) * Matrix4::ScaleMatrix(Vector4(0.5, 0.5, 1.0)) * data.pmatrix; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::LightRenderPSSM(Light &l) +{ + Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr(); + ViewConfig view = BackupView(); + + SetViewport(fRect(0, 0, (float)gpu_config.shadow_size, (float)gpu_config.shadow_size)); + Clear(0, 0, 0, 0, 1, ClearDepth); + + int split_count = registry.GetInteger("ShadowMapping:PSSM:Split", 3); + for (int n = 0; n < split_count; ++n) + { + ShadowRenderData *shd_data = (ShadowRenderData *)data->shadow_data[n].render_data.c_ptr(); + + SetViewport(shd_data->split.rect); + SetClippingRect(&shd_data->split.rect); + + DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::Depth); + + view_item = &shd_data->split.view; + ApplyCamera(); + DrawList(shd_data->split.list.display_lists[0], dc); + DrawList(shd_data->split.list.display_lists[2], dc); + shd_data->split.list.Clear(false); // limit dynamic allocations + } + RestoreView(view); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::LightPreparePSM(const Light &l, bool build_dlist) const +{ + Light::RenderData *light_render_data = (Light::RenderData *)l.render_data.c_ptr(); + if (!light_render_data || !light_render_data->shadow_data.Allocate(6)) + return false; + + for (uint n = 0; n < 6; ++n) + { + Light::RenderData::ShadowData &data = light_render_data->shadow_data[n]; + + if (data.render_data.IsNull()) + data.render_data = new ShadowRenderData; + ShadowRenderData *shd_data = (ShadowRenderData *)data.render_data.c_ptr(); + + ShadowMapSplit &split = shd_data->split; + + static Vector4 view_angle[6] = { Vector4(0, 0, 0), Vector4(0, Units::Deg(90.f), 0), Vector4(0, Units::Deg(180.f), 0), Vector4(0, Units::Deg(270.f), 0), Vector4(Units::Deg(90.f), 0, 0), Vector4(Units::Deg(270.f), 0, 0) }; + static UVOffset split_offset[] = { { 0, 0 }, { 0.33f, 0 }, { 0.66f, 0 }, { 0, 0.5f }, { 0.33f, 0.5f }, { 0.66f, 0.5f } }; + + split.view.aspect_ratio = 1; + split.view.SetFov(Units::Deg(95.f)); // Add a 5° safe area to avoid artifacts at transition. + split.view.SnapshotTransformation(l.GetMatrix() * Matrix4::FromMatrix3(Matrix3::FromEuler(view_angle[n]))); + + split.rect = fRect::FromWidthHeight(split_offset[n].x * gpu_config.shadow_size, split_offset[n].y * gpu_config.shadow_size, gpu_config.shadow_size / 3.f, gpu_config.shadow_size / 2.f); + + if (build_dlist) + { + BuildRenderablePrimitiveList(split.view, *view_item, split.list.primitive_list, Renderable::Context_Shadow); + BuildDisplayLists(split.list.primitive_list, split.list.display_lists); + } + + // Store cube view to light matrix. + data.imatrix = split.view.GetInverseMatrix(); + split.view.ComputeProjectionMatrix(split.rect, data.pmatrix); // FIXME watch out, do we need the split viewport (split.rect) or the complete viewport??? + if (!gpu_config.tex_origin_is_top_left) + data.pmatrix = Matrix4::ScaleMatrix(Vector4(1, -1, 1)) * data.pmatrix; + data.pmatrix = Matrix4::ScaleMatrix(Vector4(0.5f, 0.5f, 0.5f)) * Matrix4::TranslationMatrix(Vector4(1, 1, 1)) * data.pmatrix; + + // Crop on view region. + data.pmatrix = Matrix4::TranslationMatrix(Vector4(split_offset[n].x, split_offset[n].y, 0.f)) * Matrix4::ScaleMatrix(Vector4(0.33f, 0.5f, 1)) * data.pmatrix; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::LightRenderPSM(Light &l) +{ + Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr(); + ViewConfig view = BackupView(); + + SetViewport(fRect(0, 0, (float)gpu_config.shadow_size, (float)gpu_config.shadow_size)); + Clear(0, 0, 0, 0, 1, ClearDepth); + + for (uint n = 0; n < 6; ++n) + { + ShadowRenderData *psm_data = (ShadowRenderData *)data->shadow_data[n].render_data.c_ptr(); + + SetViewport(psm_data->split.rect); + SetClippingRect(&psm_data->split.rect); + + view_item = &psm_data->split.view; + ApplyCamera(); + + DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::Depth); + DrawList(psm_data->split.list.display_lists[0], dc); + DrawList(psm_data->split.list.display_lists[2], dc); + psm_data->split.list.Clear(false); // limit dynamic allocations + } + RestoreView(view); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::LightPrepareSSM(const Light &l, bool build_dlist) const +{ + Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr(); + if (!data || !data->shadow_data.Allocate(1)) + return false; + + if (data->shadow_data[0].render_data.IsNull()) + data->shadow_data[0].render_data = new ShadowRenderData; + ShadowRenderData *shd_data = (ShadowRenderData *)data->shadow_data[0].render_data.c_ptr(); + + Renderer::ShadowMapSplit &split = shd_data->split; + split.view.AlignTo(l); + + if (build_dlist) + { + BuildRenderablePrimitiveList(split.view, *view_item, split.list.primitive_list, Renderable::Context_Shadow); + BuildDisplayLists(split.list.primitive_list, split.list.display_lists); + } + + // Store shadow matrices. + data->shadow_data[0].imatrix = split.view.GetInverseMatrix(); + l.ComputeProjectionMatrix(data->shadow_data[0].pmatrix); + if (!gpu_config.tex_origin_is_top_left) + data->shadow_data[0].pmatrix = Matrix4::ScaleMatrix(Vector4(1.0, -1.0, 1.0)) * data->shadow_data[0].pmatrix; + data->shadow_data[0].pmatrix = Matrix4::ScaleMatrix(Vector4(0.5, 0.5, 0.5)) * Matrix4::TranslationMatrix(Vector4(1, 1, 1)) * data->shadow_data[0].pmatrix; + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::LightRenderSSM(Light &l) +{ + Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr(); + ViewConfig view = BackupView(); + + SetViewport(fRect(0, 0, (float)gpu_config.shadow_size, (float)gpu_config.shadow_size)); + Clear(0, 0, 0, 0, 1, ClearDepth); + + ShadowRenderData *render_data = (ShadowRenderData *)data->shadow_data[0].render_data.c_ptr(); + + view_item = &render_data->split.view; + ApplyCamera(); + + DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::Depth); + DrawList(render_data->split.list.display_lists[0], dc); + DrawList(render_data->split.list.display_lists[2], dc); + render_data->split.list.Clear(false); // limit dynamic allocations + + RestoreView(view); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Renderer::ViewConfig Renderer::BackupView() const +{ + return ViewConfig(view_item, viewport); +} +void Renderer::RestoreViewport(const ViewConfig &config) +{ + SetViewport(config.viewport); +} +void Renderer::RestoreView(const ViewConfig &config) +{ + RestoreViewport(config); + view_item = config.camera; + ApplyCamera(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::PrepareShadowMap(const Light &l, bool build_dlist) const +{ + switch (l.model) + { + case Light::Model_Spot: return LightPrepareSSM(l, build_dlist); + case Light::Model_Point: return LightPreparePSM(l, build_dlist); + case Light::Model_Linear: return LightPreparePSSM(l, build_dlist); + } + return false; +} +void Renderer::RenderShadowMap(Light &l) +{ + PerfBeginEvent(__FUNCTION__, Color::Blue); + + SetCurrentFBO(shadow_map_fbo); + SetCullFunc(CullBack); + + fRect old_clipping = GetClippingRect(); + SetClippingRect(NULL); + + switch (l.model) + { + case Light::Model_Spot: LightRenderSSM(l); break; + case Light::Model_Point: LightRenderPSM(l); break; + case Light::Model_Linear: LightRenderPSSM(l); break; + } + + SetClippingRect(&old_clipping); + + SetCullFunc(CullFront); + SetCurrentFBO(NULL); + + PerfEndEvent(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_skybox.cpp b/include/engine/gpu/gpu_skybox.cpp new file mode 100644 index 0000000..f74dbb6 --- /dev/null +++ b/include/engine/gpu/gpu_skybox.cpp @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "core/camera.h" + + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void Renderer::DrawSkybox(GS::Render::sTexture t[2], GS::Render::Shader *s) +{ + static const size_t stride = sizeof(float) * 3; + + SetDepthFunc(DepthEqual); // only draw on Z = 1 + EnableDepthWrite(false); + + Shader &p = s ? (Shader &)*s : *skybox_program; + + SetShaderProgram(&p); + SetIndexSource(skybox_idx_vbo); + SetVertexSource(skybox_vtx_vbo, stride); + + ShaderInput *vtx_parm = p.GetInput(Core::ShaderInput::Position), + *layer0_parm = p.GetInput("u_layer0"), + *layer1_parm = p.GetInput("u_layer1"); + + p.Set(*vtx_parm->location, 3, Types::ValueFloat, false, stride, (const void *)0); + if (layer0_parm && t[0].IsValid()) + p.Set(*layer0_parm->location, (Render::Texture &)*t[0], layer0_parm->index); + if (layer1_parm && t[1].IsValid()) + p.Set(*layer1_parm->location, (Render::Texture &)*t[1], layer1_parm->index); + + p.SetRendererInputs(*this); + p.SetTransformInputs(m_projection, m_view, m_iview, &Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + p.CommitInputs(); + + DrawElements(Types::PrimitiveTriangle, 3 * 2, Types::ValueUShort); + + p.Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL); + + EnableDepthWrite(true); + SetDepthFunc(DepthLess); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_spline.cpp b/include/engine/gpu/gpu_spline.cpp new file mode 100644 index 0000000..648401f --- /dev/null +++ b/include/engine/gpu/gpu_spline.cpp @@ -0,0 +1,539 @@ +#include "gpu/gpu_types.h" +#include "gpu/gpu_renderer.h" +#include "log/log.h" +#include "math/nmath.h" +#include "memory/memory.h" + +using namespace GS; +using namespace GS::GPU; + +//------------------------------------------------------------------------------ +Render::Texture *Renderer::CreateRenderTexture( + const char *name, + uint width, + uint height, + Render::Texture::Format format, + Render::Texture::AA aa +) +{ + __NTRACE("CreateRenderTexture") + // __LOG_W__ << "CreateRenderTexture: name=" << name << ", size=" << width << "x" << height << "\n"; + + Render::Texture *tex = NewTexture(name); + if (!tex) + { + __LOG_E__ << "CreateRenderTexture: NewTexture failed!\n"; + return nullptr; + } + // __LOG_W__ << "CreateRenderTexture: NewTexture succeeded, tex ptr=" << (void*)tex << "\n"; + + const Render::Texture::Usage usage = + Render::Texture::Usage( + Render::Texture::IsRenderTarget | + Render::Texture::IsShaderResource + ); + + // __LOG_W__ << "CreateRenderTexture: Calling tex->Create with format=" << format << ", aa=" << aa << "\n"; + if (tex->Create(nullptr, width, height, format, aa, usage)) + { + // __LOG_W__ << "CreateRenderTexture: Success! Returning texture.\n"; + return tex; + } + + __LOG_E__ << "CreateRenderTexture: tex->Create failed!\n"; + tex->Free(); + return nullptr; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::ClearTexture(Render::Texture *target, const Color &clear_color) +{ + __NTRACE("ClearTexture") + // __LOG_W__ << "ClearTexture: Clearing target texture with color (" << clear_color.x << ", " << clear_color.y << ", " << clear_color.z << ", " << clear_color.w << ")\n"; + + if (!target) + { + __LOG_E__ << "ClearTexture: target is null!\n"; + return; + } + + const uint tex_w = target->GetWidth(); + const uint tex_h = target->GetHeight(); + + // Use DrawSplineToTexture with clear_target=true to clear the texture + // This is a workaround since Blit() doesn't work on RenderTarget textures + // __LOG_W__ << "ClearTexture: Using DrawSplineToTexture method with clear...\n"; + + // Create a dummy 2-point array (not used since we're clearing) + Array dummy_points; + dummy_points.Allocate(2); + dummy_points[0] = Vector2(0, 0); + dummy_points[1] = Vector2(1, 1); + + // Call DrawSplineToTexture with clear_target=true and zero width (no drawing) + // This will fill the buffer with the clear color + const uint pitch = tex_w * 4; + const size_t buffer_size = pitch * tex_h; + unsigned char *pixels = new unsigned char[buffer_size]; + + // Convert color to 8-bit RGBA + const auto r = (unsigned char)(clear_color.x * 255.0f); + const auto g = (unsigned char)(clear_color.y * 255.0f); + const auto b = (unsigned char)(clear_color.z * 255.0f); + const auto a = (unsigned char)(clear_color.w * 255.0f); + + // __LOG_W__ << "ClearTexture: Filling buffer with RGBA(" << (int)r << ", " << (int)g << ", " << (int)b << ", " << (int)a << ")...\n"; + + // Fill with clear color (ABGR format) + unsigned int pixel_value = (a << 24) | (b << 16) | (g << 8) | r; + unsigned int *pixel_buffer = (unsigned int *)pixels; + for (uint i = 0; i < tex_w * tex_h; ++i) + { + pixel_buffer[i] = pixel_value; + } + + // __LOG_W__ << "ClearTexture: Uploading via Blit...\n"; + target->Blit((const char *)pixels, tex_w, tex_h, 0, 0, Render::Texture::FormatRGBA8); + + delete[] pixels; + + // __LOG_W__ << "ClearTexture: Complete!\n"; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::BlitTextureToTexture( + Render::Texture *src, + Render::Texture *dst, + const fRect *src_rect, + const fRect *dst_rect +) +{ + __NTRACE("BlitTextureToTexture") + + if (!src || !dst) + return; + + // Default rectangles (full texture) + const fRect src_r = src_rect ? *src_rect : fRect(0, 0, 1, 1); + const fRect dst_r = dst_rect ? *dst_rect : fRect(0, 0, 1, 1); + + // Save current state + const fRect old_viewport = viewport; + + // Setup FBO for destination + fx_fbo->SetColorTexture(dst); + fx_fbo->SetDepthTexture(nullptr); + SetCurrentFBO(fx_fbo); + SetViewport(fRect(0, 0, (float)dst->GetWidth(), (float)dst->GetHeight())); + + // Use existing RenderFullscreenQuad infrastructure + RenderFullscreenQuad(*single_texture_program, src_r, dst_r, src); + + // Restore state + SetCurrentFBO(nullptr); + SetViewport(old_viewport); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector2 Renderer::CatmullRomInterpolate( + const Vector2 &p0, + const Vector2 &p1, + const Vector2 &p2, + const Vector2 &p3, + float t +) const +{ + // Catmull-Rom spline with tau = 0.5 + const float t2 = t * t; + const float t3 = t2 * t; + + // Manual calculation for Vector2 + Vector2 result; + result.x = 0.5f * ( + (2.0f * p1.x) + + (-p0.x + p2.x) * t + + (2.0f * p0.x - 5.0f * p1.x + 4.0f * p2.x - p3.x) * t2 + + (-p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x) * t3 + ); + result.y = 0.5f * ( + (2.0f * p1.y) + + (-p0.y + p2.y) * t + + (2.0f * p0.y - 5.0f * p1.y + 4.0f * p2.y - p3.y) * t2 + + (-p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y) * t3 + ); + return result; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::TessellateSplineRibbon( + const Array &control_points, + float width_normalized, + const Color &color, + int samples_per_segment, + bool soft_edge, + SplineRibbon &out_ribbon +) +{ + __NTRACE("TessellateSplineRibbon") + + const int num_control = control_points.GetCount(); + if (num_control < 2) + return; + + // For Catmull-Rom: we have num_control-1 segments + const int num_segments = num_control - 1; + if (num_segments < 1) + return; + + // Allocate arrays for sampled points + const int total_samples = num_segments * samples_per_segment + 1; + Array samples; + Array tangents; + samples.Allocate(total_samples); + tangents.Allocate(total_samples); + + // Sample the spline using Catmull-Rom interpolation + int sample_idx = 0; + for (int seg = 0; seg < num_segments; seg++) + { + // Get 4 control points (with duplication at boundaries) + Vector2 p0 = (seg > 0) ? control_points[seg - 1] : control_points[seg]; + Vector2 p1 = control_points[seg]; + Vector2 p2 = control_points[seg + 1]; + Vector2 p3 = (seg < num_segments - 1) ? control_points[seg + 2] : control_points[seg + 1]; + + for (int s = 0; s < samples_per_segment; s++) + { + const float t = (float)s / (float)samples_per_segment; + samples[sample_idx] = CatmullRomInterpolate(p0, p1, p2, p3, t); + + // Compute tangent (derivative approximation) + const float dt = 0.01f; + const float t_next = (t + dt > 1.0f) ? 1.0f : t + dt; + Vector2 p_next = CatmullRomInterpolate(p0, p1, p2, p3, t_next); + Vector2 diff = p_next - samples[sample_idx]; + tangents[sample_idx] = diff.Normalized(); + + sample_idx++; + } + } + + // Add final point + samples[total_samples - 1] = control_points[num_control - 1]; + tangents[total_samples - 1] = tangents[total_samples - 2]; // Reuse last tangent + + // Build ribbon geometry + out_ribbon.positions.Allocate(total_samples * 2); + out_ribbon.colors.Allocate(total_samples * 2); + + for (int i = 0; i < total_samples; i++) + { + const Vector2 pos = samples[i]; + const Vector2 tangent = tangents[i]; + + // Perpendicular normal (2D rotation by 90 degrees) + Vector2 normal(-tangent.y, tangent.x); + + // Convert from normalized [0..1] texture space to clip space [-1..1] + const float x_clip = pos.x * 2.0f - 1.0f; + const float y_clip = 1.0f - pos.y * 2.0f; // Flip Y (texture origin top-left) + + // Offset in clip space + const Vector2 offset = normal * width_normalized; + + // Left and right vertices + out_ribbon.positions[i * 2 + 0] = Vector4( + x_clip - offset.x, + y_clip - offset.y, + 0.0f, + 1.0f + ); + out_ribbon.positions[i * 2 + 1] = Vector4( + x_clip + offset.x, + y_clip + offset.y, + 0.0f, + 1.0f + ); + + // Colors with soft edge via alpha gradient + if (soft_edge) + { + // Apply alpha gradient on outer edges (30% opacity) vs center (full opacity) + // But since we're using a ribbon with 2 vertices per sample, both get same alpha + // To get true soft edge, we'd need a center vertex too, but for now just use the color as-is + // TODO: Implement true soft edge with centerline vertex if needed + out_ribbon.colors[i * 2 + 0] = color; + out_ribbon.colors[i * 2 + 1] = color; + } + else + { + out_ribbon.colors[i * 2 + 0] = color; + out_ribbon.colors[i * 2 + 1] = color; + } + } + + // Build indices (triangle list) + const int num_quads = total_samples - 1; + out_ribbon.indices.Allocate(num_quads * 6); + + for (int i = 0; i < num_quads; i++) + { + const ushort i0 = (ushort)(i * 2); + const ushort i1 = (ushort)(i * 2 + 1); + const ushort i2 = (ushort)((i + 1) * 2); + const ushort i3 = (ushort)((i + 1) * 2 + 1); + + // Triangle 1 + out_ribbon.indices[i * 6 + 0] = i0; + out_ribbon.indices[i * 6 + 1] = i2; + out_ribbon.indices[i * 6 + 2] = i1; + + // Triangle 2 + out_ribbon.indices[i * 6 + 3] = i1; + out_ribbon.indices[i * 6 + 4] = i2; + out_ribbon.indices[i * 6 + 5] = i3; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Helper: Draw a simple line to texture pixel data (Bresenham-like) +static void DrawLineToPixels(unsigned char *pixels, uint width, uint height, uint pitch, + int x0, int y0, int x1, int y1, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + const int dx = abs(x1 - x0); + const int dy = abs(y1 - y0); + const int sx = (x0 < x1) ? 1 : -1; + const int sy = (y0 < y1) ? 1 : -1; + int err = dx - dy; + + int x = x0, y = y0; + while (true) + { + if (x >= 0 && x < (int)width && y >= 0 && y < (int)height) + { + int *pixel = (int*)(pixels + y * pitch + x * 4); + + // Read destination pixel components (packed as in existing code: ABGR) + const unsigned int dst = *pixel; + const unsigned char dst_r = (unsigned char)(dst & 0xFF); + const unsigned char dst_g = (unsigned char)((dst >> 8) & 0xFF); + const unsigned char dst_b = (unsigned char)((dst >> 16) & 0xFF); + const unsigned char dst_a = (unsigned char)((dst >> 24) & 0xFF); + + // Source alpha (0..1) + const float src_af = (float)a / 255.0f; + const float inv = 1.0f - src_af; + + // Standard 'over' compositing: out = src*src_a + dst*(1-src_a) + const unsigned char out_r = (unsigned char)(r * src_af + dst_r * inv + 0.5f); + const unsigned char out_g = (unsigned char)(g * src_af + dst_g * inv + 0.5f); + const unsigned char out_b = (unsigned char)(b * src_af + dst_b * inv + 0.5f); + const unsigned char out_a = (unsigned char)(a + dst_a * inv + 0.5f); + + *pixel = (out_a << 24) | (out_b << 16) | (out_g << 8) | out_r; // ABGR packing (kept as original) + } + + if (x == x1 && y == y1) break; + + const int e2 = 2 * err; + if (e2 > -dy) { err -= dy; x += sx; } + if (e2 < dx) { err += dx; y += sy; } + } +} + +void Renderer::DrawSplineToTexture( + Render::Texture *target, + const Array &control_points, + float width_pixels, + const Color &color, + int samples_per_segment, + bool clear_target, + bool soft_edge, + const Color *border_color, + float border_width, + float margin +) +{ + __NTRACE("DrawSplineToTexture") + // __LOG_W__ << "Drawing spline to texture (CPU-based method)...\n"; + + if (!target) { + __LOG_E__ << "DrawSplineToTexture: target texture is null!\n"; + return; + } + + if (control_points.GetCount() < 2) { + __LOG_E__ << "DrawSplineToTexture: not enough control points!\n"; + return; + } + + const uint tex_w = target->GetWidth(); + const uint tex_h = target->GetHeight(); + // __LOG_W__ << "Target texture size: " << tex_w << "x" << tex_h << "\n"; + + // Convert color to 8-bit RGBA + const auto r = (unsigned char)(color.x * 255.0f); + const auto g = (unsigned char)(color.y * 255.0f); + const auto b = (unsigned char)(color.z * 255.0f); + const auto a = (unsigned char)(color.w * 255.0f); + + // __LOG_W__ << "Color: R=" << (int)r << " G=" << (int)g << " B=" << (int)b << " A=" << (int)a << "\n"; + + // Convert border color if provided + unsigned char border_r = 0, border_g = 0, border_b = 0, border_a = 0; + if (border_color && border_width > 0.0f) { + border_r = (unsigned char)(border_color->x * 255.0f); + border_g = (unsigned char)(border_color->y * 255.0f); + border_b = (unsigned char)(border_color->z * 255.0f); + border_a = (unsigned char)(border_color->w * 255.0f); + // __LOG_W__ << "Border Color: R=" << (int)border_r << " G=" << (int)border_g << " B=" << (int)border_b << " A=" << (int)border_a << " Width=" << border_width << "\n"; + } + + const int num_control = control_points.GetCount(); + const int num_segments = num_control - 1; + + // Adjust control points with margin to avoid clipping + Array adjusted_points; + adjusted_points.Allocate(num_control); + + if (margin > 0.0f) { + // __LOG_W__ << "Applying margin: " << margin << "\n"; + + // Calculate the margin in normalized coordinates [0..1] + const float margin_x = margin / (float)tex_w; + const float margin_y = margin / (float)tex_h; + + // Scale and offset control points to fit within margin bounds + float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; + for (int i = 0; i < num_control; i++) { + if (control_points[i].x < min_x) min_x = control_points[i].x; + if (control_points[i].x > max_x) max_x = control_points[i].x; + if (control_points[i].y < min_y) min_y = control_points[i].y; + if (control_points[i].y > max_y) max_y = control_points[i].y; + } + + const float range_x = max_x - min_x; + const float range_y = max_y - min_y; + const float scale_x = (range_x > 0.0f) ? (1.0f - 2.0f * margin_x) / range_x : 1.0f; + const float scale_y = (range_y > 0.0f) ? (1.0f - 2.0f * margin_y) / range_y : 1.0f; + + for (int i = 0; i < num_control; i++) { + adjusted_points[i].x = margin_x + (control_points[i].x - min_x) * scale_x; + adjusted_points[i].y = margin_y + (control_points[i].y - min_y) * scale_y; + } + } else { + // No margin, use original points + for (int i = 0; i < num_control; i++) { + adjusted_points[i] = control_points[i]; + } + } + + Array samples; + samples.Allocate(num_segments * samples_per_segment + 1); + + // Sample the spline using Catmull-Rom interpolation with adjusted points + int sample_idx = 0; + for (int seg = 0; seg < num_segments; seg++) + { + Vector2 p0 = (seg > 0) ? adjusted_points[seg - 1] : adjusted_points[seg]; + Vector2 p1 = adjusted_points[seg]; + Vector2 p2 = adjusted_points[seg + 1]; + Vector2 p3 = (seg < num_segments - 1) ? adjusted_points[seg + 2] : adjusted_points[seg + 1]; + + for (int s = 0; s < samples_per_segment; s++) + { + const float t = (float)s / (float)samples_per_segment; + samples[sample_idx] = CatmullRomInterpolate(p0, p1, p2, p3, t); + sample_idx++; + } + } + samples[num_segments * samples_per_segment] = adjusted_points[num_control - 1]; + + // __LOG_W__ << "Generated " << samples.GetCount() << " sampled points\n"; + + // Create pixel buffer for drawing + // __LOG_W__ << "Creating pixel buffer for CPU rendering...\n"; + + const uint pitch = tex_w * 4; // RGBA = 4 bytes per pixel + const size_t buffer_size = pitch * tex_h; + unsigned char *pixels = new unsigned char[buffer_size]; + + // __LOG_W__ << "Pixel buffer created. Size=" << buffer_size << " Pitch=" << pitch << "\n"; + + if (clear_target) + { + // Initialize with transparent black + memset(pixels, 0, buffer_size); + } + else + { + // Read back the existing texture contents into the buffer so we can composite on top. + // __LOG_W__ << "Reading existing texture pixels into buffer (for compositing)...\n"; + + // Setup FBO for readback + fx_fbo->SetColorTexture(target); + fx_fbo->SetDepthTexture(nullptr); + SetCurrentFBO(fx_fbo); + + fx_fbo->ReadColorPixels((char*)pixels, 0, 0, tex_w, tex_h); + + // Restore + SetCurrentFBO(nullptr); + } + + // __LOG_W__ << "Drawing spline lines...\n"; + + // Draw border first (if specified) + if (border_color && border_width > 0.0f) { + // __LOG_W__ << "Drawing border with width: " << border_width << "\n"; + const float total_width = width_pixels + border_width * 2.0f; + + for (uint i = 0; i + 1 < samples.GetCount(); i++) + { + const int x0 = (int)(samples[i].x * (float)tex_w); + const int y0 = (int)(samples[i].y * (float)tex_h); + const int x1 = (int)(samples[i + 1].x * (float)tex_w); + const int y1 = (int)(samples[i + 1].y * (float)tex_h); + + for (int w = -(int)total_width/2; w <= (int)total_width/2; w++) + { + DrawLineToPixels(pixels, tex_w, tex_h, pitch, + x0 + w, y0, x1 + w, y1, border_r, border_g, border_b, border_a); + } + } + } + + // Draw main spline on top + for (uint i = 0; i + 1 < samples.GetCount(); i++) + { + // Convert from normalized [0..1] to pixel coordinates + const int x0 = (int)(samples[i].x * (float)tex_w); + const int y0 = (int)(samples[i].y * (float)tex_h); + const int x1 = (int)(samples[i + 1].x * (float)tex_w); + const int y1 = (int)(samples[i + 1].y * (float)tex_h); + + // Draw line with width by drawing multiple parallel lines + for (int w = -(int)width_pixels/2; w <= (int)width_pixels/2; w++) + { + DrawLineToPixels(pixels, tex_w, tex_h, pitch, + x0 + w, y0, x1 + w, y1, r, g, b, a); + } + } + + // __LOG_W__ << "Uploading pixel buffer to texture...\n"; + // Upload to texture using Blit + target->Blit((const char *)pixels, tex_w, tex_h, 0, 0, Render::Texture::FormatRGBA8); + + // __LOG_W__ << "Freeing pixel buffer...\n"; + delete[] pixels; + // __LOG_W__ << "Buffer freed!\n"; + + // __LOG_W__ << "DrawSplineToTexture complete!\n"; +} +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/include/engine/gpu/gpu_terrain.cpp b/include/engine/gpu/gpu_terrain.cpp new file mode 100644 index 0000000..78e20a5 --- /dev/null +++ b/include/engine/gpu/gpu_terrain.cpp @@ -0,0 +1,264 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "core/terrain.h" + #include "log/log.h" + + using namespace GS::GPU; + + // Terrain patch size. +#define _PatchSize 64 + // Terrain page count. +#if __PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__ + #define _PageCount 4 +#else + #define _PageCount 32 +#endif + + +//----------------------------------------------------------------------------- +bool Renderer::CreateTerrainPatch() +{ + // Allocate terrain cache. + if (!terrain_patch_cache.Allocate(_PageCount)) + __ERR__(__LOG_E__ << "Failed to allocate terrain cache.\n", false) + + // Compute page stride. + size_t stride = 0; + + size_t vertex_offset = stride; + stride += 3 * 4; // Vertex buffer (3x float). + size_t normal_offset = stride; + stride += (3 + 1) * 1; // Normal buffer (3x byte + 1 padding). + size_t uv_offset = stride; + stride += 2 * 4; // Large UV (2x float). + + // Setup default page layout. + size_t byte_size = stride * (_PatchSize + 1) * (_PatchSize + 1); + + __LOG_H__ << "Setup terrain cache: " << terrain_patch_cache.GetCount() << " pages (" << uint(byte_size * terrain_patch_cache.GetCount()) << " bytes).\n"; + + terrain_patch_vtx.Allocate((uint)byte_size); + if (char *p = terrain_patch_vtx) + { + Vector4 wp(0, 0, 0); + for (int v = 0; v < (_PatchSize + 1); ++v) + { + for (int u = 0; u < (_PatchSize + 1); ++u) + { + float *pv = (float *)p; + pv[0] = wp.x; pv[1] = 0; pv[2] = wp.z; + + p += stride; + wp.x += 1.f; + } + wp.x = 0.f; + wp.z += 1.f; + } + } + + // Allocate pages. + for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n) + { + DisplayList *patch = terrain_patch_cache[n].patch = NewDisplayList(); + + // Create the patch index buffer. + patch->idx = NewVBO(); + + if (patch->idx->Create(6 * _PatchSize * _PatchSize * sizeof(ushort), VBO::Index, VBO::Static)) + { + SetIndexSource(patch->idx); + if (ushort *p_idx = (ushort *)patch->idx->Map()) + { + for (int v = 0; v < _PatchSize; ++v) + for (int u = 0; u < _PatchSize; ++u) + { + *p_idx++ = (ushort)(u + v * (_PatchSize + 1)); + *p_idx++ = (ushort)(u + (v + 1) * (_PatchSize + 1) + 1); + *p_idx++ = (ushort)(u + v * (_PatchSize + 1) + 1); + *p_idx++ = (ushort)(u + v * (_PatchSize + 1)); + *p_idx++ = (ushort)(u + (v + 1) * (_PatchSize + 1)); + *p_idx++ = (ushort)(u + (v + 1) * (_PatchSize + 1) + 1); + } + + patch->idx->Unmap(); + patch->index_count = 6 * _PatchSize * _PatchSize; + } + SetIndexSource(NULL); + } + + // Create the patch vertex buffer. + patch->vertex_offset = vertex_offset; + patch->normal_offset = normal_offset; + patch->uv_offset[0] = uv_offset; + patch->stride = stride; + + patch->vtx = NewVBO(); + if (patch->vtx->Create(byte_size, VBO::Vertex, VBO::Dynamic)) + { + SetVertexSource(patch->vtx, patch->stride); + patch->vtx->Update(terrain_patch_vtx); + SetVertexSource(NULL, 0); + } + } + return true; +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +void Renderer::InvalidateTerrainCache(int, int, int, int) +{ + // Very naive invalidation that ignores the input region. + for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n) + terrain_patch_cache[n].terrain = NULL; +} +void Renderer::DecayTerrainCache() +{ + for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n) + if (terrain_patch_cache[n].score > 0) + --terrain_patch_cache[n].score; +} +void Renderer::UploadTerrainPatchToPage(CachedTerrainPatch &page, const GS::Core::Item &item, const GS::Core::Patch &patch, const DrawContext &dc) +{ + if (!patch.terrain || !page.patch) + return; + + Core::Terrain &terrain = *patch.terrain; + DisplayList &terrain_patch = *page.patch; + + float pixel_size = terrain.GetUnit(); + Vector4 patch_scale(pixel_size * patch.decimation, 1, pixel_size * patch.decimation); + +#if 1 + + // Update patch CPU-side data. + Core::Terrain::Attrib *psa = terrain.GetAttributesMap() + patch.v * terrain.GetHeightmapPitch() + patch.u; + float *psh = terrain.GetHeightmap() + patch.v * terrain.GetHeightmapPitch() + patch.u; + + char *p = terrain_patch_vtx; + + Vector4 uv(0, 0, patch.v * pixel_size); + for (int v = 0; v < (_PatchSize + 1); ++v) + { + uv.x = patch.u * pixel_size; + + Core::Terrain::Attrib *pa = psa; + float *ph = psh; + + for (int u = 0; u < (_PatchSize + 1); ++u) + { + // Vertex. + float *pv = (float *)(p + terrain_patch.vertex_offset); + pv[1] = ph[0]; + + // Normal. + char *pn = (char *)(p + terrain_patch.normal_offset); + pn[0] = pa[0].nx; + pn[1] = pa[0].ny; + pn[2] = pa[0].nz; + + // UV. + float *pu = (float *)(p + terrain_patch.uv_offset[0]); + pu[0] = uv.x / terrain.GetWidth(); + uv.x += patch_scale.x; + pu[1] = uv.z / terrain.GetDepth(); + + p += terrain_patch.stride; + + pa += patch.decimation; + ph += patch.decimation; + } + + uv.z += patch_scale.z; + + psa += terrain.GetHeightmapPitch() * patch.decimation; + psh += terrain.GetHeightmapPitch() * patch.decimation; + } + + // Update VBO. + SetVertexSource(terrain_patch.vtx, terrain_patch.stride); + terrain_patch.vtx->Update(terrain_patch_vtx); + + // [EJ 9 Mar] the display list cache MUST be reset here otherwise an invalid + // VBO reference will be used by the next draw calls for this patch. + dls_cache.dls = NULL; + +#endif + + // Synchronize cache. + page.terrain = patch.terrain; + page.u = patch.u; page.v = patch.v; + page.w = patch.w; page.h = patch.h; + page.decimation = patch.decimation; +} +void Renderer::RenderTerrainPatch(const GS::Core::Patch &patch, const GS::Core::Item &item, const DrawContext &dc) +{ + // Cache query. + ++gpu_stats.terrain_page_query_count; + + DisplayList *dlist = NULL; + CachedTerrainPatch *page = NULL; + uint lowest_score = (uint)~0; + + for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n) + if (CachedTerrainPatch *c_page = &terrain_patch_cache[n]) + { + if ( + (c_page->terrain == patch.terrain) && + (c_page->u == patch.u) && (c_page->v == patch.v) && + (c_page->w == patch.w) && (c_page->h == patch.h) && + (c_page->decimation == patch.decimation) + ) + { + dlist = c_page->patch; + c_page->score++; // Increase score. + break; + } + + // Track the lowest scoring page. + if (c_page->score <= lowest_score) + { + lowest_score = c_page->score; + page = c_page; + } + } + + // Cache miss. + if (!dlist) + { + ++gpu_stats.terrain_page_query_miss; + + if (!page || !page->patch) + __ERRRAW__(__LOG_E__ << "No page to upload terrain patch.\n") // Unexpected... + + // Create new page. + UploadTerrainPatchToPage(*page, item, patch, dc); + dlist = page->patch; + page->score = 1; // Reset score (+1 for being used). + } + + // Draw patch scaled and translated on the GPU. + float pixel_size = patch.terrain->GetUnit(); + Vector4 patch_scale(pixel_size * patch.decimation, 1, pixel_size * patch.decimation); + + Matrix4 patch_matrix = + Matrix4::TranslationMatrix(Vector4(patch.u * pixel_size - patch.terrain->GetWidth() * 0.5f, 0, patch.v * pixel_size - patch.terrain->GetDepth() * 0.5f)) * + Matrix4::ScaleMatrix(patch_scale); + + SetWorldMatrix(item.GetMatrix() * patch_matrix); + m_previous_world = item.GetPreviousMatrix() * patch_matrix; + + dls_cache.item = NULL; // Force matrices upload to program. + + // Draw. + if (patch.terrain->render_data) + { + dlist->material = patch.terrain->render_data->material; + DrawDisplayListCached(*dlist, item, dc); + } +} +//----------------------------------------------------------------------------- diff --git a/include/engine/gpu/gpu_triangle_batch.cpp b/include/engine/gpu/gpu_triangle_batch.cpp new file mode 100644 index 0000000..16c79a5 --- /dev/null +++ b/include/engine/gpu/gpu_triangle_batch.cpp @@ -0,0 +1,68 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_triangle_batch.h" + #include "gpu/gpu_renderer.h" + + using namespace GS; + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void TriangleBatch::Flush() +{ + if (batch_triangle_count > 0) + renderer.DrawTriangle(batch_triangle_count, batch_vtx, batch_idx, batch_col, batch_uv, batch_t, batch_blend_op, batch_render_word); + + batch_triangle_count = 0; + batch_attrib_offset = 0; +} +void TriangleBatch::DrawTriangle(uint triangle_count, uint attrib_count, const Vector4 *vtx, const ushort *idx, const Color *col, const Vector2 *uv, const Render::Texture *t, Core::Material::BlendOperator blend_op, Core::Material::RenderWord render_word) +{ + bool batch_broken = (batch_triangle_count == 0) || (batch_t != t) || (batch_blend_op != blend_op) || (batch_render_word != render_word); + + if (batch_triangle_count + triangle_count > batch_max_triangle_count) + batch_broken = true; + + if (batch_broken) + Flush(); + + // Transfer and fix-up indices. + for (uint n = 0; n < triangle_count; ++n) + { + batch_idx[batch_triangle_count * 3 + 0] = (ushort)(idx[n * 3 + 0] + batch_attrib_offset); + batch_idx[batch_triangle_count * 3 + 1] = (ushort)(idx[n * 3 + 1] + batch_attrib_offset); + batch_idx[batch_triangle_count * 3 + 2] = (ushort)(idx[n * 3 + 2] + batch_attrib_offset); + ++batch_triangle_count; + } + + // Transfer attributes. + Memory::Copy(&batch_vtx[batch_attrib_offset], vtx, sizeof(Vector4) * attrib_count); + Memory::Copy(&batch_col[batch_attrib_offset], col, sizeof(Color) * attrib_count); + Memory::Copy(&batch_uv[batch_attrib_offset], uv, sizeof(Vector2) * attrib_count); + batch_attrib_offset += attrib_count; + + batch_render_word = render_word; + batch_blend_op = blend_op; + batch_t = t; +} +//------------------------------------------------------------------------------ + +TriangleBatch::TriangleBatch(Renderer &r, uint max) : renderer(r) +{ + batch_t = NULL; + batch_render_word = Core::Material::Render_None; + batch_blend_op = Core::Material::Blend_None; + + batch_max_triangle_count = max; + batch_triangle_count = 0; + batch_attrib_offset = 0; + + batch_idx.Allocate(3 * batch_max_triangle_count); + batch_vtx.Allocate(3 * batch_max_triangle_count); + batch_col.Allocate(3 * batch_max_triangle_count); + batch_uv.Allocate(3 * batch_max_triangle_count); +} diff --git a/include/engine/gpu/gpu_video.cpp b/include/engine/gpu/gpu_video.cpp new file mode 100644 index 0000000..32b0d8a --- /dev/null +++ b/include/engine/gpu/gpu_video.cpp @@ -0,0 +1,328 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "gpu/gpu_renderer.h" + #include "log/log.h" + + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +Renderer::RenderTechnique Renderer::GetDefaultRenderTechnique() const +{ + String technique = registry.GetString("Technique", "Forward"); + + if (technique == "Deferred") + return TechniqueDeferred; + + return TechniqueForward; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::FreeRenderTechnique() +{ + for (uint n = 0; n < 4; ++n) + t_gbuffer[n] = NULL; + t_depth = NULL; + + t_color_aa = NULL; + t_depth_aa = NULL; +} +void Renderer::SetRenderTechnique(RenderTechnique p) +{ + if (p == TechniqueDefault) + p = GetDefaultRenderTechnique(); + + // Filter out illegal configurations. + if (!gpu_config.use_rtt && (p == TechniqueDeferred)) + p = TechniqueForward; + + FreeRenderTechnique(); + render_technique = p; + + // Select AA method. + Render::Texture::AA aa = Render::Texture::NoAA; + + if ((p == TechniqueForward) && gpu_config.can_resolve_msaa) + if (registry.GetBool("Antialiasing:Enable", false)) + { + float sample = registry.GetReal("Antialiasing:Sample", 4.0); + + if (sample > 8.f) aa = Render::Texture::MSAA16x; + else if (sample > 4.f) aa = Render::Texture::MSAA8x; + else if (sample > 2.f) aa = Render::Texture::MSAA4x; + else if (sample > 1.f) aa = Render::Texture::MSAA2x; + } + + gpu_config.enable_aa = asbool(aa != Render::Texture::NoAA); + + // Setup technique objects. + __LOG__ << "SetRenderTechnique(): " << dimensions.x << "x" << dimensions.y << "\n"; + + bool use_float = registry.GetBool("Texture:Float:Enable", false); + Render::Texture::Format t_format = use_float ? Render::Texture::FormatRGBAF : Render::Texture::FormatRGBA8; + + for (uint n = 0; n < 2; ++n) + { + t_compose[n] = NewTexture(String("t_compose") << n); + t_compose[n]->Create(NULL, dimensions.x, dimensions.y, t_format, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + t_compose[n]->SetFiltering(Render::TextureParm::FilterTrilinear); + t_compose[n]->SetWrapping(Render::TextureParm::WrapClamp, Render::TextureParm::WrapClamp); + } + + switch (p) + { + case TechniqueForward: + { + if (gpu_config.can_resolve_msaa) + { + t_color_aa = NewTexture("t_color_aa"); + t_color_aa->Create(NULL, dimensions.x, dimensions.y, t_format, aa, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + t_depth_aa = NewTexture("t_depth_aa"); + t_depth_aa->Create(NULL, dimensions.x, dimensions.y, Render::Texture::FormatDepth, aa, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + + buffer_fbo->SetColorTexture(t_color_aa); + buffer_fbo->SetDepthTexture(t_depth_aa); + } + + if (gpu_config.use_rtt) + { + t_depth = NewTexture("t_depth"); + t_depth->Create(NULL, dimensions.x, dimensions.y, Render::Texture::FormatDepth, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + + resolve_fbo->SetColorTexture(t_compose[0]); + resolve_fbo->SetDepthTexture(t_depth); + } + } + break; + + case TechniqueDeferred: + { + for (uint n = 0; n < 4; ++n) + { + t_gbuffer[n] = NewTexture(String("t_gbuffer") << n); + t_gbuffer[n]->Create(NULL, dimensions.x, dimensions.y, Render::Texture::FormatRGBAF, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + t_gbuffer[n]->SetFiltering(Render::TextureParm::FilterNearest); + } + t_depth = NewTexture("t_depth"); + t_depth->Create(NULL, dimensions.x, dimensions.y, Render::Texture::FormatDepth, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + + Render::Texture *rt[4] = { t_gbuffer[0], t_gbuffer[1], t_gbuffer[2], t_gbuffer[3] }; + + buffer_fbo->SetColorTexture(rt, 4); + buffer_fbo->SetDepthTexture(t_depth); + + resolve_fbo->SetColorTexture(t_compose[0]); + resolve_fbo->SetDepthTexture(t_depth); + } + break; + } + + SetPostProcess(); +} +void Renderer::SetPostProcess(uint k) +{ + if (!gpu_config.use_rtt) + return; + + if (k == 0) + k = registry.GetInteger("PostProcess:FX:Scale", 4); + + for (uint n = 0; n < 3; ++n) + { + t_fx[n] = NewTexture(String("t_fx") << n); + t_fx[n]->Create(NULL, dimensions.x / k, dimensions.y / k, Render::Texture::FormatRGBAF, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + t_fx[n]->SetFiltering(Render::TextureParm::FilterBilinear); + t_fx[n]->SetWrapping(Render::TextureParm::WrapClamp, Render::TextureParm::WrapClamp); + } + + t_fx_depth = NewTexture("t_fx_depth"); + t_fx_depth->Create(NULL, dimensions.x / k, dimensions.y / k, Render::Texture::FormatDepth, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + t_fx_depth->SetFiltering(Render::TextureParm::FilterNearest); + t_fx_depth->SetWrapping(Render::TextureParm::WrapClamp, Render::TextureParm::WrapClamp); + + fx_scale = k; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::SetupCoreResources(bool support_3d) +{ + // Core shaders & objects. + if (!LoadCoreShaders(support_3d)) + return false; + + resolve_fbo = NewFBO(); + resolve_fbo->Create(); + + if (support_3d) + { + buffer_fbo = NewFBO(); + buffer_fbo->Create(); + fx_fbo = NewFBO(); + fx_fbo->Create(); + + // Shadow mapping objects. + if (gpu_config.enable_shadow) + { + shadow_map_fbo = NewFBO(); + shadow_map_fbo->Create(); + CreateShadowMaps(); + } + + // Default technique. + SetRenderTechnique(); + + if (!CreateTerrainPatch()) + return false; + + t_noise = core_resource_factory->LoadTexture("@core/noise.tga"); + } + + { + static const ushort idx[] = { 2, 1, 0, 3, 2, 0 }; + static const float vtx[] = { -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1 }; + + skybox_idx_vbo = NewVBO(); + skybox_idx_vbo->Create(idx, sizeof(ushort) * 6, VBO::Index); + skybox_vtx_vbo = NewVBO(); + skybox_vtx_vbo->Create(vtx, sizeof(float) * 3 * 4, VBO::Vertex); + + helper_idx_vbo = NewVBO(); + helper_idx_vbo->Create(idx, sizeof(ushort) * 6, VBO::Index); + helper_vtx_vbo = NewVBO(); + helper_vtx_vbo->Create(sizeof(float) * 256, VBO::Vertex, VBO::Dynamic); // 1Kb WARNING watch out for possible overflow when updating this buffer! + + ushort box_idx[] = + { + 0, 1, 2, 0, 2, 3, 1, 5, 6, 1, 6, 2, + 5, 4, 7, 5, 7, 6, 4, 0, 3, 4, 3, 7, + 4, 5, 1, 4, 1, 0, 3, 2, 6, 3, 6, 7 + }; + box_idx_vbo = NewVBO(); + box_idx_vbo->Create(box_idx, sizeof(ushort) * 3 * 4 * 3, VBO::Index); + + direct_idx_vbo = NewVBO(); + direct_vtx_vbo = NewVBO(); + } + return true; +} +void Renderer::SetDefaultStates() +{ + // Set defaults states. + EnableDepthTest(true); + SetDepthFunc(DepthLess); + EnableCulling(true); + SetCullFunc(CullFront); + EnableBlending(false); + SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Renderer::DiscoverGPUConfiguration() +{ + Variant v; + if (QueryCaps(CanBlitRBO, v)) + gpu_config.can_resolve_msaa = v.b_value; + if (QueryCaps(MaxAnisotropy, v)) + gpu_config.max_anisotropy = v.i_value; + if (QueryCaps(TextureTopLeftOrigin, v)) + gpu_config.tex_origin_is_top_left = v.b_value; + +#if __PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__ || __PLATFORM_EMSCRIPTEN__ + // Drop all advanced features... for now. + gpu_config.enable_shadow = false; + + gpu_config.can_resolve_msaa = false; + gpu_config.use_rtt = false; + + gpu_config.npot = RendererConfig::NPOT_Limited; +#endif + + if (!gpu_config.can_resolve_msaa) + __LOG_W__ << "Insufficient RBO support, falling back to RTT: No hardware MSAA.\n"; + if (!gpu_config.enable_shadow) + __LOG_W__ << "Shadow-mapping support disabled.\n"; + + if (gpu_config.npot == RendererConfig::NPOT_Limited) + __LOG_V__ << "NPOT limited support.\n"; + if (gpu_config.npot == RendererConfig::NPOT_Full) + __LOG_V__ << "NPOT full support.\n"; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Renderer::ResizeVideo(uint w, uint h) +{ + __LOG_V__ << "GPU Resize video to " << w << "x" << h << ".\n"; + + dimensions.Set(w, h); + SetRenderTechnique(render_technique); + return true; +} +bool Renderer::Open(uint w, uint h, char bpp, GS::Render::VideoMode mode, const void *sys_handle) +{ + if (!OpenPlatformVideo(w, h, bpp, mode, sys_handle)) + return false; + if (!InitializePlatform()) + return false; + + __LOG__ << "\n"; + __LOG_H__ << "GPU-based (" << GetName() << ") on adapter " << stats.adapter << " (vendor: " << stats.vendor << ").\n"; + __LOG__ << "\n"; + + DiscoverGPUConfiguration(); + + dimensions.Set(w, h); + SetViewport(fRect(0, 0, (float)w, (float)h)); + return true; +} +void Renderer::Free() +{ + __LOG_FUNC__ + + terrain_patch_cache.Free(); + + FreeRenderTechnique(); + + helper_idx_vbo = NULL; + helper_vtx_vbo = NULL; + + skybox_idx_vbo = NULL; + skybox_vtx_vbo = NULL; + + direct_idx_vbo = NULL; + direct_vtx_vbo = NULL; + + box_idx_vbo = NULL; + + buffer_fbo = NULL; + resolve_fbo = NULL; + fx_fbo = NULL; + + for (uint n = 0; n < 2; ++n) + t_compose[n] = NULL; + + for (uint n = 0; n < 3; ++n) + t_fx[n] = NULL; + t_fx_depth = NULL; + fx_scale = 0; + + t_noise = NULL; + + FreeShadowMaps(); + shadow_map_fbo = NULL; + + UnloadCoreShaders(); +} +void Renderer::Close() +{ + Free(); + ClosePlatformVideo(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/gpu/gpu_writer.cpp b/include/engine/gpu/gpu_writer.cpp new file mode 100644 index 0000000..dd59f5c --- /dev/null +++ b/include/engine/gpu/gpu_writer.cpp @@ -0,0 +1,154 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "gpu/gpu_renderer.h" + #include "gpu/gpu_triangle_batch.h" + #include "core/raster_font.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::GPU; + + +//------------------------------------------------------------------------------ +void Renderer::Write(const Render::RasterFont &f, const char *t, float &x, float &y, const WriterConfig &config, float s, const Color *c, WriterAlignment a, bool mirrored) +{ + Render::Texture *page = f.GetPage(0); + if (!page) + __ERRRAW__(__LOG_E__ << "No glyph page in raster font '" << f.name << "'.\n") + + float scale_width = s; + if(mirrored) + scale_width = -s; + + // Aspect ratio, texel/pixel mapping. + float ar = config.correct_ar ? viewport.GetHeight() / viewport.GetWidth() : 1.f; // w / h + + Vector2 glyph_mapping((float)page->GetWidth() / viewport.GetWidth(), (float)page->GetHeight() / viewport.GetHeight()), + pixel_mapping(1.f / viewport.GetWidth(), 1.f / viewport.GetHeight()); + + if (!config.normalized) + { + x *= pixel_mapping.x; + y *= pixel_mapping.y; + y = floor(y * viewport.GetHeight()) / viewport.GetHeight(); // Stay on a pixel boundary. + } + float in_x = x; + + Vector4 vtx[4]; + Vector2 uv[4]; + + Color col[4]; + for (uint n = 0; n < 4; ++n) + col[n] = c ? *c : Color(1, 1, 1, 1); + + // Draw glyphs. + Render::Texture *t_page = NULL; + bool aligned = false; + + TriangleBatch batch(*this); + + for ( ; t[0]; ++t) + { + // Catch line feed. + if (t[0] == '\n') + { + x = in_x; + if (config.normalized) + y += f.GetHeight() * s; + else + { + y += f.GetHeight() * glyph_mapping.y * s; + y = floor(y * viewport.GetHeight()) / viewport.GetHeight(); // Avoid float drift, stay on pixel boundary. + } + + aligned = false; + continue; + } + + // Compute alignment. + if (!aligned) + { + switch (a) + { + case AlignMiddle: + if (config.normalized) + x -= f.ComputeLineRect(t).x * scale_width * 0.5f * ar; + else x -= f.ComputeLineRect(t).x * scale_width * 0.5f * glyph_mapping.x; + break; + + case AlignRight: + if (config.normalized) + x -= f.ComputeLineRect(t).x * scale_width * ar; + else x -= f.ComputeLineRect(t).x * scale_width * glyph_mapping.x; + break; + + default: + break; + } + + // Make sure we stay as close as possible to a pixel boundary for non-normalized modes. + if (!config.normalized) + x = floor(x * viewport.GetWidth()) / viewport.GetWidth(); + + aligned = true; + } + + // Output glyph. + if (const Render::RasterFont::Glyph *glyph = f.GetGlyphInfos(t[0])) + { + if ((t_page = f.GetPage(glyph->page)) != NULL) + { + float _x, _y, _w, _h; + + if (config.normalized) + { + _x = x * 2.f - 1.f + glyph->offx * 1.f * scale_width; + _y = (1.f - y) * 2.f - 1.f - glyph->offy * 2.f * s; + _w = glyph->w * 2.f * scale_width * ar; + _h = glyph->h * 2.f * s; + + _x *= GetGlobalAspectRatio(); + _w *= GetGlobalAspectRatio(); + } + else + { + _x = x * 2.f - 1.f + glyph->offx * 2.f * glyph_mapping.x * scale_width; + _y = (1.f - y) * 2.f - 1.f - glyph->offy * 2.f * glyph_mapping.y * s; + _w = glyph->w * 2.f * glyph_mapping.x * scale_width; + _h = glyph->h * 2.f * glyph_mapping.y * s; + } + + vtx[0].Set(_x, _y, 0.5); + vtx[1].Set(_x + _w, _y, 0.5); + vtx[2].Set(_x + _w, _y - _h, 0.5); + vtx[3].Set(_x, _y - _h, 0.5); + + uv[0].Set(glyph->u, glyph->v); + uv[1].Set(glyph->u + glyph->w, glyph->v); + uv[2].Set(glyph->u + glyph->w, glyph->v + glyph->h); + uv[3].Set(glyph->u, glyph->v + glyph->h); + + const ushort indice[] = { 0, 1, 2, 0, 2, 3 }; // order is reversed because the quad is drawn from the baseline (bottom to top) + batch.DrawTriangle(2, 4, vtx, indice, col, uv, t_page, Core::Material::Blend_Alpha, (Core::Material::RenderWord)(Core::Material::Render_NoZTest | Core::Material::Render_NoZWrite | Core::Material::Render_DoubleSided)); + } + + if (config.normalized) + x += glyph->step * scale_width * ar; + else x += glyph->step * glyph_mapping.x * scale_width; + } + } + + batch.Flush(); + + if (!config.normalized) + { + x /= pixel_mapping.x; + y /= pixel_mapping.y; + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/import/import_interface.cpp b/include/engine/import/import_interface.cpp new file mode 100644 index 0000000..b217b70 --- /dev/null +++ b/include/engine/import/import_interface.cpp @@ -0,0 +1,45 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "import/import_interface.h" + #include "filesystem/filesystem.h" + #include "platform.h" + + using GS::String; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool IImport::GetOutputPath(String &path, const String &base, const char *name, const char *dflt, const char *ext, Config::PathExistsPolicy exist_policy) const +{ + if (base.IsEmpty()) + return false; + + if (!name) + name = dflt; + + path = String::Format("%s/%s.%s", base.c_str(), name, ext); + + switch (exist_policy) + { + case Config::Overwrite: + return true; + + case Config::Skip: + if (Platform::Get().io->Exists(path)) + return false; + break; + + case Config::Rename: + for (uint n = 0; Platform::Get().io->Exists(path) && (n < 10000); ++n) + path = String::Format("%s/%s-%04d.%s", base.c_str(), name, n, ext); + break; + + default: break; + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/motion.cpp b/include/engine/motion/motion.cpp new file mode 100644 index 0000000..d96df41 --- /dev/null +++ b/include/engine/motion/motion.cpp @@ -0,0 +1,457 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "motion/motion.h" + #include "core/path_kdtree.h" + #include "math/vector.h" + #include "geometry/geometric_tools.h" + #include "time/ntime_range.h" + #include "memory/memory.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +void Motion::Clone(const Motion &src, const TimeRange &range, bool enforce_loop) +{ + // Clone all channels. + channel_list.Clear(); + ListForeachPtr(MotionChannel *, sc, src.GetChannelList()) + { + MotionChannel *c = new MotionChannel; + if (c == NULL) + continue; + + c->type = sc->type; + + // Transfer points. + const ArrayList &points = sc->GetPoints(); + for (uint n = 0; n < points.GetCount(); ++n) + { + CurvePoint *p = points[n]; + if ((p->t < range.start) || (p->t > range.end)) + continue; + + CurvePoint np(*p); + np.t -= range.start; + c->Append(np); + } + channel_list.Add(c); + + // Post-processing. + const ArrayList &c_points = c->GetPoints(); + uint count = c_points.GetCount(); + + if (count == 0) + continue; + + if (enforce_loop) + { + c_points[0]->t.setSec(0); // snap key start + + if (count > 1) + { + c_points[count - 1]->t = range.valueRange(); + c_points[count - 1]->v = c_points[0]->v; + } + } + } + + // Clone quaternion channel. + quaternion.Clear(); + + if ((use_quaternion = src.GetUseQuaternion()) != false) + { + const ArrayList &keys = src.GetQuaternion().GetKeys(); + + for (uint n = 0; n < keys.GetCount(); ++n) + { + QuaternionKey *k = keys[n]; + if ((k->t < range.start) || (k->t > range.end)) + continue; + + QuaternionKey nk(*k); + nk.t -= range.start; + quaternion.Insert(nk); + } + + // Post-processing. + const ArrayList &c_keys = quaternion.GetKeys(); + uint count = c_keys.GetCount(); + + if (enforce_loop) + { + c_keys[0]->t.setSec(0); // snap key start + + if (count > 1) + { + c_keys[count - 1]->t = range.valueRange(); + c_keys[count - 1]->q = c_keys[0]->q; + } + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Motion::HasKey(const TimeRange &t) const +{ + ListForeachPtr(MotionChannel *, c, GetChannelList()) + for (uint n = 0; n < c->GetPointCount(); ++n) + { + const CurvePoint *p = c->GetPoints()[n]; + if (t.inRange(p->t)) + return true; + } + + return false; +} +void Motion::MoveKey(const TimeRange &t, const Time &offset) const +{ + ListForeachPtr(MotionChannel *, c, GetChannelList()) + { + for (uint n = 0; n < c->GetPointCount(); ++n) + { + CurvePoint *p = c->GetPoints()[n]; + if (t.inRange(p->t)) + p->t += offset; + } + c->Sort(); + } +} +void Motion::DeleteKey(const TimeRange &t) +{ + ListForeachPtr(MotionChannel *, c, GetChannelList()) + { + for (uint n = 0; n < c->GetPointCount(); ++n) + { + CurvePoint *p = c->GetPoints()[n]; + if (t.inRange(p->t)) + { + c->Delete(p); + --n; + } + } + c->Sort(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Motion::GetClosestPoint(const Vector4 &position, Vector4 &closest, float *closest_t) +{ + float best_d = -1.f; + if (closest_t) + *closest_t = -1; + + MotionChannel *c[3]; + GetTransformationChannels(c, NULL, NULL); + + // kdtree path + if (c[0] && c[1] && c[2]) + { + if(0 && quadtree.IsNull()) // create it, because we need it + { + quadtree = new PathKdtree; + + ArrayList &array_x = c[0]->GetPoints(); + ArrayList &array_y = c[1]->GetPoints(); + ArrayList &array_z = c[2]->GetPoints(); + + ArrayList ::Iterator iterator_x(array_x); + ArrayList ::Iterator iterator_y(array_y); + ArrayList ::Iterator iterator_z(array_z); + + CurvePoint * x = iterator_x.ObjectPtr(); + CurvePoint * y = iterator_y.ObjectPtr(); + CurvePoint * z = iterator_z.ObjectPtr(); + + Vector4 a_node(x->v,y->v, z->v); + float a_node_t = x->t.toSec(); + + // get the second node + ++iterator_x; + ++iterator_y; + ++iterator_z; + + x = iterator_x.ObjectPtr(); + y = iterator_y.ObjectPtr(); + z = iterator_z.ObjectPtr(); + + while(x && y && z) + { + Vector4 b_node(x->v,y->v, z->v); + float b_node_t = x->t.toSec(); + + nMSegment * segment = new nMSegment(); + segment->a = a_node; + segment->b = b_node; + segment->a_t = a_node_t; + segment->b_t = b_node_t; + + quadtree->AddSegment(segment); + + a_node = b_node; + a_node_t = b_node_t; + + ++iterator_x; + ++iterator_y; + ++iterator_z; + + x = iterator_x.ObjectPtr(); + y = iterator_y.ObjectPtr(); + z = iterator_z.ObjectPtr(); + } + + quadtree->BuildQuadtree(); + } + + // check first if the point is inside the kdtree, else brute force + if(0 && quadtree->InsideKdTree(position)) + { + SharedArrayList list_segment; + quadtree->NearestQuadtreeTreeNode(position, list_segment); + + for (uint i = 0; i < list_segment.GetCount(); ++i) + { + Vector4 p; + float t = GS::Geometric::SegmentClosestPoint(list_segment[i]->a, list_segment[i]->b, position, &p); + + t = t < 0.0f? 0.0f: (t>1.0f? 1.0f:t); + + float d = Vector4::Dist2(position, p); + if ((best_d < 0.f) || (d < best_d)) + { + best_d = d; + closest = p; + if (closest_t) + *closest_t = t * (list_segment[i]->b_t - list_segment[i]->a_t) + list_segment[i]->a_t; + } + } + } + else + //brute force + { + ArrayList &array_x = c[0]->GetPoints(); + ArrayList &array_y = c[1]->GetPoints(); + ArrayList &array_z = c[2]->GetPoints(); + + ArrayList ::Iterator iterator_x(array_x); + ArrayList ::Iterator iterator_y(array_y); + ArrayList ::Iterator iterator_z(array_z); + + CurvePoint * x = iterator_x.ObjectPtr(); + CurvePoint * y = iterator_y.ObjectPtr(); + CurvePoint * z = iterator_z.ObjectPtr(); + + if (x && y && z) // [EJ] empty channels would crash on the next line + { + Vector4 a_node(x->v,y->v, z->v); + float a_node_t = x->t.toSec(); + + // get the second node + ++iterator_x; + ++iterator_y; + ++iterator_z; + + x = iterator_x.ObjectPtr(); + y = iterator_y.ObjectPtr(); + z = iterator_z.ObjectPtr(); + + while(x && y && z) + { + Vector4 b_node(x->v,y->v, z->v); + float b_node_t = x->t.toSec(); + + Vector4 p; + float t = Geometric::SegmentClosestPoint(a_node, b_node, position, &p); + + t = t < 0.0f? 0.0f: (t>1.0f? 1.0f:t); + + float d = Vector4::Dist2(position, p); + if ((best_d < 0.f) || (d < best_d)) + { + best_d = d; + closest = p; + if (closest_t) + *closest_t = t * (b_node_t - a_node_t) + a_node_t; + } + + a_node = b_node; + a_node_t = b_node_t; + + ++iterator_x; + ++iterator_y; + ++iterator_z; + + x = iterator_x.ObjectPtr(); + y = iterator_y.ObjectPtr(); + z = iterator_z.ObjectPtr(); + } + } + } + } + return best_d != -1.f; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Motion::EvaluateData(const Time &t, Variant &sample) +{ + ArrayListForeachPtr(SDataPoint *, data, data_point) + { + if (data->t <= t) + sample = data->data; + else + return; // the t in data is more than the t asked so return because the t in data is ordered + } +} +void Motion::EvaluatePosition(const Time &t, Vector4 &sample, Curve::LoopMode _loop_mode) +{ + MotionChannel *c[3]; + GetTransformationChannels(c, NULL, NULL); + for (int n = 0; n < 3; ++n) + if (c[n]) + c[n]->Evaluate(t, &sample[n], _loop_mode); +} +void Motion::EvaluateRotation(const Time &t, Vector4 &sample, Curve::LoopMode _loop_mode) +{ + MotionChannel *c[3]; + GetTransformationChannels(NULL, c, NULL); + for (int n = 0; n < 3; ++n) + if (c[n]) + c[n]->Evaluate(t, &sample[n], _loop_mode); +} + +void Motion::EvaluateDirection(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode) +{ + const float dt = 0.01f; + + Vector4 p1(0,0,0), p2(0,0,0); + + EvaluatePosition(t, p1, loop_mode); + + Time t2 = Time::fromSec(t.toSec() + dt); + EvaluatePosition(t2, p2, loop_mode); + + sample = p2 - p1; + + float len = sample.Len(); + if (len > 1e-4f) + sample /= len; + else + sample = Vector4(0,0,0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Motion::GetTransformationChannels(MotionChannel *t[3], MotionChannel *r[3], MotionChannel *s[3]) +{ + if (t) { t[0] = t[1] = t[2] = NULL; } + if (r) { r[0] = r[1] = r[2] = NULL; } + if (s) { s[0] = s[1] = s[2] = NULL; } + + ListForeachPtr(MotionChannel *, channel, channel_list) + switch (channel->type) + { + case MotionChannel::XPos: if (t) t[0] = channel; break; + case MotionChannel::YPos: if (t) t[1] = channel; break; + case MotionChannel::ZPos: if (t) t[2] = channel; break; + case MotionChannel::XRot: if (r) r[0] = channel; break; + case MotionChannel::YRot: if (r) r[1] = channel; break; + case MotionChannel::ZRot: if (r) r[2] = channel; break; + case MotionChannel::XScl: if (s) s[0] = channel; break; + case MotionChannel::YScl: if (s) s[1] = channel; break; + case MotionChannel::ZScl: if (s) s[2] = channel; break; + + default: break; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +TimeRange Motion::GetTimeRange() const +{ + if (channel_list.GetCount() == 0) + return TimeRange(); + + List ::Item *i = channel_list.GetRoot(); + + TimeRange range = i->Object()->GetTimeRange(); + for (i = i->Next(); i; i = i->Next()) + range = TimeRange::Union(range, i->Object()->GetTimeRange()); + + range = TimeRange::Union(range, quaternion.GetTimeRange()); + return range; +} +Time Motion::GetDuration() const +{ + Time duration; + ListForeachPtr(MotionChannel *, channel, channel_list) + duration = Types::Max(duration, channel->GetDuration()); + return duration; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MotionChannel *Motion::AddChannel(MotionChannel::Type type) +{ + MotionChannel *nc = new MotionChannel; + if (!nc) + __ERR__(__LOG_E__ << "Could not allocate channel.\n", NULL) + nc->type = type; + channel_list.Add(nc); + return nc; +} +void Motion::AddChannels(uint nc) +{ + while (nc--) + AddChannel(MotionChannel::Undf); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Motion::GetUseQuaternion() const +{ return use_quaternion && quaternion.GetKeys().GetCount(); } +MotionChannel *Motion::GetChannel(uint index) const +{ return GetChannelList().ObjectAt(index); } +MotionChannel *Motion::GetChannel(MotionChannel::Type type) const +{ + ListForeachPtr(MotionChannel *, channel, channel_list) + if (channel && channel->type == type) + return channel; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t Motion::MemoryFootPrint() const +{ + size_t footprint = 0; + ListForeachPtr(MotionChannel *, channel, channel_list) + footprint += channel->MemoryFootPrint(); + footprint += quaternion.MemoryFootPrint(); + footprint += sizeof(Motion); + return footprint; +} +uint Motion::Optimize(float threshold) +{ + uint wiped = 0; + ListForeachPtr(MotionChannel *, channel, channel_list) + forever + { + uint pass_wiped = channel->Optimize(threshold); + if (!pass_wiped) + break; + wiped += pass_wiped; + } + + return wiped; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/motion.h b/include/engine/motion/motion.h index b69ba70..968f962 100644 --- a/include/engine/motion/motion.h +++ b/include/engine/motion/motion.h @@ -59,6 +59,7 @@ public: void EvaluateData(const Time &t, Variant &sample); void EvaluatePosition(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode = Curve::Reset); + void EvaluateDirection(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode = Curve::Reset); void EvaluateRotation(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode = Curve::Reset); /// Get transformation channels. diff --git a/include/engine/motion/motion_automation_source.cpp b/include/engine/motion/motion_automation_source.cpp new file mode 100644 index 0000000..add4dd9 --- /dev/null +++ b/include/engine/motion/motion_automation_source.cpp @@ -0,0 +1,143 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/motion_automation_source.h" + #include "motion/motion.h" + #include "automation/automation_source_group.h" + #include "automation/automation_player.h" + + using namespace GS::Automation; + + +//------------------------------------------------------------------------------ +void MotionSource::Evaluate(Player &target) +{ + if (motion == NULL) + return; + + ListForeachPtr(MotionChannel *, channel, motion->GetChannelList()) + { + if (channel->GetPointCount() == 0) + continue; + + // Skip rotation channels if using quaternion. + if (motion->GetUseQuaternion()) + switch (channel->type) + { + case MotionChannel::XRot: + case MotionChannel::YRot: + case MotionChannel::ZRot: + continue; + + default: break; + } + + // Evaluate channel. + float v; + channel->Evaluate(time, &v, loop_mode, loop_start, loop_end); + + // Relative mode. + switch (channel->type) + { + case MotionChannel::XPos: + case MotionChannel::YPos: + case MotionChannel::ZPos: + { + float _v = v, s; + if (relative && target.property_provider->GetProperty(channel->type, s)) + v = s + v - p_pos[channel->type - MotionChannel::XPos]; + p_pos[channel->type - MotionChannel::XPos] = _v; + } + break; + + case MotionChannel::XRot: + case MotionChannel::YRot: + case MotionChannel::ZRot: + { + float _v = v, s; + if (relative && target.property_provider->GetProperty(channel->type, s)) + v = s + v - p_euler[channel->type - MotionChannel::XRot]; + p_euler[channel->type - MotionChannel::XRot] = _v; + } + break; + + default: break; + } + + target.BlendAutomatedProperty(channel->type, v, GetWeight()); + } +} +bool MotionSource::EvaluateRotation(GS::Quaternion &q) +{ + if (!motion->GetUseQuaternion()) + return false; + + Quaternion s = q; + motion->GetQuaternion().Evaluate(time, q, loop_mode, loop_start, loop_end); + + Quaternion _q = q; + if (relative) + q = (q * p_quat.Inverse()) * s; + p_quat = _q; + return true; +} +bool MotionSource::IsDone() const +{ + if (!motion) + return true; + + switch (loop_mode) + { + case Curve::Repeat: + case Curve::OffsetAndRepeat: + case Curve::Oscillate: + break; + + default: + if (time_scale > 0) + { + if (time > loop_end) + return true; + } + else + if (time < loop_start) + return true; + break; + } + return false; +} +MotionSource::MotionSource(Motion *_motion, SourceGroup *_group) +{ + type = TypeMotion; + motion = _motion; + + loop_mode = Curve::Constant; + + if (motion) + { + TimeRange range = motion->GetTimeRange(); + loop_start = range.start; + loop_end = range.end; + } + else + { + loop_start = Time::Inf; + loop_end = Time::Inf; + } + + // Evaluate relative position/euler. + relative = false; + + motion->EvaluatePosition(loop_start, p_pos, loop_mode); + if (motion->GetUseQuaternion()) + motion->GetQuaternion().Evaluate(loop_start, p_quat, loop_mode); + else motion->EvaluateRotation(loop_start, p_euler, loop_mode); + + group = _group; + if (group) + group->source_list.Add(this, true, false); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/motion_channel.cpp b/include/engine/motion/motion_channel.cpp new file mode 100644 index 0000000..f02e32d --- /dev/null +++ b/include/engine/motion/motion_channel.cpp @@ -0,0 +1,17 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/motion_channel.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +MotionChannel::MotionChannel() +{ type = NoType; } +MotionChannel::~MotionChannel() +{ Clear(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/motion_channel_nml.cpp b/include/engine/motion/motion_channel_nml.cpp new file mode 100644 index 0000000..5067693 --- /dev/null +++ b/include/engine/motion/motion_channel_nml.cpp @@ -0,0 +1,131 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/motion_channel.h" + #include "log/log.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +bool MotionChannel::FromMetaTag(GS::NML::Tag &tag) +{ + if (tag.name != "Channel") + __ERR__(__LOG_E__ << "Could not parse motion channel, incorrect root tag (" << tag.name << ").\n", false) + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "Curve") + Curve::FromMetaTag(*pt); + + else if (pt->name == "Id") + { + String chn(pt->GetString()); + + if (chn == "PositionX") type = XPos; + else if (chn == "PositionY") type = YPos; + else if (chn == "PositionZ") type = ZPos; + else if (chn == "RotationX") type = XRot; + else if (chn == "RotationY") type = YRot; + else if (chn == "RotationZ") type = ZRot; + else if (chn == "ScaleX") type = XScl; + else if (chn == "ScaleY") type = YScl; + else if (chn == "ScaleZ") type = ZScl; + + else if (chn == "PivotX") type = XPiv; + else if (chn == "PivotY") type = YPiv; + else if (chn == "PivotZ") type = ZPiv; + + else if (chn == "DiffuseR") type = RDif; + else if (chn == "DiffuseG") type = GDif; + else if (chn == "DiffuseB") type = BDif; + else if (chn == "SpecularR") type = RSpc; + else if (chn == "SpecularG") type = GSpc; + else if (chn == "SpecularB") type = BSpc; + + else if (chn == "DiffuseI") type = DiffuseIntensity; + else if (chn == "SpecularI") type = SpecularIntensity; + + else if (chn == "ConeAngle") type = ConeAngle; + else if (chn == "EdgeAngle") type = EdgeAngle; + + else if (chn == "Alpha") type = Alpha; + + else if (chn == "Zoom") type = ZoomFactor; + + else if (chn == "Range") type = Range; + + else if (chn == "FogStart") type = FogStart; + else if (chn == "FogEnd") type = FogEnd; + else if (chn == "FogR") type = RFog; + else if (chn == "FogG") type = GFog; + else if (chn == "FogB") type = BFog; + + else __LOG_W__ << "Unknown channel id '" << chn << "'.\n"; + } + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +GS::NML::Tag *MotionChannel::AsMetaTag() const +{ + NML::Tag *root = new NML::Tag("Channel"); + if (!root) + __ERR__(__LOG_E__ << "Could not create channel root tag to serialize.\n", NULL) + + // Serialize underlying curve. + root->AddChild(Curve::AsMetaTag()); + + // Channel type. + switch (type) + { + case XPos: root->AddChild("Id", "PositionX"); break; + case YPos: root->AddChild("Id", "PositionY"); break; + case ZPos: root->AddChild("Id", "PositionZ"); break; + case XRot: root->AddChild("Id", "RotationX"); break; + case YRot: root->AddChild("Id", "RotationY"); break; + case ZRot: root->AddChild("Id", "RotationZ"); break; + case XScl: root->AddChild("Id", "ScaleX"); break; + case YScl: root->AddChild("Id", "ScaleY"); break; + case ZScl: root->AddChild("Id", "ScaleZ"); break; + + case XPiv: root->AddChild("Id", "PivotX"); break; + case YPiv: root->AddChild("Id", "PivotY"); break; + case ZPiv: root->AddChild("Id", "PivotZ"); break; + + case RDif: root->AddChild("Id", "DiffuseR"); break; + case GDif: root->AddChild("Id", "DiffuseG"); break; + case BDif: root->AddChild("Id", "DiffuseB"); break; + case RSpc: root->AddChild("Id", "SpecularR"); break; + case GSpc: root->AddChild("Id", "SpecularG"); break; + case BSpc: root->AddChild("Id", "SpecularB"); break; + + case DiffuseIntensity: root->AddChild("Id", "DiffuseI"); break; + case SpecularIntensity: root->AddChild("Id", "SpecularI"); break; + + case ConeAngle: root->AddChild("Id", "ConeAngle"); break; + case EdgeAngle: root->AddChild("Id", "EdgeAngle"); break; + + case Alpha: root->AddChild("Id", "Alpha"); break; + + case ZoomFactor: root->AddChild("Id", "Zoom"); break; + + case Range: root->AddChild("Id", "Range"); break; + + case FogStart: root->AddChild("Id", "FogStart"); break; + case FogEnd: root->AddChild("Id", "FogEnd"); break; + case RFog: root->AddChild("Id", "FogR"); break; + case GFog: root->AddChild("Id", "FogG"); break; + case BFog: root->AddChild("Id", "FogB"); break; + + default: + __LOG_W__ << "Unknown motion channel type (" << type << ").\n"; + break; + } + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/motion_nml.cpp b/include/engine/motion/motion_nml.cpp new file mode 100644 index 0000000..6554334 --- /dev/null +++ b/include/engine/motion/motion_nml.cpp @@ -0,0 +1,108 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/motion.h" + #include "log/log.h" + + using namespace GS::Core; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool Motion::FromMetaTag(Tag &tag) +{ + if (tag.name != "Motion") + __ERR__(__LOG_E__ << "Could not parse motion, incorrect root tag (" << tag.name << ").\n", false) + + use_quaternion = false; + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "Id") + name = pt->GetString(); + else if (pt->name == "UseQuaternion") + use_quaternion = pt->GetBool(); + else if (pt->name == "QChannel") + quaternion.FromMetaTag(*pt); + + else if (pt->name == "Channel") + { + MotionChannel *chn = AddChannel(MotionChannel::Undf); + chn->FromMetaTag(*pt); + } + else if (pt->name == "DataKnot") + { + Tag *count_tag = pt->GetTag("Count"); + + ArrayListDeleteAllPtr(SDataPoint *, data_point) + + if (count_tag && count_tag->GetInteger() > 0) + { + uint n = (uint)count_tag->GetInteger(); + while (n--) + if (!data_point.Add(new SDataPoint)) + return false; + + n = 0; + NMLTagForeach(st, *pt) + { + if (st->name == "Knot") + { + if (n == data_point.GetCount()) + { + __LOG_E__ << "Too many knot in , " << data_point.GetCount() << " expected.\n"; + break; + } + + if (const char *p = st->GetString()) + { + data_point[n]->t = Time::fromSec(String::atof(p)); + + p = String::strfindchar(p, ':'); + data_point[n]->data = Variant(p + 1); + + n++; + } + else + __LOG_W__ << "Invalid knot tag while parsing curve.\n"; + } + } + } + } + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *Motion::AsMetaTag() +{ + Tag *root = new Tag("Motion"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild("Id", name.c_str()); + + // Dump quaternion channel. + root->AddChild("UseQuaternion", use_quaternion); + root->AddChild(quaternion.AsMetaTag()); + + // Dump all channels. + ListForeachPtr(MotionChannel *, channel, channel_list) + root->AddChild(channel->AsMetaTag()); + + // Dump the data array + if (data_point.GetCount()) + if (Tag *data_knot_tag = root->AddChild("DataKnot")) + { + data_knot_tag->AddChild("Count", (int)data_point.GetCount()); + + ArrayListForeachPtr(SDataPoint *, data, data_point) + data_knot_tag->AddChild("Knot",String::Format("%f:%s", data->t.toSec(), data->data.s_value.c_str()).c_str()); + } + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/quaternion_channel.cpp b/include/engine/motion/quaternion_channel.cpp new file mode 100644 index 0000000..dd68025 --- /dev/null +++ b/include/engine/motion/quaternion_channel.cpp @@ -0,0 +1,179 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/quaternion_channel.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +static float range(float v, float lo, float hi, int *i) +{ + float r = hi - lo; + + if (!r) + { + if (i) + *i = 0; + return lo; + } + + float v2 = v - lo; + + if (v2 >= 0) + v2 = lo + v2 - r * Math::Floor(v2 / r); + else v2 = hi + v2 - r * Math::Ceil(v2 / r); + + if (i) + *i = - (int)((v2 - v) / r + (v2 > v ? 0.5f : -0.5f)); + return Types::Clamp(v2, lo, hi); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void QuaternionChannel::Evaluate(Time t, Quaternion &p, Curve::LoopMode loop, Time loop_start, Time loop_end) const +{ + if (keys.GetCount() == 0) + return; + + QuaternionKey *skey = keys[0], *ekey = keys[keys.GetCount() - 1]; + + loop_start = (loop_start == Time::Inf) ? skey->t : Types::Clamp(loop_start, skey->t, ekey->t); + loop_end = (loop_end == Time::Inf) ? ekey->t : Types::Clamp(loop_end, skey->t, ekey->t); + + int noff = 0; + if (t < loop_start) + { + switch (loop) + { + default: + case Curve::Constant: + Evaluate(loop_start, p, loop, loop_start, loop_end); + return; + case Curve::Reset: + p.Set(0, 0, 0, 1); + return; + + case Curve::Repeat: + case Curve::OffsetAndRepeat: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL)); + break; + case Curve::Oscillate: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff)); + if (noff % 2) + t = loop_end + loop_start - t; + break; + } + } + else if (t > loop_end) + { + switch (loop) + { + default: + case Curve::Constant: + Evaluate(loop_end, p, loop, loop_start, loop_end); + return; + case Curve::Reset: + p.Set(0, 0, 0, 1); + return; + + case Curve::Repeat: + case Curve::OffsetAndRepeat: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL)); + break; + case Curve::Oscillate: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff)); + if (noff % 2) + t = loop_end + loop_start - t; + break; + } + } + + // Evaluate (t is guaranteed to be in range). + int ikey0; +#if 1 + { + uint lo = 0, hi = keys.GetCount() - 1; + + forever + { + uint mid = (lo + hi) / 2; + + if (keys[mid]->t > t) + hi = mid; + else + { + if (lo == mid) + { + ikey0 = lo; + break; + } + else + lo = mid; + } + } + } +#else + for (ikey0 = 1; ikey0 < int(keys.GetCount()); ikey0++) + if (keys[ikey0]->t > t) + break; + --ikey0; +#endif + + // Slerp. + if (ikey0 == (int(keys.GetCount()) - 1)) + p = keys[ikey0]->q; + else + { + const float k = (t - keys[ikey0]->t).toSec() / (keys[ikey0 + 1]->t - keys[ikey0]->t).toSec(); + p = Quaternion::Slerp(k, keys[ikey0]->q, keys[ikey0 + 1]->q).Normalize(); + } +} +uint QuaternionChannel::Optimize(float threshold) +{ + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +TimeRange QuaternionChannel::GetTimeRange() const +{ + Time min, max; + if (keys.GetCount() > 0) + { + min = max = keys[0]->t; + for (uint n = 1; n < keys.GetCount(); ++n) + { + min = Types::Min(min, keys[n]->t); + max = Types::Max(max, keys[n]->t); + } + } + return TimeRange(min, max); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool QuaternionChannel::Insert(const QuaternionKey &key) +{ + uint n = 0; + for (; n < keys.GetCount(); ++n) + if (keys[n]->t > key.t) + break; + + return keys.Insert(new QuaternionKey(key), n); +} +void QuaternionChannel::Clear() +{ + ArrayListDeleteAllPtr(QuaternionKey *, keys) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +QuaternionChannel::QuaternionChannel() +{} +QuaternionChannel::~QuaternionChannel() +{ Clear(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/quaternion_channel_nml.cpp b/include/engine/motion/quaternion_channel_nml.cpp new file mode 100644 index 0000000..f50921e --- /dev/null +++ b/include/engine/motion/quaternion_channel_nml.cpp @@ -0,0 +1,121 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/quaternion_channel.h" + #include "metafile/nml.h" + #include "alloc/ialloc.h" + #include "log/log.h" + + using namespace GS; + using NML::Tag; + + +//------------------------------------------------------------------------------ +bool QuaternionChannel::FromMetaTag(Tag &tag) +{ + if (tag.name != "QChannel") + __ERR__(__LOG_E__ << "Could not parse motion quaternion channel, incorrect root tag (" << tag.name << ").\n", false) + + Clear(); + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "BinaryKeys") + { + Tag *count_tag = pt->GetTag("Count"), *data_tag = pt->GetTag("Data"); + + if (count_tag && data_tag) + { + float *data = (float *)data_tag->GetValue().GetBinaryBuffer(), *p_data = data; + + if (data) + { + int count = count_tag->GetInteger(); + for (int n = 0; n < count; ++n) + { + QuaternionKey *key = new QuaternionKey; + + key->t = Time::fromSec(*p_data++); + key->q.x = *p_data++; + key->q.y = *p_data++; + key->q.z = *p_data++; + key->q.w = *p_data++; + + keys.Add(key); + } + } + } + } + else if (pt->name == "Keys") + { + NMLTagForeach(st, *pt) + if (st->name == "Key") + { + const char *p = st->GetString(); + if (!p) + __LOG_W__ << "Invalid key tag while parsing quaternion channel.\n"; + + else + { + //------------------------------------------------------------------------------------------- + #define SEEK_CHAR(v) \ + p = String::strfindchar(p, (v)); \ + if (!p[0]) \ + __ERR__(__LOG_W__ << "Mangled keyframe tag while parsing quaternion channel.\n", false) \ + p++; \ + //------------------------------------------------------------------------------------------- + + QuaternionKey *key = new QuaternionKey; + + key->t = Time::fromSec(String::atof(p, NULL, false)); + SEEK_CHAR(':'); + + key->q.x = String::atof(p, NULL, false); + SEEK_CHAR(','); + key->q.y = String::atof(p, NULL, false); + SEEK_CHAR(','); + key->q.z = String::atof(p, NULL, false); + SEEK_CHAR(','); + key->q.w = String::atof(p, NULL, false); + + keys.Add(key); + } + } + } + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *QuaternionChannel::AsMetaTag() +{ + Tag *root = new Tag("QChannel"); + if (!root) + __ERR__(__LOG_E__ << "Could not create quaternion channel root tag to serialize.\n", NULL) + + if (keys.GetCount()) + if (Tag *kf_tag = root->AddChild("BinaryKeys")) + { + kf_tag->AddChild("Count", (int)keys.GetCount()); // Legacy support. + + float *kf_array = new float[5 * keys.GetCount()], *p_kf = kf_array; + + for (uint n = 0; n < keys.GetCount(); n++) + { + *p_kf++ = keys[n]->t.toSec(); + *p_kf++ = keys[n]->q.x; + *p_kf++ = keys[n]->q.y; + *p_kf++ = keys[n]->q.z; + *p_kf++ = keys[n]->q.w; + } + + kf_tag->AddChild("Data", (uchar *)kf_array, 5 * 4 * keys.GetCount()); + _safe_delete_array(kf_array); + } + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/scene_motion.cpp b/include/engine/motion/scene_motion.cpp new file mode 100644 index 0000000..71a2bfb --- /dev/null +++ b/include/engine/motion/scene_motion.cpp @@ -0,0 +1,138 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/scene_motion.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Core; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +Motion *SceneMotion::GetItemMotion(uint uid, bool create_if_missing) +{ + ListForeachPtr(ItemMotion *, m, item_motions) + if (m->uid == uid) + return m->motion; + + if (!create_if_missing) + return NULL; + + ItemMotion *item_motion = new ItemMotion; + if (!item_motion) + __ERR__(__LOG_E__ << "Failed to allocate item motion.\n", NULL) + + item_motion->uid = uid; + item_motion->motion = new Motion; + + item_motions.Add(item_motion); + return item_motion->motion; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SceneMotion::Clone(const SceneMotion &src, const TimeRange &range, bool enforce_loop) +{ + // Clone item motions. + item_motions.Clear(); + + ListForeachPtr(ItemMotion *, m, src.item_motions) + { + ItemMotion *c = new ItemMotion; + if (c == NULL) + continue; + + c->uid = m->uid; + c->motion = new Motion; + c->motion->Clone(*m->motion, range, enforce_loop); + + item_motions.Add(c); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +TimeRange SceneMotion::GetTimeRange() const +{ + List ::Item *i = item_motions.GetRoot(); + if (i == NULL) + return TimeRange(); + + TimeRange range = i->Object()->motion->GetTimeRange(); + for (i = i->Next(); i; i = i->Next()) + range = TimeRange::Union(range, i->Object()->motion->GetTimeRange()); + + return range; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool SceneMotion::FromMetaTag(Tag &tag, const Map *uid_map) +{ + if (tag.name != "SceneMotion") + __ERR__(__LOG_E__ << "Could not parse scene motion, incorrect root tag (" << tag.name << ").\n", false) + + item_motions.Clear(); + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "Name") + name = pt->GetString(); + + else if (pt->name == "ItemMotions") + { + NMLTagForeach(it, *pt) + { + if (it->name == "ItemMotion") + { + Tag *uid_tag = it->GetTypedTag("UId", Variant::VariantInteger), + *motion_tag = it->GetTag("Motion"); + + if (uid_tag && motion_tag) + { + uint uid = uid_tag->GetUnsigned(); + if (uid_map && !uid_map->HasKey(uid)) + continue; // item got lost, don't load + + ItemMotion *item_motion = new ItemMotion; + + item_motion->uid = uid_map ? (*uid_map)[uid] : uid; + item_motion->motion = new Motion; + item_motion->motion->FromMetaTag(*motion_tag); + + item_motions.Add(item_motion); + } + else + __LOG_W__ << "Mangled item motion tag.\n"; + } + } + } + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *SceneMotion::AsMetaTag() +{ + Tag *root = new Tag("SceneMotion"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild("Name", name); + + if (Tag *pim = root->AddChild("ItemMotions")) + ListForeachPtr(ItemMotion *, m, item_motions) + if (Tag *pm = pim->AddChild("ItemMotion")) + { + pm->AddChild("UId", m->uid); + pm->AddChild(m->motion->AsMetaTag()); + } + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/motion/scene_motion_container.cpp b/include/engine/motion/scene_motion_container.cpp new file mode 100644 index 0000000..040bba2 --- /dev/null +++ b/include/engine/motion/scene_motion_container.cpp @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "motion/scene_motion_container.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Core; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool SceneMotionContainer::FromMetaTag(Tag &tag, const Map *uid_map) +{ + if (tag.name != "SceneMotionContainer") + __ERR__(__LOG_E__ << "Could not parse scene motion container, incorrect root tag (" << tag.name << ").\n", false) + + motions.Clear(); + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "SceneMotion") + { + SceneMotion *set = new SceneMotion; + set->FromMetaTag(*pt, uid_map); + motions.Add(set); + } + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *SceneMotionContainer::AsMetaTag() const +{ + Tag *root = new Tag("SceneMotionContainer"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + ListForeachPtr(SceneMotion *, s, motions) + root->AddChild(s->AsMetaTag()); + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/physic/physic_constraint_desc.cpp b/include/engine/physic/physic_constraint_desc.cpp new file mode 100644 index 0000000..53b1d77 --- /dev/null +++ b/include/engine/physic/physic_constraint_desc.cpp @@ -0,0 +1,73 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic/physic_constraint_desc.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::S3D; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool PhysicConstraintDesc::FromMetaTag(Tag &tag) +{ + if (tag.name != "Constraint") + __ERR__(__LOG_E__ << "Could not parse physic constraint, incorrect root tag (" << tag.name << ").\n", false) + + type = TypeNone; + item_a = item_b = NULL; + pivot_a = pivot_b = Matrix4::IdentityMatrix(); + + NMLTagForeach(pt, tag) + { + if (pt->name == "Type") + { + String _type(pt->GetString()); + + if (_type == "Point") + type = TypePoint; + else if (_type == "Hinge") + type = TypeHinge; + } + + else if (pt->name == "PivotA") + pivot_a.FromMetaTag(*pt); + else if (pt->name == "PivotB") + pivot_b.FromMetaTag(*pt); + + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *PhysicConstraintDesc::AsMetaTag() const +{ + Tag *root = new Tag("Constraint"); + if (!root) + __ERR__(__LOG_E__ << "Could not create physic constraint root tag to serialize.\n", NULL) + + if (type != TypeNone) + { + String _type = "None"; + switch (type) + { + case TypePoint: _type = "Point"; break; + case TypeHinge: _type = "Hinge"; break; + + default: break; + } + root->AddChild("Type", _type.c_str()); + } + + // Save pivot informations. + root->AddChild(pivot_a.AsMetaTag("PivotA")); + root->AddChild(pivot_b.AsMetaTag("PivotB")); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/physic/physic_item_desc.cpp b/include/engine/physic/physic_item_desc.cpp new file mode 100644 index 0000000..805733b --- /dev/null +++ b/include/engine/physic/physic_item_desc.cpp @@ -0,0 +1,143 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic/physic_item_desc.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +float PhysicItemDesc::GetMass() const +{ + float mass = 0; + ListForeachPtr(PhysicShape *, shape, shape_list) + mass += shape->mass; + return mass; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool PhysicItemDesc::FromMetaTag(Tag &tag) +{ + if ((tag.name != "TauItem") && (tag.name != "GColItem") && (tag.name != "PhysicItem")) + __ERR__(__LOG_E__ << "Could not parse physic item, incorrect root tag (" << tag.name << ").\n", false) + + shape_list.Clear(); + vehicle.wheel_list.Clear(); + physic_flags.Set(PhysicFlag_None); + + self_mask = 1; + collision_mask = 1; + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "SelfMask") + self_mask = pt->GetInteger(); + else if (pt->name == "Mask") + collision_mask = pt->GetInteger(); + + else if (pt->name == "Mode") + { + String mode(pt->GetString()); + + if (mode == "None") physic_mode = Mode_None; + else if (mode == "Static") physic_mode = Mode_Static; + else if (mode == "Dynamic") physic_mode = Mode_Dynamic; + else if (mode == "Kinematic") physic_mode = Mode_Kinematic; + else if (mode == "Character") physic_mode = Mode_Character; + else if (mode == "Vehicle") physic_mode = Mode_Vehicle; + } + else if (pt->name == "Shapes") + { + NMLTagForeach(st, *pt) + if (PhysicShape *shape = new PhysicShape) + { + shape->FromMetaTag(*st); + shape_list.Add(shape); + } + } + else if (pt->name == "Wheels") + { + NMLTagForeach(wt, *pt) + if (PhysicWheel *wheel = new PhysicWheel) + { + wheel->FromMetaTag(*wt); + vehicle.wheel_list.Add(wheel); + } + } + else if (pt->name == "Flag") + {} + + else if (pt->name == "CharacterRadius") + character.radius = pt->GetReal(); + else if (pt->name == "CharacterHeight") + character.height = pt->GetReal(); + else if (pt->name == "CharacterMaxStep") + character.max_step = pt->GetReal(); + + else if (pt->name == "LinearDamping_v2") + linear_damping = pt->GetReal(); + else if (pt->name == "AngularDamping_v2") + angular_damping = pt->GetReal(); +#if 1 + else if (pt->name == "LinearDamping") + linear_damping = pt->GetReal(); + else if (pt->name == "AngularDamping") + angular_damping = pt->GetReal(); + else if (pt->name == "Active") + ; +#endif + + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *PhysicItemDesc::AsMetaTag() const +{ + Tag *root = new Tag("PhysicItem"); + if (!root) + __ERR__(__LOG_E__ << "Could not create collision item root tag to serialize.\n", NULL) + + root->AddChild("SelfMask", (int)self_mask); + root->AddChild("Mask", (int)collision_mask); + root->AddChild("LinearDamping_v2", linear_damping); + root->AddChild("AngularDamping_v2", angular_damping); + root->AddChild("CharacterRadius", character.radius); + root->AddChild("CharacterHeight", character.height); + root->AddChild("CharacterMaxStep", character.max_step); + + switch (physic_mode) + { + default: + case Mode_None: root->AddChild("Mode", "None"); break; + + case Mode_Static: root->AddChild("Mode", "Static"); break; + case Mode_Dynamic: root->AddChild("Mode", "Dynamic"); break; + case Mode_Kinematic: root->AddChild("Mode", "Kinematic"); break; + + case Mode_Character: root->AddChild("Mode", "Character"); break; + case Mode_Vehicle: root->AddChild("Mode", "Vehicle"); break; + } + + // Dump shapes. + if (shape_list.GetCount()) + if (Tag *st = root->AddChild("Shapes")) + ListForeachPtr(PhysicShape *, shape, shape_list) + st->AddChild(shape->AsMetaTag()); + + // Dump wheels. + if (vehicle.wheel_list.GetCount()) + if (Tag *wt = root->AddChild("Wheels")) + ListForeachPtr(PhysicWheel *, wheel, vehicle.wheel_list) + wt->AddChild(wheel->AsMetaTag()); + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/physic/physic_shape.cpp b/include/engine/physic/physic_shape.cpp new file mode 100644 index 0000000..fcc0463 --- /dev/null +++ b/include/engine/physic/physic_shape.cpp @@ -0,0 +1,100 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic/physic_shape.h" + #include "math/matrix4.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +GS::Matrix4 PhysicShape::GetMatrix() +{ return Matrix4::TransformationMatrix(position, rotation, dimensions); } +void PhysicShape::SetMatrix(const GS::Matrix4 &m) +{ m.Decompose(&position, &dimensions, &rotation); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool PhysicShape::Set(Type t, const char *p) +{ + Free(); + + type = t; + path = p; + return true; +} +bool PhysicShape::Set(Type t, const GS::Vector4 &d) +{ + Free(); + + type = t; + dimensions = d; + return true; +} +bool PhysicShape::Set(float *ph, int w, int h, float r) +{ + Free(); + + type = TypeHeightmap; + + // Resample the terrain heightfield to a meter resolution. + width = (int)((float)w * r); + height = (int)((float)h * r); + + // + float i = (float)w / (float)width, j = (float)h / (float)height; + + heightmap.Allocate(width * height); + + if (float *po = heightmap) + { + float y = 0; + for (int v = 0; v < height; ++v) + { + float x = 0; + for (int u = 0; u < width; ++u) + { +// *po++ = ph[int(h - y - 1) * w + int(x)]; + *po++ = ph[int(y) * w + int(x)]; + x += i; + } + y += j; + } + } + + resolution = 1.f; // Resampled + return true; +} +void PhysicShape::Free() +{ + type = TypeNone; + heightmap.Free(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +PhysicShape::PhysicShape() +{ + type = TypeNone; + mass = 0; // Static. + + position.Set(); + rotation.Set(); + dimensions.Set(1, 1, 1); + scale.Set(1, 1, 1); + + restitution = 0.5; + static_friction = 0.5; + dynamic_friction = 0.5; + + width = height = 0; + resolution = 1; +} +PhysicShape::~PhysicShape() +{ + Free(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/physic/physic_shape_nml.cpp b/include/engine/physic/physic_shape_nml.cpp new file mode 100644 index 0000000..2a59b90 --- /dev/null +++ b/include/engine/physic/physic_shape_nml.cpp @@ -0,0 +1,157 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic/physic_shape.h" + #include "math/matrix3.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::NML; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool PhysicShape::FromMetaTag(Tag &tag) +{ + if ((tag.name != "GColShape") && (tag.name != "PhysicShape")) + __ERR__(__LOG_E__ << "Could not parse physic shape, incorrect root tag (" << tag.name << ").\n", false) + + type = TypeNone; + mass = Units::Kg(1.f); + + // Parse root tags. + String _mss("Mass"), _damp("Damping"), _sfr("StaticFriction"), _dfr("DynamicFriction"), _res("Restitution"), + _plm("Polymesh"), _msh("Mesh"), _dms("Dimensions"), _rds("Radius"), _pos("Position"), _ori("Orientation"), _rot("Rotation"), + _act("Active"), _type("Type"), _aso("AnisotropicFriction"), _vsf("VStaticFriction"), _vdf("VDynamicFriction"), + _scl("Scale"); + + NMLTagForeach(pt, tag) + { + if (pt->name == _type) + { + String _type(pt->GetString()); + + if (_type == "Box") + type = TypeBox; + else if (_type == "Sphere") + type = TypeSphere; + else if (_type == "Convex") + type = TypeConvex; + else if (_type == "Cylinder") + type = TypeCylinder; + else if (_type == "Cone") + type = TypeCone; + else if (_type == "Capsule") + type = TypeCapsule; + else if (_type == "Mesh") + type = TypeMesh; + else if (_type == "Heightmap") + type = TypeHeightmap; + + // GCol shapes. + else if (_type == "Cuboid") + type = TypeBox; + else if (_type == "PolyMesh") + type = TypeMesh; + + else type = TypeNone; + } + + else if (pt->name == _pos) + position.FromMetaTag(*pt); + else if (pt->name == _rot) + rotation.FromMetaTag(*pt); + else if (pt->name == _ori) + { + Matrix3 orientation_matrix; + orientation_matrix.FromMetaTag(*pt); + rotation = orientation_matrix.AsEuler(); + } + else if (pt->name == _scl) + scale.FromMetaTag(*pt); + else if (pt->name == _dms) + dimensions.FromMetaTag(*pt); + else if (pt->name == _rds) + dimensions.x = pt->GetReal(); + + else if ((pt->name == _plm) || (pt->name == _msh)) + path = pt->GetString(); + + else 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(); + + #if 1 + else if (pt->name == "Active") + ; + #endif + + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *PhysicShape::AsMetaTag() const +{ + Tag *root = new Tag("PhysicShape"); + if (!root) + __ERR__(__LOG_E__ << "Could not create collision shape root tag to serialize.\n", NULL) + + if (type != TypeNone) + { + String _type; + switch (type) + { + case TypeBox: _type = "Box"; break; + case TypeSphere: _type = "Sphere"; break; + case TypeConvex: _type = "Convex"; break; + case TypeCylinder: _type = "Cylinder"; break; + case TypeCone: _type = "Cone"; break; + case TypeCapsule: _type = "Capsule"; break; + case TypeMesh: _type = "Mesh"; break; + case TypeHeightmap: _type = "Heightmap"; break; + + default: + _type = "None"; + break; + } + root->AddChild("Type", _type.c_str()); + } + + root->AddChild(position.AsMetaTag("Position")); + root->AddChild(rotation.AsMetaTag("Rotation")); + root->AddChild(scale.AsMetaTag("Scale")); + root->AddChild(dimensions.AsMetaTag("Dimensions")); + + switch (type) + { + case TypeMesh: + case TypeConvex: + if (!path.IsEmpty()) + root->AddChild("Mesh", path.c_str()); + break; + + default: + break; + } + + if (mass != Units::Kg(1)) + root->AddChild("Mass", mass); + + root->AddChild("StaticFriction", static_friction); + root->AddChild("DynamicFriction", dynamic_friction); + root->AddChild("Restitution", restitution); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/physic/physic_wheel.cpp b/include/engine/physic/physic_wheel.cpp new file mode 100644 index 0000000..13c9bbe --- /dev/null +++ b/include/engine/physic/physic_wheel.cpp @@ -0,0 +1,69 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic/physic_wheel.h" + #include "math/matrix4.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::S3D; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool PhysicWheel::FromMetaTag(Tag &tag) +{ + if (tag.name != "PhysicWheel") + __ERR__(__LOG_E__ << "Could not parse physic wheel, incorrect root tag (" << tag.name << ").\n", false) + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "Friction") friction = pt->GetReal(); + else if (pt->name == "Radius") radius = pt->GetReal(); + + else if (pt->name == "RefMatrix") ref_matrix.FromMetaTag(*pt); + + else if (pt->name == "RestLength") rest_length = pt->GetReal(); + else if (pt->name == "MaxCompression") max_compression = pt->GetReal(); + else if (pt->name == "Stiffness") stiffness = pt->GetReal(); + else if (pt->name == "Damping") damping = pt->GetReal(); + + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *PhysicWheel::AsMetaTag() const +{ + Tag *root = new Tag("PhysicWheel"); + if (!root) + __ERR__(__LOG_E__ << "Could not create physic wheel root tag to serialize.\n", NULL) + + root->AddChild("Friction", friction); + root->AddChild("Radius", radius); + + root->AddChild(ref_matrix.AsMetaTag("RefMatrix")); + + root->AddChild("RestLength", rest_length); + root->AddChild("MaxCompression", max_compression); + root->AddChild("Stiffness", stiffness); + root->AddChild("Damping", damping); + return root; +} +//------------------------------------------------------------------------------ + +PhysicWheel::PhysicWheel() +{ + ref_matrix = Matrix4::IdentityMatrix(); + + friction = 50.f; + radius = 0.3f; + + rest_length = 1.0f; + max_compression = 2.0f; + stiffness = 30.f; + damping = 0.25f; +} diff --git a/include/engine/physic/physic_world.cpp b/include/engine/physic/physic_world.cpp new file mode 100644 index 0000000..63376c2 --- /dev/null +++ b/include/engine/physic/physic_world.cpp @@ -0,0 +1,19 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic/physic_world.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +PhysicWorld::PhysicWorld() +{ + timestep = 1.f / 60.f; + gravity.Set(0, -9.8f, 0); // m.s2 + world_interface = NULL; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/project/project.cpp b/include/engine/project/project.cpp new file mode 100644 index 0000000..e42ff5f --- /dev/null +++ b/include/engine/project/project.cpp @@ -0,0 +1,278 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "project/project.h" + #include "scene3d/scene.h" + #include "ui/ui.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + #include "metafile/nml_object.h" + #include "platform.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +bool Project::IsProjectActionAllowed(const char *f) +{ + if (prohibit_project_action) + __ERR__(__LOG_E__ << "Cannot call '" << f << "' while rendering or evaluating the project scene stack.\n", false) + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Project::ResetStatistics() +{ + ListForeachPtr(ProjectSceneInstance *, i, instance_list) + switch (i->type) + { + case ProjectSceneInstance::Type_Scene2d: + break; + + case ProjectSceneInstance::Type_Scene3d: + i->instance_3d->profiler.ResetProfiles(); + break; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Project::GetActiveCount() const +{ + uint count = 0; + ListForeachPtr(ProjectSceneInstance *, i, instance_list) + if (i->active) + ++count; + return count; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ProjectSceneInstance *Project::FindSceneInstance(const char *name) const +{ + ListForeachPtr(ProjectSceneInstance *, s, instance_list) + switch (s->GetType()) + { + case ProjectSceneInstance::Type_Scene3d: + if (s->instance_3d->name == name) + return s; + break; + + case ProjectSceneInstance::Type_Scene2d: + if (s->instance_2d->name == name) + return s; + break; + } + return NULL; +} +ProjectSceneInstance *Project::FindSceneInstance(const GS::S3D::Scene *scene) const +{ + ListForeachPtr(ProjectSceneInstance *, s, instance_list) + if (s->instance_3d == scene) + return s; + return NULL; +} +ProjectSceneInstance *Project::FindSceneInstance(const GS::S2D::Scene *scene) const +{ + ListForeachPtr(ProjectSceneInstance *, s, instance_list) + if (s->instance_2d == scene) + return s; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Project::New() +{ + Close(); + + name = "New Project"; + + root_script_list.Clear(); + search_path.Clear(); +} +bool Project::Open(bool project_exec_mode) +{ + __PROJECT_ACTION_SAFETY_CHECK(false) + + vm->Set("g_platform", Platform::Get().GetName().c_str()); + vm->Set("g_context_project", project_exec_mode); + + if (!CompileRootScripts()) + return false; + if (!script_unit->Open()) + return false; + + return true; +} +bool Project::Setup() +{ + __PROJECT_ACTION_SAFETY_CHECK(false) + + // Script callback. + if (script_unit->SetupFunctionCall("OnSetup", script_unit->setup_callback)) + script_unit->DoFunctionCall(); + + return true; +} +void Project::Close() +{ + __PROJECT_ACTION_SAFETY_CHECK_RAW + + // OnClose callback. + if (script_unit->SetupFunctionCall("OnClose")) + script_unit->DoFunctionCall(0); + + // Drop content. + file_path.Clear(); + + // Drop all layer/instance/scene. + layer_list.Clear(); + instance_list.Clear(); + + flags = 0; + + script_unit->Close(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ProjectLayer *Project::AddLayer(ProjectSceneInstance *scene, float zorder) +{ + ProjectLayer *layer = new ProjectLayer(scene, zorder); + if (!layer) + __ERR__(__LOG_E__ << "Failed to allocate a new project scene layer.\n", NULL) + layer_list.Add(layer); + return layer; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ProjectSceneInstance *Project::Instantiate(GS::S3D::Scene *scene) +{ + ProjectSceneInstance *inst = new ProjectSceneInstance(scene); + if (inst) + instance_list.Add(inst); + return inst; +} +ProjectSceneInstance *Project::Instantiate(GS::S2D::Scene *scene) +{ + ProjectSceneInstance *inst = new ProjectSceneInstance(scene); + if (inst) + instance_list.Add(inst); + return inst; +} +ProjectSceneInstance *Project::Instantiate(const char *name) +{ + __PROJECT_ACTION_SAFETY_CHECK(NULL) + + // Scene is already instantiated. + ProjectSceneInstance *inst = FindSceneInstance(name); + if (inst) + return inst; + + // Create new instance. + NML::File file; + if (!NML::Parser::Load(name, file)) + __ERR__(__LOG_E__ << "Could not instantiate scene '" << name << "', file not found.\n", NULL) + + // Scene 3d + if (file.GetTag("Scene;")) + { + S3D::Scene *scene = new S3D::Scene(vm); + if (!scene) + __ERR__(__LOG_E__ << " Failed to allocate scene object.\n", NULL) + scene->SetClock(clock); + + if ((inst = new ProjectSceneInstance(scene)) == NULL) + { + _safe_delete(scene); + __ERR__(__LOG_E__ << " Failed to allocate project scene instance.\n", NULL) + } + + scene->Create(iproject_factory->NewPhysicWorld()); + NML::LoadFromFile(*scene, file); + scene->name = name; + scene->InstanceSetup(); + scene->RenderSetup(factories); + scene->SetAsScriptGlobalScene(); + scene->Setup(NoTool); + scene->Reset(); + } + else if (file.GetTag("UIScene;")) + { + S2D::Scene *scene = new S2D::Scene(vm); + if (!scene) + __ERR__(__LOG_E__ << " Failed to allocate scene 2D object.\n", NULL) + scene->SetClock(clock); + + if ((inst = new ProjectSceneInstance(scene)) == NULL) + { + _safe_delete(scene); + __ERR__(__LOG_E__ << " Failed to allocate project scene instance.\n", NULL) + } + + NML::LoadFromFile(*scene, file); + scene->name = name; + scene->RenderSetup(factories); + scene->SetAsScriptGlobalScene(); + scene->Setup(); + scene->Reset(); + } + + if (inst) + instance_list.Append(inst); + return inst; +} +void Project::Delete(ProjectSceneInstance *inst) +{ + __PROJECT_ACTION_SAFETY_CHECK_RAW + if (!inst) + return; + + // Callback. + if (script_unit->SetupFunctionCall("OnUnloadScene")) + { + script_unit->PushFunctionCallArgument(Script::Variant((void *)inst, Script::typetag_ProjectScene)); + script_unit->DoFunctionCall(0); + } + + // Drop scene from all layers using it. + ListForeachPtr(ProjectLayer *, layer, layer_list) + if (layer->inst == inst) + layer_list.Remove(layer); + + instance_list.Remove(inst); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Project::Project(ResourceFactories *f, GS::IFontFactory *ff, GS::Script::IVM *_vm) : vm(_vm) +{ + factories = f; + + name = "New Project"; + + authors = "Authors"; + description = "New project"; + company = "Empty Notice"; + + clock = new Clock; + + font_cache = new FontCache(ff); + font_cache->LoadFont("@core/default.ttf"); + + script_unit = new ProjectScriptUnit(vm); + script_unit->SetInterfaceObject(this, Script::typetag_Project); + + prohibit_project_action = false; +} +Project::~Project() +{ + Close(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/project/project_nml.cpp b/include/engine/project/project_nml.cpp new file mode 100644 index 0000000..9f29f47 --- /dev/null +++ b/include/engine/project/project_nml.cpp @@ -0,0 +1,78 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "project/project.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::Core; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool Project::FromMetaTag(Tag &tag) +{ + if (tag.name != "Environment") + __ERR__(__LOG_E__ << "Could not parse project, incorrect root tag (" << tag.name << ").\n", false) + + name.Clear(); + search_path.Clear(); + root_script_list.Clear(); + + NMLTagForeach(t, tag) + { + if (t->name == "Name") name = t->GetString(); + else if (t->name == "Authors") authors = t->GetString(); + else if (t->name == "Description") description = t->GetString(); + else if (t->name == "Copyright") company = t->GetString(); + else if (t->name == "Company") company = t->GetString(); + + else if (t->name == "Include") + { + NMLTagForeach(st, *t) + if (st->name == "URI") + root_script_list.Add(st->GetString()); + } + else if (t->name == "SearchPaths") + { + NMLTagForeach(path, *t) + if (path->GetType() == GS::Variant::VariantString) + search_path.Add(path->GetString()); + } + else if (t->name == "ScriptUnit") + script_unit->FromMetaTag(*t); + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Project::AsMetaTag() const +{ + Tag *root = new Tag("Environment"); + if (!root) + __ERR__(__LOG_E__ << "Could not create project root tag to serialize.\n", NULL) + + root->AddChild("Name", name.c_str()); + root->AddChild("Authors", authors.c_str()); + root->AddChild("Description", description.c_str()); + root->AddChild("Company", company.c_str()); + + root->AddChild(script_unit->AsMetaTag()); + + // Save includes. + if (Tag *include_tag = root->AddChild("Include")) + for (uint n = 0; n < root_script_list.GetCount(); ++n) + include_tag->AddChild("URI", root_script_list.ObjectAt(n).c_str()); + + // Save search paths. + if (Tag *path_section = root->AddChild("SearchPaths")) + for (uint n = 0; n < search_path.GetCount(); ++n) + path_section->AddChild("Path", search_path.ObjectAt(n).c_str()); + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/project/project_profiler.cpp b/include/engine/project/project_profiler.cpp new file mode 100644 index 0000000..82cd195 --- /dev/null +++ b/include/engine/project/project_profiler.cpp @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "project/project.h" + #include "scene3d/scene.h" + #include "ui/ui.h" + #include "core/renderer.h" + + using namespace GS::Core; + using namespace GS::Render; + + +//------------------------------------------------------------------------------ +void Project::DrawProfilerText(Renderer &render, RasterFont *font[2], float &x, float &y) +{ + render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + render.SetViewMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + render.SetProjectionMatrix(Matrix4::IdentityMatrix()); + + Color title_color(1, 0.8f, 0); + Renderer::WriterConfig config(false); + + // Output layer stack. + render.Write(*font[1], String::Format("Scene list (%d instantiated, %d active):\n\n", GetInstanceCount(), GetActiveCount()), x, y, config, 1, &title_color); + render.Write(*font[1], "Layer stack:", x, y, config, 1, &Color::White); + + for (uint n = layer_list.GetCount(); n > 0; --n) + { + ProjectLayer *layer = layer_list.ObjectAt(n - 1); + render.Write(*font[0], String::Format(" -> %s\n", layer->inst ? layer->inst->GetPath().c_str() : "No Instance"), x, y, config, 1, &title_color); + } + render.Write(*font[0], "\n", x, y, config); + + // Output scene details. + x += 16; + + ListForeachPtr(ProjectSceneInstance *, inst, instance_list) + if (IsActive(*inst)) + { + render.Write(*font[0], String::Format("Scene instance '%s':\n\n", inst->GetPath().c_str()), x, y, config, 1, &Color::White); + + switch (inst->GetType()) + { + case ProjectSceneInstance::Type_Scene2d: + inst->instance_2d->DrawProfilerText(render, font, x, y); + break; + + case ProjectSceneInstance::Type_Scene3d: + inst->instance_3d->DrawProfilerText(render, font, x, y); + break; + } + } + + x -= 16; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/project/project_runtime.cpp b/include/engine/project/project_runtime.cpp new file mode 100644 index 0000000..5f93d1b --- /dev/null +++ b/include/engine/project/project_runtime.cpp @@ -0,0 +1,121 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "project/project.h" + #include "scene3d/scene.h" + #include "ui/ui.h" + #include "core/renderer.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + + using namespace GS::Core; + using namespace GS::Script; + + +static float CompareLayerZOrder(const ProjectLayer *c, const ProjectLayer *n) { return c->zorder - n->zorder; } + +//------------------------------------------------------------------------------ +void Project::Render(Renderer &renderer, RenderFlag render_flag) +{ + __PROJECT_ACTION_SAFETY_CHECK_RAW + + bool send_events = render_flag & FlagDisableScript ? false : true; + + // Sort the layer list. + layer_list.Sort(CompareLayerZOrder); + + // OnRender callback. + if (script_unit->SetupFunctionCall("OnRender")) + script_unit->DoFunctionCall(); + + // Render the layer display list. + int active_layer = 0; + + ListForeachPtr(ProjectLayer *, layer, layer_list) + if (layer->inst && IsActive(*layer->inst)) + { + // OnRenderScene callback. + if (send_events && script_unit->SetupFunctionCall("OnRenderScene")) + { + switch (layer->inst->GetType()) + { + case ProjectSceneInstance::Type_Scene2d: + script_unit->PushFunctionCallArgument(Script::Variant(layer->inst->instance, typetag_Scene2d)); + break; + + case ProjectSceneInstance::Type_Scene3d: + script_unit->PushFunctionCallArgument(Script::Variant(layer->inst->instance, typetag_Scene3d)); + break; + } + script_unit->PushFunctionCallArgument(Script::Variant(layer, typetag_ProjectLayer)); + script_unit->DoFunctionCall(); + } + + // Specialized rendering. + prohibit_project_action = true; + + switch (layer->inst->GetType()) + { + case ProjectSceneInstance::Type_Scene2d: + { + GS::S2D::Scene *scene = layer->inst->instance_2d; + + if (active_layer == 0) + renderer.Clear(0, 0, 0); + scene->Render(renderer); + } + break; + + case ProjectSceneInstance::Type_Scene3d: + { + GS::S3D::Scene *scene = layer->inst->instance_3d; + + scene->flags.Raise(S3D::Scene::FlagDebugPhysics, flags.IsSet(ProjectFlagDebugPhysics)); // synchronize scene flag with project one + scene->Render(renderer); + scene->RenderUI(renderer); + } + break; + } + prohibit_project_action = false; + + ++active_layer; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Project::Update(uint eval_flag) +{ + __PROJECT_ACTION_SAFETY_CHECK_RAW + + // OnUpdate callback. + if (script_unit->SetupFunctionCall("OnUpdate", script_unit->update_callback)) + script_unit->DoFunctionCall(); + + // Evaluate all instantiated scenes. + prohibit_project_action = true; + + ListForeachPtr(ProjectSceneInstance *, inst, instance_list) + if (IsActive(*inst)) + switch (inst->GetType()) + { + case ProjectSceneInstance::Type_Scene2d: + if (inst->instance_2d) + inst->instance_2d->Update(); + break; + + case ProjectSceneInstance::Type_Scene3d: + if (inst->instance_3d) + { + inst->instance_3d->SetAsScriptGlobalScene(); + inst->instance_3d->Update(eval_flag); + } + break; + } + + prohibit_project_action = false; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/project/project_scene.cpp b/include/engine/project/project_scene.cpp new file mode 100644 index 0000000..d4bca7c --- /dev/null +++ b/include/engine/project/project_scene.cpp @@ -0,0 +1,62 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "project/project.h" + #include "scene3d/scene.h" + #include "ui/ui.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +void Project::Activate(ProjectSceneInstance &inst, bool activate) +{ + // Callback to project. + if (script_unit->SetupFunctionCall("OnActivateScene")) + { + script_unit->PushFunctionCallArgument(Script::Variant(&inst, Script::typetag_ProjectScene)); + script_unit->DoFunctionCall(); + } + + // Set flag. + inst.active = activate; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +GS::String ProjectSceneInstance::GetPath() const +{ + if (instance) + switch (GetType()) + { + case Type_Scene2d: return instance_2d->name; break; + case Type_Scene3d: return instance_3d->name; break; + } + return "Empty"; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void ProjectSceneInstance::Free() +{ + if (instance_2d) + { + instance_2d->SetAsScriptGlobalScene(); + _safe_delete(instance_2d); + } + if (instance_3d) + { + instance_3d->SetAsScriptGlobalScene(); + _safe_delete(instance_3d); + } +} +ProjectSceneInstance::~ProjectSceneInstance() +{ + Free(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/project/project_script.cpp b/include/engine/project/project_script.cpp new file mode 100644 index 0000000..55cbe58 --- /dev/null +++ b/include/engine/project/project_script.cpp @@ -0,0 +1,34 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "project/project.h" + #include "script/script_variant.h" + #include "script/script_vm.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +void Project::UpdateScriptClock() +{ + vm->Set("g_dt_frame", clock->GetDeltaf()); + vm->Set("g_clock", (float)clock->Get()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Project::CompileRootScripts() +{ + if (!vm) + return false; + + ListForeach(String, p, root_script_list) + if (!vm->CompileFile(p.Object())) + return false; + + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/project/project_script_unit.cpp b/include/engine/project/project_script_unit.cpp new file mode 100644 index 0000000..8144424 --- /dev/null +++ b/include/engine/project/project_script_unit.cpp @@ -0,0 +1,34 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "project/project_script_unit.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +bool ProjectScriptUnit::Open() +{ + if (!Unit::Open()) + return false; + + setup_callback = vm->GetObjectFromName("OnSetup", self); + update_callback = vm->GetObjectFromName("OnUpdate", self); + return true; +} +void ProjectScriptUnit::Close() +{ + setup_callback = NULL; + update_callback = NULL; + + Unit::Close(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ProjectScriptUnit::ProjectScriptUnit(GS::Script::IVM *vm) : Script::Unit(vm) {} +ProjectScriptUnit::~ProjectScriptUnit() { Close(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/group.cpp b/include/engine/scene3d/group.cpp new file mode 100644 index 0000000..c782769 --- /dev/null +++ b/include/engine/scene3d/group.cpp @@ -0,0 +1,189 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/group.h" + #include "scene3d/mitem.h" + #include "motion/motion_automation_source.h" + #include "automation/automation_source_group.h" + + using namespace GS::Core; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool Group::AppendGroup(const Group &group) +{ + ListForeachPtr(MItem *, i, group.item_list) + if (!Add(i)) + return false; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Group::SetInvisible(bool v) +{ + ListForeachPtr(MItem *, i, item_list) + i->GetBaseItem()->item_flags.Raise(ItemFlagInvisible, v); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Group::IsMember(const MItem *i) const +{ + ListForeachPtr(MItem *, item, item_list) + if (item == i) + return true; + return false; +} +bool Group::IsMember(const Group *g) const +{ + ListForeachPtr(Group *, group, group_list) + if (group == g) + return true; + return false; +} +void Group::SetRootItem(MItem *i) +{ + if (root) + if (Core::Item *base_root = root->GetBaseItem()) + ListForeachPtr(MItem *, item, item_list) + if (Core::Item *b = item->GetBaseItem()) + if (b->GetParent() == base_root) + b->SetParent(NULL); + + ListForeachPtr(MItem *, item, item_list) + if (Core::Item *b = item->GetBaseItem()) + if (!b->GetParent()) + b->SetParent(i ? i->GetBaseItem() : NULL); + + root = i; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Group::Offset(const GS::Matrix4 &m) +{ + ListForeachPtr(MItem *, item, item_list) + if (Core::Item *b = item->GetBaseItem()) + if (!b->GetParent()) + b->SnapshotTransformation(m * b->GetMatrix()); +} +void Group::Translate(float x, float y, float z) +{ + Vector4 translation(x, y, z); + ListForeachPtr(MItem *, item, item_list) + if (Core::Item *b = item->GetBaseItem()) + if (!b->GetParent()) + b->SetPosition(b->GetPosition() + translation); +} +void Group::Rotate(float x, float y, float z) +{ + Vector4 rotation(x, y, z); + ListForeachPtr(MItem *, item, item_list) + if (Core::Item *b = item->GetBaseItem()) + if (!b->GetParent()) + b->SetRotation(b->GetRotation() + rotation); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MItem *Group::Item(const char *item_id) const +{ + String seek(item_id); + ListForeachPtr(MItem *, item, item_list) + if (item->name == seek) + return item; + __ERR__(__LOG_W__ << "No item '" << item_id << "' in group '" << name << "'.\n", NULL) +} +MItem *Group::ItemFromUid(uint uid) const +{ + ListForeachPtr(MItem *, item, item_list) + if (item->GetUid() == uid) + return item; + __ERR__(__LOG_W__ << "No item with uid '" << uid << "' in group '" << name << "'.\n", NULL) +} +Group *Group::GetGroup(const char *_name) const +{ + ListForeachPtr(Group *, group, group_list) + if (group->name == _name) + return group; + __ERR__(__LOG_W__ << "Could not find group '" << _name << "' in group '" << name << "'.\n", NULL) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MItem *Group::Add(MItem *i, bool block_duplicate) +{ + if (!i || (block_duplicate && IsMember(i))) + return NULL; + + item_list.Add(i); + return i; +} +bool Group::Remove(MItem *i) +{ + return item_list.Remove(i); +} +Group *Group::Add(Group *g, bool block_duplicate) +{ + if (!g || (block_duplicate && IsMember(g))) + return NULL; + + group_list.Add(g); + return g; +} +bool Group::Remove(Group *g) +{ return group_list.Remove(g); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Group::RenderSetup(GS::Core::ResourceFactories *f) +{ + ListForeachPtr(MItem *, i, item_list) + if (Core::Item *b = i->GetBaseItem()) + b->RenderSetup(f); +} +void Group::Setup() +{ + ListForeachPtr(MItem *, i, item_list) + i->Setup(NULL); +} +void Group::Reset() +{ + ListForeachPtr(MItem *, i, item_list) + i->Reset(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Group::SetMotion(const char *name, GS::Automation::SourceGroup **group, float blend, GS::Automation::Player::AddSourceMode mode, float weight) +{ + if (group) + *group = new Automation::SourceGroup; + + SceneMotion *scene_motion = NULL; + + ListForeachPtr(SceneMotion *, m, motion.motions) + if (m->name == name) + { + scene_motion = m; + break; + } + + if (scene_motion) + { + // Start item motions. + ListForeachPtr(SceneMotion::ItemMotion *, m, scene_motion->item_motions) + if (MItem *i = ItemFromUid(m->uid)) + i->automation_player->StartAutomation(new Automation::MotionSource(m->motion, group ? *group : NULL), blend, mode, weight); + } + else + ListForeachPtr(MItem *, i, item_list) + if (Motion *motion = i->automation_player->GetMotion(name)) + i->automation_player->StartAutomation(new Automation::MotionSource(motion, *group), blend, mode, weight); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/instance.cpp b/include/engine/scene3d/instance.cpp new file mode 100644 index 0000000..dd88580 --- /dev/null +++ b/include/engine/scene3d/instance.cpp @@ -0,0 +1,97 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/instance.h" + #include "scene3d/mobject.h" + #include "scene3d/group.h" + #include "scene3d/scene.h" + #include "script/scripted_object.h" + + using namespace GS::Core; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void Instance::RenderSetup(ResourceFactories *f) +{ + if (instance_group) + instance_group->RenderSetup(f); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Instance::ComputeMinMax(GS::MinMax &minmax) const +{ + if (!instance_group) + return; + + MinMax l_minmax; + const SharedList &items = instance_group->GetItemList(); + + bool first = true; + ListForeachPtr(MItem *, i, items) + if (i->GetItemType() == Type_Object) + { + MObject *o = (MObject *)i; + o->ComputeLocalMinMax(l_minmax); + + if (first) + minmax = l_minmax; + else minmax.Grow(l_minmax); + first = false; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Instance::Instantiate(Scene *owner) +{ + if (instance_group) + return true; + if (!owner || template_path.IsEmpty() || !isActive()) + return false; + + using namespace NML; + File file; + if (Parser::Load(template_path, file)) + { + // Load scene scripted object on this instance. + if (Tag *script_tag = file.GetTag("Scene:ScriptedObject;")) + scripted_object->FromMetaTag(*script_tag); + + // Append template scene to this scene. + owner->FromMetaFileStoreGroup(template_path, &instance_group, SceneIOAll & ~(SceneIOGlobals | SceneIOSettings | SceneIOHelper | SceneIOScript)); + } + + if (instance_group) + { + instance_group->name = template_path; + + if (do_not_parent) + instance_group->Offset(GetMatrix()); + else instance_group->SetRootItem(this); + } + return true; +} +void Instance::FreeEditorInstance() +{ + instance_scene = NULL; + instance_group = NULL; +} +//------------------------------------------------------------------------------ + +Instance::Instance() +{ + item_type = Type_Instance; + mitem = (void *)((MItem *)this); + + instance_group = NULL; + do_not_parent = false; +} +Instance::~Instance() +{ + // group is deleted by the scene it belongs to. +} diff --git a/include/engine/scene3d/instance_nml.cpp b/include/engine/scene3d/instance_nml.cpp new file mode 100644 index 0000000..28a01fe --- /dev/null +++ b/include/engine/scene3d/instance_nml.cpp @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/instance.h" + #include "log/log.h" + + using namespace GS::NML; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool Instance::FromMetaTag(Tag &tag) +{ + if (tag.name != "Instance") + __ERR__(__LOG_E__ << "Could not parse instance, incorrect root tag (" << tag.name << ").\n", false) + + do_not_parent = false; + + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") + MItem::FromMetaTag(*pt); + else if (pt->name == "Item") + Item::FromMetaTag(*pt); + + else if (pt->name == "Template") + template_path = pt->GetString(); + else if (pt->name == "DoNotParent") + do_not_parent = pt->GetBool(); + + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *Instance::AsMetaTag() +{ + Tag *root = new Tag("Instance"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(Item::AsMetaTag()); + + root->AddChild("Template", template_path); + if (do_not_parent) + root->AddChild("DoNotParent", do_not_parent); + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/item_automated_property_provider.cpp b/include/engine/scene3d/item_automated_property_provider.cpp new file mode 100644 index 0000000..3b641ab --- /dev/null +++ b/include/engine/scene3d/item_automated_property_provider.cpp @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/item_automated_property_provider.h" + #include "core/item.h" + + using GS::Quaternion; + using namespace GS::Core; + using namespace GS::S3D::Automation; + + +//------------------------------------------------------------------------------ +bool ItemPropertyProvider::GetProperty(MotionChannel::Type type, float &v) +{ + switch (type) + { + case MotionChannel::XPos: v = item->GetPosition().x; return true; + case MotionChannel::YPos: v = item->GetPosition().y; return true; + case MotionChannel::ZPos: v = item->GetPosition().z; return true; + case MotionChannel::XRot: v = item->GetRotation().x; return true; + case MotionChannel::YRot: v = item->GetRotation().y; return true; + case MotionChannel::ZRot: v = item->GetRotation().z; return true; + case MotionChannel::XScl: v = item->GetScale().x; return true; + case MotionChannel::YScl: v = item->GetScale().y; return true; + case MotionChannel::ZScl: v = item->GetScale().z; return true; + } + return false; +} +bool ItemPropertyProvider::SetProperty(MotionChannel::Type type, float v) +{ + Vector4 t; + switch (type) + { + case MotionChannel::XPos: t = item->GetPosition(); t.x = v; item->SetPosition(t); return true; + case MotionChannel::YPos: t = item->GetPosition(); t.y = v; item->SetPosition(t); return true; + case MotionChannel::ZPos: t = item->GetPosition(); t.z = v; item->SetPosition(t); return true; + case MotionChannel::XRot: t = item->GetRotation(); t.x = v; item->SetRotation(t); return true; + case MotionChannel::YRot: t = item->GetRotation(); t.y = v; item->SetRotation(t); return true; + case MotionChannel::ZRot: t = item->GetRotation(); t.z = v; item->SetRotation(t); return true; + case MotionChannel::XScl: t = item->GetScale(); t.x = v; item->SetScale(t); return true; + case MotionChannel::YScl: t = item->GetScale(); t.y = v; item->SetScale(t); return true; + case MotionChannel::ZScl: t = item->GetScale(); t.z = v; item->SetScale(t); return true; + } + return false; +} +Quaternion ItemPropertyProvider::GetRotation() const +{ + const Vector4 &e = item->GetRotation(); + return Quaternion::FromEuler(e.x, e.y, e.z, item->GetRotationOrder()); +} +bool ItemPropertyProvider::SetRotation(const Quaternion &q) +{ + item->SetRotation(q); + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mcamera.cpp b/include/engine/scene3d/mcamera.cpp new file mode 100644 index 0000000..da6cefa --- /dev/null +++ b/include/engine/scene3d/mcamera.cpp @@ -0,0 +1,19 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mcamera.h" + #include "scene3d/scene_message.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +MCamera::MCamera() +{ + item_type = Type_Camera; + mitem = (void *)((MItem *)this); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mcamera_nml.cpp b/include/engine/scene3d/mcamera_nml.cpp new file mode 100644 index 0000000..534ca3d --- /dev/null +++ b/include/engine/scene3d/mcamera_nml.cpp @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mcamera.h" + #include "log/log.h" + + using namespace GS::NML; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool MCamera::FromMetaTag(Tag &tag) +{ + if (tag.name != "MCamera") + __ERR__(__LOG_E__ << "Could not parse managed camera, incorrect root tag (" << tag.name << ").\n", false) + + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") + MItem::FromMetaTag(*pt); + else if (pt->name == "Camera") + Camera::FromMetaTag(*pt); + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *MCamera::AsMetaTag() +{ + Tag *root = new Tag("MCamera"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(Camera::AsMetaTag()); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mconstraint.cpp b/include/engine/scene3d/mconstraint.cpp new file mode 100644 index 0000000..88dd1b2 --- /dev/null +++ b/include/engine/scene3d/mconstraint.cpp @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mconstraint.h" + #include "physic/physic_constraint.h" + #include "physic/physic_world.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +void MConstraint::Setup(PhysicWorld *world) +{ + if (world) + { + physic_data = world->NewConstraint(); + physic_data->SetupConstraint(desc); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool MConstraint::FromMetaTag(Tag &tag) +{ + if (tag.name != "MConstraint") + __ERR__(__LOG_E__ << "Could not parse managed constraint, incorrect root tag (" << tag.name << ").\n", false) + + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") + MItem::FromMetaTag(*pt); + else if (pt->name == "Constraint") + desc.FromMetaTag(*pt); + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *MConstraint::AsMetaTag() +{ + Tag *root = new Tag("MConstraint"); + if (!root) + __ERR__(__LOG_E__ << "Could not create managed constraint tag to serialize.\n", NULL) + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(desc.AsMetaTag()); + + return root; +} +//------------------------------------------------------------------------------ + +MConstraint::MConstraint(PhysicConstraint *c) : physic_data(c) +{ + item_type = Type_Constraint; +} diff --git a/include/engine/scene3d/memitter.cpp b/include/engine/scene3d/memitter.cpp new file mode 100644 index 0000000..2a6f7d1 --- /dev/null +++ b/include/engine/scene3d/memitter.cpp @@ -0,0 +1,31 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/memitter.h" + #include "scene3d/scene_message.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void MEmitter::Update(const GS::Time &dt) +{ + Emitter::Update(dt); + MItem::Update(dt); +} +void MEmitter::Setup(PhysicWorld *) +{ + Emitter::Setup(); + MItem::Setup(NULL); +} +//------------------------------------------------------------------------------ + +MEmitter::MEmitter() +{ + item_type = Type_Emitter; + mitem = (void *)((MItem *)this); + priority = 1; +} diff --git a/include/engine/scene3d/memitter_nml.cpp b/include/engine/scene3d/memitter_nml.cpp new file mode 100644 index 0000000..7f3862c --- /dev/null +++ b/include/engine/scene3d/memitter_nml.cpp @@ -0,0 +1,39 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/memitter.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool MEmitter::FromMetaTag(Tag &tag) +{ + if (tag.name != "MEmitter") + __ERR__(__LOG_E__ << "could not parse managed emitter, incorrect root tag (" << tag.name << ").\n", false) + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") MItem::FromMetaTag(*pt); + else if (pt->name == "Emitter") Emitter::FromMetaTag(*pt); + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *MEmitter::AsMetaTag() +{ + Tag *root = new Tag("MEmitter"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(Emitter::AsMetaTag()); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mitem.cpp b/include/engine/scene3d/mitem.cpp new file mode 100644 index 0000000..9c43d4f --- /dev/null +++ b/include/engine/scene3d/mitem.cpp @@ -0,0 +1,150 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mitem.h" + #include "scene3d/mterrain.h" + #include "scene3d/scene_ace_manager.h" + #include "scene3d/item_automated_property_provider.h" + #include "scene3d/mitem_event_interface.h" + #include "scene3d/mitem_scripted_object.h" + #include "scene3d/scene_message.h" + #include "automation/automation_player.h" + #include "script/script_engine_types.h" + #include "rand/rand.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool MItem::ExecCommand(GS::ACE::Command *cmd, float dt) +{ + float k = dt / cmd->duration_left; + Core::Item *i = GetBaseItem(); + + switch (cmd->code) + { + case ACESN_toposition: + i->SetPosition(i->GetPosition() + (Vector4(cmd->parm[0], cmd->parm[1], cmd->parm[2]) - i->GetPosition()) * k); + return true; + + case ACESN_tooffset: + { + Matrix4 offset = i->GetPivot(); + offset.m[0][3] += (cmd->parm[0] - offset.m[0][3]) * k; + offset.m[1][3] += (cmd->parm[1] - offset.m[1][3]) * k; + offset.m[2][3] += (cmd->parm[2] - offset.m[2][3]) * k; + i->SetPivot(offset); + } + return true; + + case ACESN_offsetposition: + k = dt / cmd->duration; + i->SetPosition(i->GetPosition() + Vector4(cmd->parm[0], cmd->parm[1], cmd->parm[2]) * k); + return true; + + case ACESN_toscale: + i->SetScale(i->GetScale() + (Vector4(cmd->parm[0], cmd->parm[1], cmd->parm[2]) - i->GetScale()) * k); + return true; + + case ACESN_torotation: + i->SetRotation(i->GetRotation() + (Vector4(Units::Deg(cmd->parm[0]), Units::Deg(cmd->parm[1]), Units::Deg(cmd->parm[2])) - i->GetRotation()) * k); + return true; + + case ACESN_toalpha: + i->opacity = Types::Clamp(i->opacity + Types::Clamp(i->opacity + (cmd->parm[0] - i->opacity) * k)); + return true; + } + return ACE::Unit::ExecCommand(cmd, dt); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void MItem::SetInitialTransformation() +{ + // Note: We do not want to snapshot the pivot here. + initial_matrix = GetBaseItem()->GetPivot().InversedFast() * GetBaseItem()->GetLocalMatrix(); + initial_state_set = true; +} +void MItem::ResetToInitialTransformation() +{ + if (initial_state_set) + GetBaseItem()->SnapshotTransformation(initial_matrix, true); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void MItem::Update(const GS::Time &dt) +{ + automation_player->Evaluate(dt); + ACEManager::Get()->UpdateACEUnit(this, dt.toSec()); +} +void MItem::Setup(PhysicWorld *physic_world) +{ + item_event->OnSetup(this); + + // [EJ] must be done here for the time being as MItem base class cannot resolve the Item class. + if (automation_player->property_provider.IsNull()) + automation_player->property_provider = new Automation::ItemPropertyProvider(GetBaseItem()); + + // Setup physics. + if (physic_world && physic_item) + { + if (GetItemType() == MTerrain::GetMItemClassType()) + if (MTerrain *t = (MTerrain *)this) + { + // If the terrain physic item has an heightmap shape, link it to our heightmap. + ListForeachPtr(PhysicShape *, shape, physic_item_desc.shape_list) + if (shape->GetType() == PhysicShape::TypeHeightmap) + shape->Set(t->GetHeightmap(), t->GetHeightmapPitch(), t->GetHeightmapHeight(), t->GetUnit()); + } + + physic_item->SetScale(GetBaseItem()->GetScale()); + physic_item->SetupBody(physic_item_desc, physic_world); + } + + item_event->OnSetupDone(this); +} + +void MItem::ForceUpdateMassShapePhysic(PhysicWorld *physic_world) +{ + // update mass physics. + if (physic_world && physic_item) + { + physic_item->ForceUpdateMassShapePhysic(physic_item_desc, physic_world); + } +} + + +void MItem::Reset() +{ + item_event->OnReset(this); + + // Update matrix. + if (physic_item) + { + physic_item->ResetBody(); + physic_item->SetMatrix(GetBaseItem()->GetMatrix()); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MItem::MItem() +{ + uid = uint(~0); + + global_alpha = 1.f; + mitem_flags.Set(Flag_IsActive); + + initial_state_set = false; + initial_matrix = Matrix4::IdentityMatrix(); + + priority = 0.5; + + item_event = new IItemEvent; + automation_player = new GS::Automation::Player; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mitem_event_script_interface.cpp b/include/engine/scene3d/mitem_event_script_interface.cpp new file mode 100644 index 0000000..1523d0f --- /dev/null +++ b/include/engine/scene3d/mitem_event_script_interface.cpp @@ -0,0 +1,195 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mitem_event_script_interface.h" + #include "scene3d/mitem_scripted_object.h" + #include "scene3d/mitem_script_unit.h" + #include "scene3d/mtrigger.h" + #include "physic/physic_world.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void MItemScriptEvent::OnSetup(MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnSetup")) + unit->DoFunctionCall(); +} +void MItemScriptEvent::OnSetupDone(MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnSetupDone")) + unit->DoFunctionCall(); +} +void MItemScriptEvent::OnReset(MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnReset")) + unit->DoFunctionCall(); +} +void MItemScriptEvent::OnActivate(MItem *item, bool activate) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((MItemScriptUnit *)unit)->activation_callback && unit->SetupFunctionCall("OnActivate", ((MItemScriptUnit *)unit)->activation_callback)) + { + unit->PushFunctionCallArgument(activate); + unit->DoFunctionCall(); + } +} +void MItemScriptEvent::OnUpdate(MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((MItemScriptUnit *)unit)->update_callback && unit->SetupFunctionCall("OnUpdate", ((MItemScriptUnit *)unit)->update_callback)) + unit->DoFunctionCall(); +} +void MItemScriptEvent::OnPhysicStep(MItem *item, bool step_taken) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((MItemScriptUnit *)unit)->physic_callback && unit->SetupFunctionCall("OnPhysicStep", ((MItemScriptUnit *)unit)->physic_callback)) + { + unit->PushFunctionCallArgument(step_taken); + unit->DoFunctionCall(); + } +} +void MItemScriptEvent::OnCollision(MItem *item, MItem *with, const CollisionPair &pair) +{ + if (!item->isActive()) + return; + + IVM *vm = item->scripted_object->GetVM(); + + // Check if the contact informations will be needed. + bool contact_info_required = false; + + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((MItemScriptUnit *)unit)->collisionex_callback.IsValid()) + { contact_info_required = true; break; } + + if (contact_info_required) + { + AutoPtr table_object(vm->CreateTable()); + table_object->Set("count", pair.contact_count); + + // Contact point. + AutoPtr ctc_object(vm->CreateArray()); + for (uint n = 0; n < pair.contact_count; ++n) + if (vm->SetupFunctionCall("Vector")) + { + vm->PushArgument(pair.contact[n].x); + vm->PushArgument(pair.contact[n].y); + vm->PushArgument(pair.contact[n].z); + Script::Variant rv; + vm->DoFunctionCall(&rv); + ctc_object->Append(rv); + } + + table_object->Set("p", ctc_object.c_ptr()); + + // Contact normal. + AutoPtr nrm_object(vm->CreateArray()); + for (uint n = 0; n < pair.contact_count; ++n) + if (vm->SetupFunctionCall("Vector")) + { + vm->PushArgument(pair.normal[n].x); + vm->PushArgument(pair.normal[n].y); + vm->PushArgument(pair.normal[n].z); + Script::Variant rv; + vm->DoFunctionCall(&rv); + nrm_object->Append(rv); + } + + table_object->Set("n", nrm_object.c_ptr()); + + // Call each unit. + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnCollisionEx", ((MItemScriptUnit *)unit)->collisionex_callback)) + { + unit->PushUserObjectFunctionCallArgument(with, typetag_Item); + unit->PushFunctionCallArgument(table_object.c_ptr()); + unit->PushFunctionCallArgument(true); + unit->DoFunctionCall(); + } + } + + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((MItemScriptUnit *)unit)->collision_callback && unit->SetupFunctionCall("OnCollision", ((MItemScriptUnit *)unit)->collision_callback)) + { + unit->PushUserObjectFunctionCallArgument((void *)with, typetag_Item); + unit->DoFunctionCall(); + } +} + +void MItemScriptEvent::OnItemEnter(MTrigger *trigger, MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnItemEnter")) + { + unit->PushUserObjectFunctionCallArgument((void *)item, typetag_Item); + unit->DoFunctionCall(); + } +} +void MItemScriptEvent::OnItemExit(MTrigger *trigger, MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnItemExit")) + { + unit->PushUserObjectFunctionCallArgument((void *)item, typetag_Item); + unit->DoFunctionCall(); + } +} + +void MItemScriptEvent::OnEnterTrigger(MItem *item, MTrigger *trigger) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnEnterTrigger")) + { + unit->PushUserObjectFunctionCallArgument((void *)((MItem *)trigger), typetag_Item); + unit->DoFunctionCall(); + } +} +void MItemScriptEvent::OnTrigger(MItem *item, MTrigger *trigger) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnTrigger")) + { + unit->PushUserObjectFunctionCallArgument((void *)((MItem *)trigger), typetag_Item); + unit->DoFunctionCall(); + } +} +void MItemScriptEvent::OnExitTrigger(MItem *item, MTrigger *trigger) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnExitTrigger")) + { + unit->PushUserObjectFunctionCallArgument((void *)((MItem *)trigger), typetag_Item); + unit->DoFunctionCall(); + } +} + +void MItemScriptEvent::OnRenderDone(MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnRenderDone")) + unit->DoFunctionCall(); +} +void MItemScriptEvent::OnRenderUser(MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((MItemScriptUnit *)unit)->render_user_callback && unit->SetupFunctionCall("OnRenderUser", ((MItemScriptUnit *)unit)->render_user_callback)) + unit->DoFunctionCall(); +} +void MItemScriptEvent::OnDelete(MItem *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnDelete")) + unit->DoFunctionCall(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mitem_nml.cpp b/include/engine/scene3d/mitem_nml.cpp new file mode 100644 index 0000000..d4c2868 --- /dev/null +++ b/include/engine/scene3d/mitem_nml.cpp @@ -0,0 +1,137 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mitem.h" + #include "scene3d/scene.h" + #include "physic/physic_world.h" + #include "core/engine.h" + #include "script/scripted_object.h" + #include "log/log.h" + + using GS::NML::Tag; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool MItem::FromMetaTag(Tag &tag) +{ + if (tag.name != "MItem") + __ERR__(__LOG_E__ << "Could not parse managed item, incorrect root tag (" << tag.name << ").\n", false) + + // Set item default state. + initial_state_set = false; + initial_matrix = Matrix4::IdentityMatrix(); + + mitem_flags.Set(0); + + uid = (uint)~0; + + NMLTagForeach(pt, tag) + { + if (pt->name == "Id") name = pt->GetString(); + else if (pt->name == "UId") uid = pt->GetUnsigned(); + + else if (pt->name == "Inactive") mitem_flags.Raise(Flag_IsActive, false); + else if (pt->name == "Static") mitem_flags.Set(Flag_IsStatic); + else if (pt->name == "Helper") mitem_flags.Set(Flag_IsHelper); + + else if (pt->name == "Billboard") mitem_flags.Set(Flag_Billboard); + else if (pt->name == "SolveOverlap") mitem_flags.Set(Flag_SolveOverlap); + else if (pt->name == "Ghost") mitem_flags.Set(Flag_Ghost); + else if (pt->name == "TriggerDetected") mitem_flags.Set(Flag_TriggerDetected); + + else if (pt->name == "InitialMatrix") + { + if (initial_matrix.FromMetaTag(*pt)) + initial_state_set = true; + } + + else if (pt->name == "Priority") + priority = pt->GetReal(); + + // Components. + else if (pt->name == "MotionPlayer") + automation_player->FromMetaTag(*pt); + else if (pt->name == "PhysicItem") + physic_item_desc.FromMetaTag(*pt); + else if (pt->name == "ScriptedObject") + { + if (scripted_object) + scripted_object->FromMetaTag(*pt); + } + +#if 1 + else if (pt->name == "Active"); + + else if (pt->name == "ScriptLogicFq"); + else if (pt->name == "TauItem"); + else if (pt->name == "GColItem"); + else if (pt->name == "ScriptUnit"); + + else if (pt->name == "Proxy"); + else if (pt->name == "ProxyScene"); + else if (pt->name == "ProxyGroup"); + else if (pt->name == "ProxyFlag"); + else if (pt->name == "ProxyRootParamTo"); + + else if (pt->name == "ToolSpecific") + mitem_flags.Set(Flag_IsHelper); +#endif + + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + if (uid == ~0) + __ERR__(__LOG_E__ << "Managed item '" << name << "' Uid is invalid.\n", false) + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *MItem::AsMetaTag() +{ + Tag *root = new Tag("MItem"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + // Id. + root->AddChild("Id", name); + root->AddChild("UId", uid); + + // Flags. + if (!mitem_flags.IsSet(Flag_IsActive)) + root->AddChild("Inactive"); + if (mitem_flags.IsSet(Flag_Billboard)) + root->AddChild("Billboard"); + if (mitem_flags.IsSet(Flag_SolveOverlap)) + root->AddChild("SolveOverlap"); + if (mitem_flags.IsSet(Flag_Ghost)) + root->AddChild("Ghost"); + if (mitem_flags.IsSet(Flag_TriggerDetected)) + root->AddChild("TriggerDetected"); + + if (mitem_flags.IsSet(Flag_IsActive)) + root->AddChild("Active"); + if (mitem_flags.IsSet(Flag_IsHelper)) + root->AddChild("Helper"); + if (mitem_flags.IsSet(Flag_IsStatic)) + root->AddChild("Static"); + + // Transformation. + if (initial_state_set) + root->AddChild(initial_matrix.AsMetaTag("InitialMatrix")); + + root->AddChild("Priority", priority); + + // Components. + root->AddChild(automation_player->AsMetaTag()); + root->AddChild(scripted_object->AsMetaTag()); + root->AddChild(physic_item_desc.AsMetaTag()); + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mitem_script_unit.cpp b/include/engine/scene3d/mitem_script_unit.cpp new file mode 100644 index 0000000..d8427f0 --- /dev/null +++ b/include/engine/scene3d/mitem_script_unit.cpp @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mitem_script_unit.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +bool MItemScriptUnit::Open() +{ + if (!Unit::Open()) + return false; + + update_callback = vm->GetObjectFromName("OnUpdate", self); + trigger_callback = vm->GetObjectFromName("OnTrigger", self); + activation_callback = vm->GetObjectFromName("OnActivate", self); + physic_callback = vm->GetObjectFromName("OnPhysicStep", self); + collision_callback = vm->GetObjectFromName("OnCollision", self); + collisionex_callback = vm->GetObjectFromName("OnCollisionEx", self); + render_user_callback = vm->GetObjectFromName("OnRenderUser", self); + return true; +} +void MItemScriptUnit::Close() +{ + update_callback = NULL; + trigger_callback = NULL; + activation_callback = NULL; + physic_callback = NULL; + physic_sleep_callback = NULL; + collision_callback = NULL; + collisionex_callback = NULL; + render_user_callback = NULL; + + Unit::Close(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MItemScriptUnit::MItemScriptUnit(IVM *vm) : Unit(vm) {} +MItemScriptUnit::~MItemScriptUnit() { Close(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mitem_scripted_object.cpp b/include/engine/scene3d/mitem_scripted_object.cpp new file mode 100644 index 0000000..d7dff6a --- /dev/null +++ b/include/engine/scene3d/mitem_scripted_object.cpp @@ -0,0 +1,26 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mitem_scripted_object.h" + #include "scene3d/mitem_script_unit.h" + #include "scene3d/mitem.h" + #include "script/script_engine_types.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +Unit *MItemScriptedObject::NewUnit() const +{ + Unit *unit = new MItemScriptUnit(vm); + if (!unit) + __ERR__(__LOG_E__ << "Failed to allocate new scene script unit.", NULL); + unit->SetInterfaceObject(item, typetag_Item); + return unit; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mlight.cpp b/include/engine/scene3d/mlight.cpp new file mode 100644 index 0000000..486177b --- /dev/null +++ b/include/engine/scene3d/mlight.cpp @@ -0,0 +1,27 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mlight.h" + #include "scene3d/scene_message.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool MLight::isActive() const +{ + if ((diffuse_intensity <= 0.01f) && (specular_intensity <= 0.01f)) + return false; + return MItem::isActive(); +} +//------------------------------------------------------------------------------ + +MLight::MLight() +{ + item_type = Type_Light; + mitem = (void *)((MItem *)this); + priority = 1.f; +} diff --git a/include/engine/scene3d/mlight_nml.cpp b/include/engine/scene3d/mlight_nml.cpp new file mode 100644 index 0000000..16c217c --- /dev/null +++ b/include/engine/scene3d/mlight_nml.cpp @@ -0,0 +1,39 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mlight.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool MLight::FromMetaTag(Tag &tag) +{ + if (tag.name != "MLight") + __ERR__(__LOG_E__ << "Could not parse managed light, incorrect root tag (" << tag.name << ").\n", false) + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") MItem::FromMetaTag(*pt); + else if (pt->name == "Light") Light::FromMetaTag(*pt); + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *MLight::AsMetaTag() +{ + Tag *root = new Tag("MLight"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(Light::AsMetaTag()); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mobject.cpp b/include/engine/scene3d/mobject.cpp new file mode 100644 index 0000000..851db0a --- /dev/null +++ b/include/engine/scene3d/mobject.cpp @@ -0,0 +1,19 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mobject.h" + #include "scene3d/scene_message.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +MObject::MObject() +{ + item_type = Type_Object; + mitem = (void *)((MItem *)this); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mobject_nml.cpp b/include/engine/scene3d/mobject_nml.cpp new file mode 100644 index 0000000..d12784d --- /dev/null +++ b/include/engine/scene3d/mobject_nml.cpp @@ -0,0 +1,42 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mobject.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool MObject::FromMetaTag(Tag &tag) +{ + if (tag.name != "MObject") + __ERR__(__LOG_E__ << "Could not parse managed object, incorrect root tag (" << tag.name << ").\n", false); + + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") + MItem::FromMetaTag(*pt); + else if (pt->name == "Object") + Object::FromMetaTag(*pt); + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *MObject::AsMetaTag() +{ + Tag *root = new Tag("MObject"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL); + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(Object::AsMetaTag()); + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/mterrain.cpp b/include/engine/scene3d/mterrain.cpp new file mode 100644 index 0000000..dccb463 --- /dev/null +++ b/include/engine/scene3d/mterrain.cpp @@ -0,0 +1,17 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mterrain.h" + #include "scene3d/scene_message.h" + + using namespace GS::S3D; + + +MTerrain::MTerrain() +{ + item_type = Type_Terrain; + mitem = (void *)((MItem *)this); +} diff --git a/include/engine/scene3d/mterrain_nml.cpp b/include/engine/scene3d/mterrain_nml.cpp new file mode 100644 index 0000000..dcca046 --- /dev/null +++ b/include/engine/scene3d/mterrain_nml.cpp @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mterrain.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool MTerrain::FromMetaTag(Tag &tag) +{ + if (tag.name != "MTerrain") + __ERR__(__LOG_E__ << "could not parse managed terrain, incorrect root tag (" << tag.name << ").\n", false) + + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") + MItem::FromMetaTag(*pt); + else if (pt->name == "Terrain") + Terrain::FromMetaTag(*pt); + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *MTerrain::AsMetaTag() +{ + Tag *root = new Tag("MTerrain"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(Terrain::AsMetaTag()); + return root; +} +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/include/engine/scene3d/mtrigger.cpp b/include/engine/scene3d/mtrigger.cpp new file mode 100644 index 0000000..f0a29f3 --- /dev/null +++ b/include/engine/scene3d/mtrigger.cpp @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mtrigger.h" + #include "scene3d/mitem_event_interface.h" + #include "scene3d/scene_message.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void MTriggerProxy::MarkItem(GS::Core::Item *item) +{ + MItem *mitem = (MItem *)item->mitem; + mitem->item_event->OnTrigger(mitem, mtrigger); + + Trigger::MarkItem(item); + + mitem->item_event->OnEnterTrigger(mitem, mtrigger); + mtrigger->item_event->OnItemEnter(mtrigger, mitem); +} +void MTriggerProxy::DropItem(GS::Core::Item *item) +{ + MItem *mitem = (MItem *)item->mitem; + + mitem->item_event->OnExitTrigger(mitem, mtrigger); + mtrigger->item_event->OnItemExit(mtrigger, mitem); + + Trigger::DropItem(item); +} +//------------------------------------------------------------------------------ + +MTrigger::MTrigger() : MTriggerProxy(this) +{ + item_type = Type_Trigger; + mitem = (void *)((MItem *)this); +} diff --git a/include/engine/scene3d/mtrigger_nml.cpp b/include/engine/scene3d/mtrigger_nml.cpp new file mode 100644 index 0000000..1e7146b --- /dev/null +++ b/include/engine/scene3d/mtrigger_nml.cpp @@ -0,0 +1,42 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mtrigger.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool MTrigger::FromMetaTag(Tag &tag) +{ + if ((tag.name != "Trigger") && (tag.name != "MTrigger")) + __ERR__(__LOG_E__ << "Could not parse trigger, incorrect root tag (" << tag.name << ").\n", false) + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "MItem") + MItem::FromMetaTag(*pt); + else if (pt->name == "Item") + ((Item *)this)->FromMetaTag(*pt); + + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *MTrigger::AsMetaTag() +{ + Tag *root = new Tag("MTrigger"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(MItem::AsMetaTag()); + root->AddChild(((Item *)this)->AsMetaTag()); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene.cpp b/include/engine/scene3d/scene.cpp new file mode 100644 index 0000000..1d1fd48 --- /dev/null +++ b/include/engine/scene3d/scene.cpp @@ -0,0 +1,494 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/mlight.h" + #include "scene3d/mobject.h" + #include "scene3d/mcamera.h" + #include "scene3d/mtrigger.h" + #include "scene3d/memitter.h" + #include "scene3d/mterrain.h" + #include "scene3d/instance.h" + #include "scene3d/mconstraint.h" + #include "scene3d/mitem_scripted_object.h" + #include "scene3d/scene_event_script_interface.h" + #include "scene3d/scene_renderer_environment_interface.h" + #include "scene3d/scene_physic_world_interface.h" + #include "scene3d/scene_scripted_object.h" + #include "scene3d/scene_script_unit.h" + #include "scene3d/mitem_event_script_interface.h" + #include "physic/physic_constraint.h" + #include "physic/physic_world.h" + #include "ui/ui.h" + + using namespace GS; + using namespace S3D; + + +//------------------------------------------------------------------------------ +void Scene::SetClock(Core::Clock *c, bool set_ui) +{ + clock = c ? c : new Core::Clock; + if (set_ui) + ui->SetClock(c); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::GetMinMax(MinMax &minmax) const +{ + bool initial = true; + + ArrayListForeachPtr(MItem *, i, active_list) + { + if (i->GetItemType() != Type_Object) + continue; + + MObject *object = (MObject *)i; + if (object->render_data.IsNull() || object->render_data->geometry.IsNull()) + continue; + + MinMax local_minmax = object->render_data->geometry->minmax; + + if (initial) + minmax = local_minmax; + else minmax.Grow(local_minmax); + initial = false; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Group *Scene::AddGroup(Group *g) +{ + group_list.Add(g); + return g; +} +bool Scene::RemoveGroup(Group *g) +{ + return group_list.Remove(g); +} +Group *Scene::FindGroup(const char *name) const +{ + ListForeachPtr(Group *, g, group_list) + if (g->name == name) + return g; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Scene::GetItemGroupList(const MItem *item, SharedList &list) const +{ + uint count = 0; + ListForeachPtr(Group *, g, group_list) + if (g->IsMember(item)) + { + count++; + list.Add(g); + } + + return count; +} +void Scene::UnregisterItemFromGroups(MItem *item) const +{ + ListForeachPtr(Group *, g, group_list) + g->Remove(item); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Scene::ActivateItem(MItem *i, bool v) +{ + if (v) + { + if (active_list.IndexOf(i) == -1) + active_list.Add(i); + } + else + active_list.Remove(i); + + if (i->physic_item) + i->physic_item->SetActive(v); + + i->mitem_flags.Raise(MItem::Flag_IsActive, v); + return true; +} +void Scene::ProcessItemActivationQueue() +{ + ListForeachPtr(MItem *, i, activation_queue) + ActivateItem(i, true); + ListForeachPtr(MItem *, i, deactivation_queue) + ActivateItem(i, false); + + activation_queue.Clear(); + deactivation_queue.Clear(); +} +void Scene::QueueItemActivation(MItem *item, bool activate, bool propagate) +{ + if (item->mitem_flags.IsSet(MItem::Flag_IsActive) != activate) + { + // Queue item. + if (activate) + { + if (!activation_queue.Find(item)) + activation_queue.Add(item); + deactivation_queue.Remove(item); + } + else + { + if (!deactivation_queue.Find(item)) + deactivation_queue.Add(item); + activation_queue.Remove(item); + } + + // Script callback. + item->item_event->OnActivate(item, activate); + item->mitem_flags.Raise(MItem::Flag_IsActive, activate); + } + + if (propagate) + ListForeachPtr(Core::Item *, child, item->GetBaseItem()->GetChildren()) + QueueItemActivation(LocateManagedItem(child), activate, true); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Scene::Create(PhysicWorld *w) +{ + Clear(); + + if ((physic_world = w) != NULL) + { + if (!physic_world->Create()) + return false; + + // bullet_world->CreateDebugger(GetEngine().GetRenderer()); + physic_world->SetWorldInterface(iphysic_world); + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MTrigger *Scene::RaytraceTriggerList(Vector4 &s, Vector4 &d, float l, Vector4 *i) +{ + ListForeachPtr(MItem *, item, item_list) + if (item->GetItemType() == Type_Trigger) + { + MTrigger *t = (MTrigger *)item; + + // Move ray to trigger space. + Vector4 local_s, local_d; + t->GetInverseMatrix().Apply(&local_s, &s); + t->GetInverseMatrix().ApplyRotation(&local_d, &d); + + // Test ray against bbox normalized space. + MinMax mm; + mm.SetFromPositionSize(Vector4(0, 0, 0), Vector4(1, 1, 1)); + + // Raytrace against minmax. + Vector4 local_i; + if (l == -1 ? mm.ClassifyLine(local_s, local_d, local_i) : mm.ClassifySegment(local_s, local_s + local_d * l, local_i)) + { + if (i) + *i = local_i * t->GetMatrix(); + return t; + } + } + + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::RecordAllItemLocation() +{ + ListForeachPtr(MItem *, i, item_list) + i->SetInitialTransformation(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MItem *Scene::ItemFromUid(uint uid) const +{ + ListForeachPtr(MItem *, i, item_list) + if (i->GetUid() == uid) + return i; + + return NULL; +} +MItemType Scene::LocateItem(const Core::Item *item, MItem **entity) const +{ + ListForeachPtr(MItem *, i, item_list) + if (i->GetBaseItem() == item) + { + if (entity) + *entity = i; + return i->GetItemType(); + } + + return Type_None; +} +MItem *Scene::LocateManagedItem(Core::Item *i) +{ + return i ? (MItem *)i->mitem : NULL; +} +//------------------------------------------------------------------------------ + +static bool FindItemByName(const MItem *i, const char *name) { return i->name == name; } + +//------------------------------------------------------------------------------ +MItem *Scene::Item(const char *item_name, MItem *parent) const +{ + StringList node; + String(item_name).Split("/", node); + + MItem *item = NULL; + + if (parent) + ListForeachPtr(Core::Item *, child, parent->GetBaseItem()->GetChildren()) + { + MItem *child_item = LocateManagedItem(child); + if (child_item && (child_item->name == node[0])) + { + item = child_item; + break; + } + } + else + item = ListFindEx(item_list, FindItemByName, node[0]); + + if (!item) + __ERR__(__LOG_W__ << "No item named '" << item_name << "' in scene '" << name << "'.\n", NULL) + + // Solve additional path. + if (node.GetCount() > 1) + for (uint n = 1; n < node.GetCount(); ++n) + { + if (item->GetItemType() != Type_Instance) + __ERR__(__LOG_W__ << "Cannot solve sub-path '" << node[n] << "' on item '" << item->name << "'.\n", NULL) + + Instance *instance = (Instance *)item; + if (!instance->instance_group) + return NULL; + + item = instance->instance_group->Item(node[n]); + } + + return item; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::SetItemStatic(MItem *item, bool v) +{ + item->mitem_flags.Raise(MItem::Flag_IsStatic, v); + + if (Core::Renderable *r = item->GetRenderable()) + { + RemoveRenderable(r); + AddRenderable(r, v); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::AddRenderable(Core::Renderable *r, bool is_static) +{ + if (is_static) + octree_culling_system.AddRenderable(r); + else simple_culling_system.AddRenderable(r); +} +void Scene::RemoveRenderable(Core::Renderable *r) +{ + simple_culling_system.DeleteRenderable(r); + octree_culling_system.DeleteRenderable(r); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::SetupItemComponents(MItem *i) +{ + // Create scripted object and event handler. + i->scripted_object = new MItemScriptedObject(i, vm); + if (vm) + i->item_event = new MItemScriptEvent; + + // Create physic item. + if (physic_world && i->GetBaseItem()) + { + i->physic_item = physic_world->NewItem(); + i->physic_item->SetUserPointer((void *)i); + } +} +void Scene::AddItem(MItem *i, bool setup_components) +{ + i->uid = current_item_uid++; + + if (setup_components) + SetupItemComponents(i); + + g_scene_messenger.BroadcastMessage(SceneMsg_AddingItem, this, i); + + // Add to all lists. + item_list.Add(i); + active_list.Add(i); + + switch (i->GetItemType()) + { + case Type_Light: light_list.Add((MLight *)i); break; + case Type_Trigger: trigger_list.Add((MTrigger *)i); break; + } + + // Add to culling systems. + if (Core::Renderable *r = i->GetRenderable()) + AddRenderable(r, i->mitem_flags.IsSet(MItem::Flag_IsStatic)); + + g_scene_messenger.BroadcastMessage(SceneMsg_ItemAdded, this, i); +} +bool Scene::RemoveItem(MItem *i) +{ + g_scene_messenger.BroadcastMessage(SceneMsg_DeletingItem, this, (void *)i); + + i->item_event->OnDelete(i); + + if (vm.IsValid()) + vm->InvalidateNativeReference(i); + + // Remove from groups. + UnregisterItemFromGroups(i); + + if (Core::Renderable *r = i->GetRenderable()) + { + // Remove from culling systems. + simple_culling_system.DeleteRenderable(r); + octree_culling_system.DeleteRenderable(r); + } + + if (Core::Item *b = i->GetBaseItem()) + { + // Unset if current camera. + if (current_camera == b) + current_camera = NULL; + + // Remove from triggers & skins. + ListForeachPtr(MItem *, item, item_list) + switch (item->GetItemType()) + { + case Type_Trigger: + ((MTrigger *)item)->DropItem(b); + break; + + case Type_Object: + { + MObject *o = (MObject *)item; + for (uint n = 0; n < o->GetBoneCount(); ++n) + if (o->GetBone(n) == b) + o->BindBone(n, NULL); + } + break; + } + } + + // Remove from physic world. + i->physic_item = NULL; + + switch (i->GetItemType()) + { + case Type_Light: light_list.Remove((MLight *)i); break; + case Type_Trigger: trigger_list.Remove((MTrigger *)i); break; + } + + active_list.Remove(i); + removal_queue.Remove(i); + activation_queue.Remove(i); + deactivation_queue.Remove(i); + + item_list.Remove(i); // keep last + + g_scene_messenger.BroadcastMessage(SceneMsg_ItemDeleted, this, i); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::QueueItemRemoval(MItem *i) +{ removal_queue.Add(i); } +void Scene::ProcessItemRemovalQueue() +{ + while (List ::Item *r = removal_queue.GetRoot()) + RemoveItem(r->Object()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::Clear(bool keep_script) +{ + g_scene_messenger.BroadcastMessage(SceneMsg_Clearing, this, 0); + + scene_event->OnDelete(this); + + // Remove all items (immediate/non-queued). + while (List ::Item *i = item_list.GetRoot()) + RemoveItem(i->Object()); + + // Drop UI. + ui->Clear(); + + // Close scripts. + if (!keep_script) + scripted_object->RemoveAllUnit(); + + fog_color.Set(); + fog_near = 0; + fog_far = 0; + + current_item_uid = 0; + + g_scene_messenger.BroadcastMessage(SceneMsg_Cleared, this, 0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Scene::Scene(Script::IVM *script_vm) : profiler(*this) +{ + vm = script_vm; + current_camera = NULL; + + current_item_uid = 0; + + ambient_intensity = 1; + target_exposure = 0.25; + + time_of_day = 0.5; + + fog_near = 0; + fog_far = 0; + fog_color.Set(0, 0, 0); + + background_color.Set(0, 0, 0); + ambient_color.Set(0, 0, 0); + + clock = new Core::Clock; + + scene_event = vm ? new SceneScriptEvent : new ISceneEvent; + scripted_object = new SceneScriptedObject(vm, this); + + irenderer_environment = new IEnvironment(this); + iphysic_world = new IScenePhysicWorld(this); + + ui = new S2D::Scene(vm); +} +Scene::~Scene() +{ + SetAsScriptGlobalScene(); + Clear(); + + if (vm) + vm->InvalidateNativeReference((void *)this); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_ace_manager.cpp b/include/engine/scene3d/scene_ace_manager.cpp new file mode 100644 index 0000000..e1c8093 --- /dev/null +++ b/include/engine/scene3d/scene_ace_manager.cpp @@ -0,0 +1,32 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_ace_manager.h" + #include "core/ace.h" + #include "memory/nauto_ptr.h" + + using namespace GS::S3D; + using GS::ACE::Manager; + + +//------------------------------------------------------------------------------ +Manager *ACEManager::Get() +{ + static AutoPtr scene_manager; + + if (!scene_manager) + { + scene_manager = new Manager; + scene_manager->DefineACECommand("toposition", ACESN_toposition, 3); + scene_manager->DefineACECommand("offsetposition", ACESN_offsetposition, 3); + scene_manager->DefineACECommand("tooffset", ACESN_tooffset, 3); + scene_manager->DefineACECommand("toscale", ACESN_toscale, 3); + scene_manager->DefineACECommand("torotation", ACESN_torotation, 3); + scene_manager->DefineACECommand("toalpha", ACESN_toalpha, 1); + } + return scene_manager; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_debug.cpp b/include/engine/scene3d/scene_debug.cpp new file mode 100644 index 0000000..d1bb0c7 --- /dev/null +++ b/include/engine/scene3d/scene_debug.cpp @@ -0,0 +1,595 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "scene3d/scene_debug.h" + #include "scene3d/scene.h" + #include "scene3d/mobject.h" + #include "scene3d/mlight.h" + #include "scene3d/mcamera.h" + #include "scene3d/mtrigger.h" + #include "scene3d/mconstraint.h" + #include "scene3d/instance.h" + #include "scene3d/group.h" + #include "physic/physic_constraint.h" + #include "core/renderer_toolbox.h" + #include "metafile/nml_object.h" + #include "core/path_kdtree.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::S3D; + using namespace GS::Units; + + +//----------------------------------------------------------------------------- +void SceneDebugger::DrawItemBoundingVolume(Renderer &render, MItem *i, uint display_flags) +{ + if (i && (i->GetItemType() == Type_Object)) + { + if (display_flags & SceneDebugDisplayBoundingVolumes) + { + MObject *mobj = (MObject *)i; + + MinMax pinmax; + mobj->ComputeLocalMinMax(pinmax); + OBB obb = OBB::FromMinMax(pinmax); + obb.Transform(i->GetBaseItem()->GetMatrix()); + + Color color(1, 1, 0, 0.35f); + RendererToolbox::DrawOBB(render, obb, &color, Material::Blend_Alpha); + } + + if (display_flags & SceneDebugDisplayOctreeVolumes) + { + /// TODO + } + } +} +void SceneDebugger::DrawItem(Renderer &render, MItem *pitem, uint display_flags, Color *draw_color) +{ + if (!pitem) + return; + + Color item_color = draw_color ? *draw_color : Color(0.75f, 0.75f, 0.75f); + Color bone_color = item_color; + bone_color.w = 0.5f; + + render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + + if (pitem->GetBaseItem()->item_flags.IsSet(ItemFlagBoneHint) && pitem->GetBaseItem()->GetParent()) + { + if (display_flags & SceneDebugDisplayBones) + { + Item *link = pitem->GetBaseItem()->GetParent(); + Vector4 w = pitem->GetBaseItem()->GetMatrix().GetRow(3) - link->GetMatrix().GetRow(3); + float k = w.Len(); + Vector4 row = link->GetMatrix().GetRow(1); + Matrix4 m = Matrix4::FromMatrix3(Matrix3::FromOrthonormalBasis(w, &row)); + m.SetRow(3, link->GetMatrix().GetRow(3)); + + Vector4 p[6] = + { + Vector4(0, 0, 0), + Vector4(-k * 0.1f, k * 0.1f, k * 0.2f), + Vector4( k * 0.1f, k * 0.1f, k * 0.2f), + Vector4( k * 0.1f, -k * 0.1f, k * 0.2f), + Vector4(-k * 0.1f, -k * 0.1f, k * 0.2f), + Vector4( 0, 0, k) + }, wp[6]; + + m.Apply(wp, p, 6); + + RendererToolbox::Line3D(render, wp[0], wp[1], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[0], wp[2], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[0], wp[3], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[0], wp[4], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + + RendererToolbox::Line3D(render, wp[1], wp[5], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[2], wp[5], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[3], wp[5], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[4], wp[5], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + + RendererToolbox::Line3D(render, wp[1], wp[2], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[2], wp[3], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[3], wp[4], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + RendererToolbox::Line3D(render, wp[4], wp[1], &bone_color, Material::Blend_Alpha, Material::RenderWord(Material::Render_NoZTest | Material::Render_NoZWrite)); + } + } + + // Display item motions. + if (display_flags & SceneDebugDisplayMotions) + if (pitem->automation_player && pitem->automation_player->GetMotionList().GetCount() && pitem->GetBaseItem()) + { + bool found = true; + Matrix4 m = pitem->GetBaseItem()->GetMatrix(); + + for (int index=0; index< pitem->automation_player->GetMotionList().GetCount(); ++index) + { + Motion* motion = pitem->automation_player->GetMotionFromIndex(index); + + // if(found) + { + found = false; + if(render.GetCamera()) + { + Vector4 view_position = render.GetCamera()->GetPosition(); + Vector4 view_position_closest_point(0, 0, 0); + float closest_t; + motion->GetClosestPoint(view_position * pitem->GetBaseItem()->GetInverseMatrix(), view_position_closest_point, &closest_t); + + Vector4 sample(0, 0, 0); + motion->EvaluatePosition(Time::fromSec(closest_t+1), sample, Curve::Constant); + + Color color(1,1,0); + if(sample == view_position_closest_point) + RendererToolbox::DrawCross(render, view_position_closest_point * m, Units::Mtr(1), &color); + else + { + Vector4 OrthoVec = ((view_position_closest_point - sample).Normalized()).Cross(Vector4(0.0,1.0,0.0)); + + RendererToolbox::Line3D(render, sample * m, (view_position_closest_point-OrthoVec) * m, &color); + RendererToolbox::Line3D(render, sample * m, (view_position_closest_point+OrthoVec) * m, &color); + } + + // if(motion->quadtree.IsValid()) + // motion->quadtree->draw_scene_debug(render, m); + } + } + + MotionChannel *c[3]; + motion->GetTransformationChannels(c, NULL, NULL); + + // check all 3 channel has the same number of point, because it's a vector + // if not just continue to the next + if( c[0]->GetPoints().GetCount() != c[1]->GetPoints().GetCount()|| + c[0]->GetPoints().GetCount() != c[2]->GetPoints().GetCount()|| + c[1]->GetPoints().GetCount() != c[2]->GetPoints().GetCount()|| + c[1]->GetPoints().GetCount() <= 1) + continue; + + ArrayList ::Iterator iteratorX(c[0]->GetPoints()); + ArrayList ::Iterator iteratorY(c[1]->GetPoints()); + ArrayList ::Iterator iteratorZ(c[2]->GetPoints()); + + Vector4 vec; + + Array v; + v.Allocate(c[0]->GetPointCount()*2); + Vector4 prev_vec; + int count = 0; + + for ( ; iteratorX.ObjectPtr(); ) // need to test iterator validity prior to access in case the motion has no point + { + vec.x = iteratorX.ObjectPtr()->v; + vec.y = iteratorY.ObjectPtr()->v; + vec.z = iteratorZ.ObjectPtr()->v; + + if(count != 0) + { + v[(count++)-1] = prev_vec; + v[(count++)-1] = vec*m; + } + else + ++count; + + prev_vec = vec*m; + + ++iteratorX; + ++iteratorY; + ++iteratorZ; + } + + render.DrawLine(c[0]->GetPointCount()-1, v); + + // draw cross for the first and the last point + if ((c[0]->GetPoints().GetCount() > 1) && (c[1]->GetPoints().GetCount() > 1) && (c[2]->GetPoints().GetCount() > 1)) + { + RendererToolbox::DrawCross(render, Vector4(c[0]->GetPoints()[0]->v, c[1]->GetPoints()[0]->v, c[2]->GetPoints()[0]->v)*m, Mtr(1), &Color::Green); + RendererToolbox::DrawCross(render, Vector4(c[0]->GetPoints()[c[0]->GetPointCount()-1]->v, c[1]->GetPoints()[c[1]->GetPointCount()-1]->v, c[2]->GetPoints()[c[2]->GetPointCount()-1]->v)*m, Mtr(1.1), &Color::Red); + } + } + } +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +void Triangle2d(Renderer &renderer, Vector4 sv[3], Color *c) +{ + Vector4 wv[3]; + for (int n = 0; n < 3; ++n) + wv[n] = renderer.GetCamera()->ScreenToWorld(renderer.GetViewport(), sv[n].x, sv[n].y); + Color cl[3]; + for (int n = 0; n < 3; ++n) + cl[n] = *c; + RendererToolbox::Triangle3D(renderer, wv, cl, 0, 0, Material::Blend_Alpha, (Material::RenderWord)(Material::Render_NoZTest | Material::Render_NoZWrite)); +} +void Cartouche(Renderer &render, Vector4 sp, float width, float height, Color *color) +{ + float offset_y = 0.6f; + + Vector4 v[3]; + v[0].Set(sp.x - width * 0.5f, sp.y + (offset_y - 1) * height * 0.5f); + v[1].Set(sp.x + width * 0.5f, sp.y + (offset_y - 1) * height * 0.5f); + v[2].Set(sp.x + width * 0.5f, sp.y + (offset_y + 1) * height * 0.5f); + Triangle2d(render, v, color); + v[0].Set(sp.x + width * 0.5f, sp.y + (offset_y + 1) * height * 0.5f); + v[1].Set(sp.x - width * 0.5f, sp.y + (offset_y + 1) * height * 0.5f); + v[2].Set(sp.x - width * 0.5f, sp.y + (offset_y - 1) * height * 0.5f); + Triangle2d(render, v, color); + + // Draw border. + for (int n = 0; n < 16; ++n) + { + v[2].Set(sp.x - width * 0.5f, sp.y); + float a = n * Deg(180.f / 16.f); + v[1].Set(sp.x - width * 0.5f - sin(a) * height * 0.25f, sp.y + (offset_y - cos(a)) * height * 0.5f); + a = (n + 1) * Deg(180.f / 16.f); + v[0].Set(sp.x - width * 0.5f - sin(a) * height * 0.25f, sp.y + (offset_y - cos(a)) * height * 0.5f); + Triangle2d(render, v, color); + } + for (int n = 0; n < 16; ++n) + { + v[0].Set(sp.x + width * 0.5f, sp.y); + float a = n * Deg(180.f / 16.f); + v[1].Set(sp.x + width * 0.5f + sin(a) * height * 0.25f, sp.y + (offset_y - cos(a)) * height * 0.5f); + a = (n + 1) * Deg(180.f / 16.f); + v[2].Set(sp.x + width * 0.5f + sin(a) * height * 0.25f, sp.y + (offset_y - cos(a)) * height * 0.5f); + Triangle2d(render, v, color); + } +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +void SceneDebugger::DrawItemName(Renderer &renderer, MItem *pitem) +{ + String label; + switch (pitem->GetItemType()) + { + case Type_Object: label = "Object: "; break; + case Type_Camera: label = "Camera: "; break; + case Type_Light: label = "Light: "; break; + case Type_Trigger: label = "Trigger: "; break; + + default: break; + } + label += pitem->name; + + Vector4 sp; + if (!renderer.GetCamera()->WorldToScreen(renderer.GetViewport(), pitem->GetBaseItem()->GetMatrix().GetRow(3), sp)) + return; + sp.y += 0.05f; + + // Draw a background. +// fRect viewport = renderer.GetViewport(); +// float width = profiler_font.ComputeLineWidth(label.c_str()); + Color bg_color(0.5f, 0.5f, 0.5f, 0.7f); +// Cartouche(render, sp, k * width * 0.5f, k * 0.075f, &bg_color); +// render.Write(profiler_font, label, sp.x, sp.y, k, true, Renderer::AlignMiddle); +} +void SceneDebugger::DrawFigure(Renderer &render, Geometry *figure, const Matrix4 &matrix, Color &color) +{ + if (!figure) + return; + + uint line_count = 0; + for (uint n = 0; n < figure->pol.GetCount(); ++n) + line_count += figure->pol[n].vtx_count; + + Array p_line(line_count * 2); + Array c_line(line_count * 2); + Vector4 *p_p = p_line; + Color *p_c = c_line; + + if (p_p && p_c) + { + for (uint n = 0; n < figure->pol.GetCount(); ++n) + for (int v = 0; v < figure->pol[n].vtx_count; ++v) + { + int w = v + 1; + if (w == figure->pol[n].vtx_count) + w = 0; + + *p_p++ = figure->vtx[figure->pol[n].binding[v]]; + *p_p++ = figure->vtx[figure->pol[n].binding[w]]; + *p_c++ = color; + *p_c++ = color; + } + + render.SetWorldMatrix(matrix.AsOrthonormalBase() * Matrix4::ScaleMatrix(Vector4(scale, scale, scale))); + render.DrawLine(line_count, p_line, c_line, Material::Blend_Alpha, (Material::RenderWord)(Material::Render_NoZTest | Material::Render_NoZWrite)); + } +} +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +static void DrawLineHatched(const Vector4 &a, const Vector4 &b, Vector4 *p_p, Color *p_c) +{ + (*p_c++).Set(0.8f, 0.8f, 0.8f, 0.75f); + (*p_c++).Set(0.8f, 0.8f, 0.8f, 0.75f); + (*p_c++).Set(0.8f, 0.8f, 0.8f, 0.75f); + (*p_c++).Set(0.8f, 0.8f, 0.8f, 0.75f); + + Vector4 dt = b - a; + *p_p++ = a; *p_p++ = a + dt * 0.2f; + *p_p++ = b; *p_p++ = b - dt * 0.2f; +} +static void DrawOBBCorners(Renderer &render, const OBB &obb, const Matrix4 &m) +{ + Vector4 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); + + render.SetWorldMatrix(m * Matrix4::TransformationMatrix(obb.bb_position, obb.bb_rotation, obb.bb_scale)); + + Array p_line(12 * 2 * 2); + Array c_line(12 * 2 * 2); + Vector4 *p_p = p_line; + Color *p_c = c_line; + + if (p_p && p_c) + { + DrawLineHatched(vtx[0], vtx[1], p_p + 0, p_c + 0); + DrawLineHatched(vtx[1], vtx[2], p_p + 4, p_c + 4); + DrawLineHatched(vtx[2], vtx[3], p_p + 8, p_c + 8); + DrawLineHatched(vtx[3], vtx[0], p_p + 12, p_c + 12); + + DrawLineHatched(vtx[4], vtx[5], p_p + 16, p_c + 16); + DrawLineHatched(vtx[5], vtx[6], p_p + 20, p_c + 20); + DrawLineHatched(vtx[6], vtx[7], p_p + 24, p_c + 24); + DrawLineHatched(vtx[7], vtx[4], p_p + 28, p_c + 28); + + DrawLineHatched(vtx[0], vtx[4], p_p + 32, p_c + 32); + DrawLineHatched(vtx[1], vtx[5], p_p + 36, p_c + 36); + DrawLineHatched(vtx[2], vtx[6], p_p + 40, p_c + 40); + DrawLineHatched(vtx[3], vtx[7], p_p + 44, p_c + 44); + + render.DrawLine(12 * 2, p_line, c_line, Material::Blend_Alpha, Material::Render_NoZTest); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SceneDebugger::DrawScene(Renderer &render, const List *selection, const List *blacklist, uint display_flags) +{ + Color middle_grey(0.72f, 0.72f, 0.72f), + selected_orange(1, 0.65f, 0.16f), + draw_color; + + // Display light schematics. + ListForeachPtr(MItem *, i, scene->GetItemList()) + { + if (blacklist && blacklist->Find(i)) + continue; + + switch (i->GetItemType()) + { + case Type_Light: + if (MLight *l = (MLight *)i) + { + DrawItem(render, l, display_flags); + + if (selection && selection->Find(l)) + draw_color = selected_orange; + else draw_color = middle_grey; + + switch (l->model) + { + case Light::Model_Point: + DrawFigure(render, pointlight.c_ptr(), l->GetMatrix(), draw_color); + break; + case Light::Model_Linear: + DrawFigure(render, linearlight.c_ptr(), l->GetMatrix(), draw_color); + break; + case Light::Model_Spot: + DrawFigure(render, spotlight.c_ptr(), l->GetMatrix(), draw_color); + break; + + default: break; + } + } + break; + + case Type_Object: + if (MObject *o = (MObject *)i) + { + DrawItemBoundingVolume(render, o, display_flags); + + bool display_item = false; + if (!selection || selection->Find(o)) + { + display_item = true; + draw_color = selected_orange; + } + else + draw_color = middle_grey; + + if (display_item || o->geometry.IsEmpty()) + DrawItem(render, o, display_flags, &draw_color); + + // DrawFigure(render, dbg_object, obj->GetMatrix(), draw_color); + } + break; + + case Type_Camera: + if (MCamera *c = (MCamera *)i) + { + DrawItem(render, c, display_flags); + + if (!selection || selection->Find(c)) + draw_color = selected_orange; + else draw_color = middle_grey; + + DrawFigure(render, camera.c_ptr(), c->GetMatrix(), draw_color); + } + break; + + case Type_Trigger: + if (MTrigger *t = (MTrigger *)i) + { + OBB obb(t->GetMatrix().GetRow(3), t->GetScale(), &t->GetRotationMatrix()); + Color color(1, 0, 0); + if (t->isActive()) + color.Set(0, 1, 0); + RendererToolbox::DrawOBB(render, obb, &color); + + if (!selection || selection->Find(t)) + draw_color = selected_orange; + else draw_color = middle_grey; + + DrawFigure(render, trigger.c_ptr(), t->GetMatrix(), draw_color); + } + break; + + case Type_Constraint: + if (MConstraint *c = (MConstraint *)i) + { + if (c->desc.item_a.IsNull() || c->desc.item_b.IsNull()) + continue; + + Vector4 wp_a = c->desc.pivot_a.GetRow(3) * c->desc.item_a->GetBaseItem()->GetMatrix(), + wp_b = c->desc.pivot_b.GetRow(3) * c->desc.item_b->GetBaseItem()->GetMatrix(); + + RendererToolbox::DrawCross(render, wp_a, Cm(20.f)); + RendererToolbox::DrawCross(render, wp_b, Cm(20.f)); + RendererToolbox::Line3D(render, wp_a, wp_b); + } + break; + + case Type_Instance: + { + // the items draw debug inside this instance, only if this instance is selected + if (selection && selection->Find(i)) + { + if (Instance *instance = (Instance *)i) + { + if (instance->instance_scene) + { + // call the draw debug for the object inside this scene instance + ListForeachPtr(MItem *, i_instance, instance->instance_scene->GetItemList()) + { + if (i_instance->GetItemType() == Type_Object) + { + if (MObject *o = (MObject *)i_instance) + { + DrawItemBoundingVolume(render, o, display_flags); + + bool display_item = false; + if (selection->Find(o)) + { + display_item = true; + draw_color = selected_orange; + } + else + draw_color = middle_grey; + + if (display_item || o->geometry.IsEmpty()) + DrawItem(render, o, display_flags, &draw_color); + } + } + } + } + } + } + } + break; + + default: break; + } + } + + // Display bounding. + MinMax minmax; + ListForeachPtr(MItem *, i, *selection) + switch (i->GetItemType()) + { + case Type_Object: + { + ((MObject *)i)->ComputeLocalMinMax(minmax); + OBB obb(minmax); + DrawOBBCorners(render, obb, i->GetBaseItem()->GetMatrix()); + } + break; + + case Type_Instance: + { + Instance *instance = (Instance *)i; + if (instance->instance_scene) + { + instance->instance_scene->GetMinMax(minmax); + OBB obb(minmax); + DrawOBBCorners(render, obb, i->GetBaseItem()->GetMatrix()); + } + } + break; + + default: break; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool SceneDebugger::LoadSchematicFigures(const char *dbg_pointlight, const char *dbg_spotlight, const char *dbg_linearlight, const char *dbg_camera, const char *dbg_object, const char *dbg_trigger) +{ + pointlight = new Geometry; + pointlight->name = dbg_pointlight; + NML::LoadFromFile(*pointlight, dbg_pointlight); + spotlight = new Geometry; + spotlight->name = dbg_spotlight; + NML::LoadFromFile(*spotlight, dbg_spotlight); + linearlight = new Geometry; + linearlight->name = dbg_linearlight; + NML::LoadFromFile(*linearlight, dbg_linearlight); + + camera = new Geometry; + camera->name = dbg_camera; + NML::LoadFromFile(*camera, dbg_camera); + object = new Geometry; + object->name = dbg_object; + NML::LoadFromFile(*object, dbg_object); + trigger = new Geometry; + trigger->name = dbg_trigger; + NML::LoadFromFile(*trigger, dbg_trigger); + return true; +} +void SceneDebugger::SetScene(Scene *s) +{ scene = s; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SceneDebugger::SceneDebugger() +{ + scene = NULL; + scale = 1.f; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::DumpContentToLog() const +{ + __LOG_V__ << "Dumping scene content\n\n"; + + __LOG_V__ << "Item list (" << GetActiveList().GetCount() << " entries):\n"; + ArrayListForeachPtr(MItem *, i, GetActiveList()) + { + MItem *pi = NULL; + if (i->GetBaseItem()) + LocateItem(i->GetBaseItem()->GetParent(), &pi); + __LOG_V__ << " - '" << i->name << "' (" << i->GetUid() << ")"; + + if (pi) + __LOG_V__ << "(Linked to '" << pi->name << "' (" << pi->GetUid() << ")), (Active: " << (i->isActive() ? "yes" : "no") << ", Invisible: " << (i->GetBaseItem()->item_flags.IsSet(ItemFlagInvisible) ? "yes" : "no") << ")\n"; + else __LOG_V__ << "\n"; + } + __LOG_V__ << "\n"; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_event_script_interface.cpp b/include/engine/scene3d/scene_event_script_interface.cpp new file mode 100644 index 0000000..0c7848f --- /dev/null +++ b/include/engine/scene3d/scene_event_script_interface.cpp @@ -0,0 +1,89 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_event_script_interface.h" + #include "scene3d/scene_script_unit.h" + #include "scene3d/scene.h" + #include "scene3d/mitem_event_interface.h" + #include "scene3d/mitem.h" + #include "script/scripted_object.h" + #include "script/script_variant.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void SceneScriptEvent::OnSetup(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnSetup")) + unit->DoFunctionCall(); +} +void SceneScriptEvent::OnSetupDone(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnSetupDone")) + unit->DoFunctionCall(); +} +void SceneScriptEvent::OnReset(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnReset")) + unit->DoFunctionCall(); +} +void SceneScriptEvent::OnRender(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (((SceneScriptUnit *)unit)->render_callback && unit->SetupFunctionCall("OnRender", ((SceneScriptUnit *)unit)->render_callback)) + unit->DoFunctionCall(); +} +void SceneScriptEvent::OnRenderDone(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (((SceneScriptUnit *)unit)->render_done_callback && unit->SetupFunctionCall("OnRenderDone", ((SceneScriptUnit *)unit)->render_done_callback)) + unit->DoFunctionCall(); +} +void SceneScriptEvent::OnRenderUser(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (((SceneScriptUnit *)unit)->render_user_callback && unit->SetupFunctionCall("OnRenderUser", ((SceneScriptUnit *)unit)->render_user_callback)) + unit->DoFunctionCall(); + + ListForeachPtr(MItem *, item, scene->GetItemList()) + item->item_event->OnRenderUser(item); +} +void SceneScriptEvent::OnRenderUIDone(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (((SceneScriptUnit *)unit)->render_ui_done_callback && unit->SetupFunctionCall("OnRenderUIDone", ((SceneScriptUnit *)unit)->render_ui_done_callback)) + unit->DoFunctionCall(); +} +void SceneScriptEvent::OnPhysicStep(Scene *scene, bool step_taken) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (((SceneScriptUnit *)unit)->physic_step_callback && unit->SetupFunctionCall("OnPhysicStep", ((SceneScriptUnit *)unit)->physic_step_callback)) + { + unit->PushFunctionCallArgument(step_taken); + unit->DoFunctionCall(); + } +} +void SceneScriptEvent::OnUpdate(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + { + SceneScriptUnit *scene_unit = (SceneScriptUnit *)unit; + if (scene_unit->update_callback && scene_unit->SetupFunctionCall("OnUpdate", scene_unit->update_callback)) + scene_unit->DoFunctionCall(); + } +} +void SceneScriptEvent::OnDelete(Scene *scene) +{ + ListForeachPtr(Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnDelete")) + unit->DoFunctionCall(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_group.cpp b/include/engine/scene3d/scene_group.cpp new file mode 100644 index 0000000..181538a --- /dev/null +++ b/include/engine/scene3d/scene_group.cpp @@ -0,0 +1,25 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/group.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void Scene::GroupMembersSetActive(Group *group, bool v) +{ + ListForeachPtr(MItem *, i, group->GetItemList()) + QueueItemActivation(i, v); +} +void Scene::DeleteGroupAndMembers(Group *group) +{ + ListForeachPtr(MItem *, i, group->GetItemList()) + QueueItemRemoval(i); + group_list.Remove(group); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_info.cpp b/include/engine/scene3d/scene_info.cpp new file mode 100644 index 0000000..d51a69b --- /dev/null +++ b/include/engine/scene3d/scene_info.cpp @@ -0,0 +1,32 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_info.h" + #include "automation/automation_player.h" + #include "scene3d/mlight.h" + #include "scene3d/mcamera.h" + #include "scene3d/mobject.h" + #include "scene3d/scene.h" + #include "log/log.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +void GS::S3D::DumpMemoryLayout() +{ + __LOG__ << "Scene memory layout:\n\n"; + __LOG__ << " sizeof(S3D::Scene) = " << (uint)sizeof(Scene) << "\n"; + __LOG__ << " sizeof(S3D::MItem) = " << (uint)sizeof(MItem) << "\n"; + __LOG__ << " sizeof(Core::MotionChannel) = " << (uint)sizeof(MotionChannel) << "\n"; + __LOG__ << " sizeof(Core::Motion) = " << (uint)sizeof(Motion) << "\n"; + __LOG__ << " sizeof(Automation::Player) = " << (uint)sizeof(GS::Automation::Player) << "\n"; + __LOG__ << " sizeof(S3D::MObject) = " << (uint)sizeof(MObject) << "\n"; + __LOG__ << " sizeof(S3D::MCamera) = " << (uint)sizeof(MCamera) << "\n"; + __LOG__ << " sizeof(S3D::MLight) = " << (uint)sizeof(MLight) << "\n"; + __LOG__ << "\n"; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_message.cpp b/include/engine/scene3d/scene_message.cpp new file mode 100644 index 0000000..86cbea3 --- /dev/null +++ b/include/engine/scene3d/scene_message.cpp @@ -0,0 +1,14 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_message.h" + + +namespace GS { + namespace S3D { + Messaging::Broadcaster g_scene_messenger; + } +} \ No newline at end of file diff --git a/include/engine/scene3d/scene_mitem.cpp b/include/engine/scene3d/scene_mitem.cpp new file mode 100644 index 0000000..cecc206 --- /dev/null +++ b/include/engine/scene3d/scene_mitem.cpp @@ -0,0 +1,83 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/mlight.h" + #include "scene3d/mobject.h" + #include "scene3d/mcamera.h" + #include "scene3d/mtrigger.h" + #include "scene3d/instance.h" + #include "scene3d/mconstraint.h" + #include "scene3d/group.h" + #include "scene3d/mitem_event_interface.h" + #include "physic/physic_world.h" + #include "physic/physic_constraint.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +uint Scene::GetItemCountByType(MItemType type) const +{ + uint count = 0; + ListForeachPtr(MItem *, i, item_list) + if (i->GetItemType() == type) + ++count; + return count; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template T *DuplicateItemType(MItem *item, T *clone, Scene *scene) +{ + if (clone) + { + GS::AutoPtr tag(((T *)item)->AsMetaTag()); + scene->SetupItemComponents(clone); + clone->FromMetaTag(*tag); + scene->AddItem(clone, false); + } + return clone; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MItem *Scene::DuplicateItem(MItem *item) +{ + MItem *new_instance = NULL; + + switch (item->GetItemType()) + { + case Type_Camera: new_instance = DuplicateItemType (item, new MCamera, this); break; + case Type_Object: new_instance = DuplicateItemType (item, new MObject, this); break; + case Type_Light: new_instance = DuplicateItemType (item, new MLight, this); break; + case Type_Trigger: new_instance = DuplicateItemType (item, new MTrigger, this); break; + case Type_Constraint: new_instance = DuplicateItemType (item, new MConstraint(physic_world->NewConstraint()), this); break; + + case Type_Instance: + { + Instance *i = (Instance *)(new_instance = DuplicateItemType (item, new Instance, this)); + + if (((Instance *)item)->instance_group) + i->Instantiate(this); + + if (i->instance_group) + i->instance_group->Setup(); + + i->Setup(physic_world); + } + break; + + default: break; + } + + // Duplicate hierarchy. + if (new_instance) + new_instance->GetBaseItem()->SetParent(item->GetBaseItem()->GetParent()); + + return new_instance; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_nml.cpp b/include/engine/scene3d/scene_nml.cpp new file mode 100644 index 0000000..af25c20 --- /dev/null +++ b/include/engine/scene3d/scene_nml.cpp @@ -0,0 +1,680 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/mobject.h" + #include "scene3d/mlight.h" + #include "scene3d/mcamera.h" + #include "scene3d/mtrigger.h" + #include "scene3d/instance.h" + #include "scene3d/memitter.h" + #include "scene3d/mterrain.h" + #include "scene3d/mconstraint.h" + #include "scene3d/group.h" + #include "physic/physic_constraint.h" + #include "physic/physic_world.h" + #include "ui/ui.h" + #include "script/scripted_object.h" + #include "script/script_unit.h" + #include "container/nmap.h" + + using namespace GS; + using namespace S3D; + using NML::Tag; + + +//------------------------------------------------------------------------------ +static MItem *GetMappedItemFromTag(Scene &scene, Tag *pt, const char *tag, Map &uid_map, MItemType type = Type_None) +{ + Tag *muid = pt->GetTypedTag(tag, Variant::VariantInteger); + if (!muid) + __ERR__(__LOG_W__ << "Invalid UID tag.\n", NULL) + + uint uid = muid->GetUnsigned(); + if (!uid_map.HasKey(uid)) + __ERR__(__LOG_W__ << "Invalid item UID.\n", NULL) + + MItem *mitem = scene.ItemFromUid(uid_map[uid]); + if (mitem && (type != Type_None) && (mitem->GetItemType() != type)) + __ERR__(__LOG_V__ << "Item type filtered out.\n", NULL) + + return mitem; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static bool ShouldLoadItem(ToolMode mode, Tag *pt, uint flag, int load_level) +{ + if (pt->GetTag("MItem:ToolSpecific;") || pt->GetTag("MItem:Helper;")) + { + if (!(flag & SceneIOHelper)) + return false; + + // Do not load tool specific items in no tool or project preview modes. + if ((mode == NoTool) || (mode == ToolProjectPreview)) + return false; + + // Do not load tool specific items in no tool mode above the first load level. + if (load_level > 0) + return false; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template static T *LoadItemDerived(Scene *scene, T *i, Map &uid_map, Tag *t, uint type_flag, const uint load_flag, int load_level, ToolMode tool_mode) +{ + if (!(load_flag & type_flag) || !ShouldLoadItem(tool_mode, t, load_flag, load_level)) + { + delete i; + return NULL; + } + + scene->SetupItemComponents(i); + + if (i->FromMetaTag(*t)) + { + uint olduid = i->GetUid(); // uid from source scene + scene->AddItem(i, false); // add to live scene + uid_map.Add(olduid, i->GetUid()); // store map from source to live scene + } + return i; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Scene::FromMetaTagStoreGroup(const Tag &tag, Group **group, uint load_flag, ToolMode tool_mode, int load_level) +{ + if (tag.name != "Scene") + __ERR__(__LOG_E__ << "Could not parse scene, incorrect root tag (" << tag.name << ").\n", false); + + Benchmark bench(true); + g_scene_messenger.BroadcastMessage(SceneMsg_Loading, this, 0); + + ui->ResetCommandList(); + + // Create scene group. + if (group && !group[0]) + { + group[0] = new Group; + group[0]->name = "SceneGroup"; + group_list.Add(group[0]); + } + + // Read items and setup uid remap array. + Map uid_map; + + if (Tag *itag = tag.GetTag("Items")) + { + // Item count in scene. + uint item_to_load = 0; + NMLTagForeach(pt, *itag) + if (Tag *item_tag = pt->GetTag("MItem;")) + item_to_load++; + + NMLTagForeach(pt, *itag) + { + MItem *citem = NULL; + + if (pt->name == "MCamera") + citem = LoadItemDerived(this, new MCamera, uid_map, pt, SceneIOCamera, load_flag, load_level, tool_mode); + else if (pt->name == "MObject") + citem = LoadItemDerived(this, new MObject, uid_map, pt, SceneIOObject, load_flag, load_level, tool_mode); + else if (pt->name == "MLight") + citem = LoadItemDerived(this, new MLight, uid_map, pt, SceneIOLight, load_flag, load_level, tool_mode); + else if ((pt->name == "MTrigger") || (pt->name == "Trigger")) // Legacy + citem = LoadItemDerived(this, new MTrigger, uid_map, pt, SceneIOTrigger, load_flag, load_level, tool_mode); + else if (pt->name == "Instance") + citem = LoadItemDerived(this, new Instance, uid_map, pt, SceneIOInstance, load_flag, load_level, tool_mode); + else if (pt->name == "MEmitter") + citem = LoadItemDerived(this, new MEmitter, uid_map, pt, SceneIOEmitter, load_flag, load_level, tool_mode); + else if (pt->name == "MTerrain") + citem = LoadItemDerived(this, new MTerrain, uid_map, pt, SceneIOTerrain, load_flag, load_level, tool_mode); + else if (pt->name == "MConstraint") + citem = LoadItemDerived(this, new MConstraint(physic_world ? physic_world->NewConstraint() : NULL), uid_map, pt, SceneIOConstraint, load_flag, load_level, tool_mode); + else + __LOG_W__ << "Unexpected <" << pt->name << "> sub-tag in .\n"; + + if (citem) + { + // Add item to the scene group. + if (group && group[0]) + group[0]->Add(citem); + + // Remove from active list if inactive. + if (!citem->isActive()) + active_list.Remove(citem); + } + } + } + + // Solve links. + if (Tag *ltag = tag.GetTag("Links")) + { + NMLTagForeach(pt, *ltag) + { + if (pt->name == "Link") + { + int item = -1, link = -1; + + NMLTagForeach(lt, *pt) + { + if (lt->name == "Item") item = lt->GetInteger(); + else if (lt->name == "Link") link = lt->GetInteger(); + } + + MItem *sitem = NULL, *litem = NULL; + + if ((item == -1) || (link == -1)) + __LOG_W__ << "Incomplete link tag.\n"; + else + { + // Some items might have been masked out from import. + if (uid_map.HasKey(item) && uid_map.HasKey(link)) + { + sitem = ItemFromUid(uid_map[item]); + litem = ItemFromUid(uid_map[link]); + if (sitem && litem) + sitem->GetBaseItem()->SetParent(litem->GetBaseItem()); + +// __LOG__ << "Solving link: " << item << "(" << (sitem ? "OK" : "Failed") << ")->" << link << "(" << (litem ? "OK" : "Failed") << ").\n"; + } +// else __LOG_W__ << "Link item masked out during import.\n"; + } + } + else + __LOG_W__ << "Unexpected <" << pt->name << "> sub-tag in .\n"; + } + } + + // Solve constraints. + if (Tag *ctag = tag.GetTag("Constraints")) + { + NMLTagForeach(pt, *ctag) + if (pt->name == "Constraint") + { + MItem *mitem = GetMappedItemFromTag(*this, pt, "Uid;", uid_map, Type_Constraint); + if (!mitem) + continue; + + // Get constraint. + if (MConstraint *constraint = (MConstraint *)mitem) + { + MItem *mitem_a = GetMappedItemFromTag(*this, pt, "UidA;", uid_map), + *mitem_b = GetMappedItemFromTag(*this, pt, "UidB;", uid_map); + + constraint->desc.item_a = mitem_a; + constraint->desc.item_b = mitem_b; + } + } + } + + // Solve skins. + if (Tag *btag = tag.GetTag("Skins")) + { + NMLTagForeach(pt, *btag) + if (pt->name == "Skin") + if (MItem *mitem = GetMappedItemFromTag(*this, pt, "UId;", uid_map, Type_Object)) + { + // We can now safely cast to the managed and core objects. + MObject *mobj = (MObject *)mitem; + Core::Object *obj = (Core::Object *)mobj; + + uint bone_count = 0; + NMLTagForeach(st, *pt) + if (st->name == "Bone") + bone_count++; + + if (!obj->AllocateSkin(bone_count)) + continue; + + // Process skin binding. + NMLTagForeach(st, *pt) + if (st->name == "Bone") + { + // Grab mandatory bone tags. + Tag *itag = st->GetTypedTag("Index", Variant::VariantInteger), + *utag = st->GetTypedTag("UId", Variant::VariantInteger); + + if (!itag || !utag) + { __LOG_E__ << "Invalid bone information, incomplete bone tag.\n"; continue; } + + int index = itag->GetInteger(); + if ((index < 0) || (index >= (int)obj->GetBoneCount())) + { __LOG_E__ << "Invalid bone information, bone index out of bound.\n"; continue; } + + // Locate bone item. + uint uid = utag->GetUnsigned(); + if (!uid_map.HasKey(uid)) + { __LOG_E__ << "Invalid bone information, item uid out of bound.\n"; continue; } + + MItem *bone = ItemFromUid(uid_map[uid]); + if (!bone) + { __LOG_E__ << "Invalid bone information, item not found.\n"; continue; } + + obj->BindBone(index, bone->GetBaseItem()); + } + } + } + + // Read groups. + if (load_flag & SceneIOGroup) + if (Tag *gstag = tag.GetTag("Groups")) + { + String _item("Item"); + + NMLTagForeach(gtag, *gstag) + { + if (gtag->name == "Group") + { + if (Tag *tid = gtag->GetTag("Id")) + { + if (Group *new_group = new Group) + { + new_group->name = tid->GetString(); + group_list.Add(new_group); + + NMLTagForeach(mtag, *gtag) + { + if (mtag->name == _item) + { + int uid = mtag->GetInteger(); + if (uid_map.HasKey(uid)) + new_group->Add(ItemFromUid(uid_map[uid])); + // else + // __LOG_W__ << "Group member masked out during import.\n"; + } + } + + // Add as sub-group. + if (group) + group[0]->Add(new_group); + } + else + __LOG_E__ << "Failed to allocate group '" << tid->GetString() << "'.\n"; + } + else + __LOG_W__ << "Could not read group, no identifier found.\n"; + } + } + } + + // Script unit. + if (load_flag & SceneIOScript) + { + if (Tag *stag = tag.GetTag("ScriptedObject")) + scripted_object->FromMetaTag(*stag); + + #if 1 // Compatibility + else + if (Tag *stag = tag.GetTag("ScriptUnit")) + if (Script::Unit *unit = scripted_object->AddUnit(scripted_object->NewUnit())) + unit->FromMetaTag(*stag); + #endif + } + + // Motion sets. + if (load_flag & SceneIOMotion) + if (Tag *ctag = tag.GetTag("SceneMotionContainer")) + { + if (group) + { + if (*group) + (*group)->motion.FromMetaTag(*ctag, &uid_map); + } + else + motion.FromMetaTag(*ctag, &uid_map); + } + + // Scene properties. + static String _bgc("BackgroundColor"), _abc("AmbientColor"), _abi("AmbientIntensity"), _tge("TargetExposure"), + _feb("FogEnable"), _fgn("FogNear"), _fgf("FogFar"), _fgc("FogColor"), _rad("Radiance"), _ird("Irradiance"); + + if (!group || (load_flag & SceneIOGlobals)) + if (Tag *gtag = tag.GetTag("Globals")) + NMLTagForeach(t, *gtag) + { + if (t->name == _bgc) + background_color.FromMetaTag(*t); + else if (t->name == _abc) + ambient_color.FromMetaTag(*t); + else if (t->name == _abi) + ambient_intensity = t->GetReal(); + else if (t->name == _rad) + radiance_probe = t->GetString(); + else if (t->name == _ird) + irradiance_probe = t->GetString(); + else if (t->name == _tge) + target_exposure = t->GetReal(); + + else if (t->name == _fgn) + fog_near = t->GetReal(); + else if (t->name == _fgf) + fog_far = t->GetReal(); + else if (t->name == _fgc) + fog_color.FromMetaTag(*t); + + else if (t->name == "SkyLayer0") + skybox_layer[0] = t->GetString(); + else if (t->name == "SkyLayer1") + skybox_layer[1] = t->GetString(); + else if (t->name == "SkyShader") + skybox_shader = t->GetString(); + + else if (t->name == "TimeOfDay") + time_of_day = t->GetReal(); + } + + // Physic system. + if ((load_flag & SceneIOPhysic) && physic_world) + { + Tag *ptag = tag.GetTag("Physics;"); + + if (!ptag) + ptag = tag.GetTag("Tau;"); // Look for a legacy tag. + + if (ptag) + { + NMLTagForeach(t, *ptag) + if (t->name == "Frequency") + physic_world->SetTimestep(1.f / t->GetReal()); + } + } + + // Group stats. + if (group && group[0]) + __LOG__ << "Group '" << group[0]->name << "': " << group[0]->GetItemList().GetCount() << " item(s).\n"; + + // Load current camera. + if ((load_flag & SceneIOSettings) && (load_flag & SceneIOCamera)) + if (Tag *cctag = tag.GetTag("CurrentCamera")) + { + MItem *i = Item(cctag->GetString()); + if (i && (i->GetItemType() == Type_Camera)) + current_camera = (Camera *)i->GetBaseItem(); + } + + // Query the editor tag if no camera found. + if (!current_camera && (tool_mode != ToolEdit)) + if (MCamera *camera = new MCamera) + { + camera->name = "Default"; + AddItem(camera, true); + current_camera = camera; + + if (Tag *pt = tag.GetTag("ViewMatrix;")) + { + Matrix4 m; + if (m.FromMetaTag(*pt)) + camera->SetMatrix(m); + } + } + + bench.Stop(); + __LOG__ << "Done loading scene in " << bench.GetMs() << "ms.\n"; + + g_scene_messenger.BroadcastMessage(SceneMsg_Loaded, this, 0); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Scene::FromMetaFileStoreGroup(const char *path, Group **group, uint flag, ToolMode tool_mode, int load_level) +{ + NML::File file; + if (!NML::Parser::Load(path, file)) + return false; + + if (Tag *scene_tag = file.GetTag("Scene")) + { + if (FromMetaTagStoreGroup(*scene_tag, group, flag, tool_mode, load_level)) + name = path; + } + else + __ERR__(__LOG_E__ << "No tag in '" << path << "'.\n", false) + + if (group && group[0]) + group[0]->name = path; + + return true; +} +bool Scene::IsItemToBeSaved(MItem *i, const Group *group, uint flag) const +{ + if (!i) + return false; + + // Filter out irrelevant items. + if (group && !group->IsMember(i)) + return false; + + switch (i->GetItemType()) + { + case Type_Camera: if (!(flag & SceneIOCamera)) return false; break; + case Type_Object: if (!(flag & SceneIOObject)) return false; break; + case Type_Light: if (!(flag & SceneIOLight)) return false; break; + case Type_Trigger: if (!(flag & SceneIOTrigger)) return false; break; + case Type_Instance: if (!(flag & SceneIOInstance)) return false; break; + case Type_Emitter: if (!(flag & SceneIOEmitter)) return false; break; + case Type_Terrain: if (!(flag & SceneIOTerrain)) return false; break; + + default: break; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Scene::LinkInfoAsMetaTag(MItem *i, const Group *group, uint flag) const +{ + if (!IsItemToBeSaved(i, group, flag)) + return NULL; + + // Grab link managed item. + Core::Item *link = i->GetBaseItem() ? i->GetBaseItem()->GetParent() : NULL; + MItem *mlink; + if (!link || ((mlink = LocateManagedItem(link)) == NULL)) + return NULL; + + if (!IsItemToBeSaved(mlink, group, flag)) + return NULL; + + // Save link information. + if (Tag *tag = new Tag("Link")) + { + tag->AddChild("Item", i->GetUid()); + tag->AddChild("Link", mlink->GetUid()); + return tag; + } + __ERR__(__LOG_E__ << "Failed to allocate link tag.\n", NULL) +} +Tag *Scene::SkinInfoAsMetaTag(MObject *mobj, const Group *group, uint flag) const +{ + if (group && (!group->IsMember(mobj))) + return NULL; + + // Go to the low-level core object. + Core::Object *obj = (Core::Object *)mobj; + if (!obj->HasSkin()) + return NULL; + + Tag *skin_tag = new Tag("Skin"); + if (!skin_tag) + __ERR__(__LOG_E__ << "Failed to allocate skin tag.\n", NULL); + skin_tag->AddChild("UId", mobj->GetUid()); + + for (int n = 0; n < (int)obj->GetBoneCount(); ++n) + { + MItem *bone = Scene::LocateManagedItem(obj->GetBone(n)); + if (!bone || (group && (!group->IsMember(bone)))) + continue; + + // Export bone informations. + if (Tag *bone_tag = skin_tag->AddChild("Bone")) + { + bone_tag->AddChild("Index", n); + bone_tag->AddChild("UId", bone->GetUid()); + Matrix4 m; + if (obj->GetBindMatrix(n, m)) + bone_tag->AddChild(m.AsMetaTag("BindMatrix")); + else + __LOG_E__ << "Failed to serialize bone " << n << " bind matrix for object '" << mobj->name << "'.\n"; + } + else __LOG_E__ << "Failed to allocate bone tag.\n"; + } + return skin_tag; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Scene::AsMetaTag(const Group *group, uint save_flag, ToolMode tool_mode) const +{ + Tag *root = new Tag("Scene"); + if (!root) + __ERR__(__LOG_E__ << "Could not create scene root tag to serialize.\n", NULL); + + // Write script object. + if (scripted_object.IsValid() && !group) + root->AddChild(scripted_object->AsMetaTag()); + + // Write motion sets. + if (save_flag & SceneIOMotion) + root->AddChild(motion.AsMetaTag()); + + // Write managed items. + if (Tag *itag = root->AddChild("Items")) + ListForeachPtr(MItem *, i, item_list) + { + if (group && !group->IsMember(i)) + continue; + + switch (i->GetItemType()) + { + case Type_Camera: if (!(save_flag & SceneIOCamera)) continue; break; + case Type_Object: if (!(save_flag & SceneIOObject)) continue; break; + case Type_Light: if (!(save_flag & SceneIOLight)) continue; break; + case Type_Trigger: if (!(save_flag & SceneIOTrigger)) continue; break; + case Type_Instance: if (!(save_flag & SceneIOInstance)) continue; break; + case Type_Emitter: if (!(save_flag & SceneIOEmitter)) continue; break; + case Type_Terrain: if (!(save_flag & SceneIOTerrain)) continue; break; + case Type_Constraint: if (!(save_flag & SceneIOConstraint)) continue; break; + + default: break; + } + + itag->AddChild(i->AsMetaTag()); + } + else + __ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL); + + // Write link informations. + if (Tag *ltag = root->AddChild("Links")) + ListForeachPtr(MItem *, i, item_list) + ltag->AddChild(LinkInfoAsMetaTag(i, group, save_flag)); + else + __ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL) + + // Write skin informations. + if (Tag *stag = root->AddChild("Skins")) + { + ListForeachPtr(MItem *, i, item_list) + if (i->GetItemType() == Type_Object) + stag->AddChild(SkinInfoAsMetaTag((MObject *)i, group, save_flag)); + + if (stag->GetChildCount() == 0) + { + root->RemoveTag(stag); + _safe_delete(stag); + } + } + else + __ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL); + + // Write constraints. + if (Tag *constraint_tag = root->AddChild("Constraints")) + ListForeachPtr(MItem *, i, item_list) + if (i->GetItemType() == Type_Constraint) + { + if (group && !group->IsMember(i)) + continue; + + MConstraint *c = (MConstraint *)i; + if (Tag *ctag = constraint_tag->AddChild("Constraint")) + { + ctag->AddChild("Uid", c->GetUid()); + if (c->desc.item_a.IsValid()) + ctag->AddChild("UidA", c->desc.item_a->GetUid()); + if (c->desc.item_b.IsValid()) + ctag->AddChild("UidB", c->desc.item_b->GetUid()); + } + } + + // Write scene groups. + if (!group) + { + if ((save_flag & SceneIOGroup) && group_list.GetCount()) + { + if (Tag *gstag = root->AddChild("Groups")) + { + ListForeachPtr(Group *, group, group_list) + if (Tag *gtag = gstag->AddChild("Group")) + { + gtag->AddChild("Id", group->name.c_str()); + ListForeachPtr(MItem *, item, group->GetItemList()) + gtag->AddChild("Item", item->GetUid()); + } + } + else + __ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL); + } + + // Output scene properties. + if (save_flag & SceneIOGlobals) + { + if (Tag *gtag = root->AddChild("Globals")) + { + gtag->AddChild(background_color.AsMetaTag("BackgroundColor")); + gtag->AddChild(ambient_color.AsMetaTag("AmbientColor")); + + if (!irradiance_probe.IsEmpty()) + gtag->AddChild("Irradiance", irradiance_probe.c_str()); + if (!radiance_probe.IsEmpty()) + gtag->AddChild("Radiance", radiance_probe.c_str()); + + if (!skybox_layer[0].IsEmpty()) + gtag->AddChild("SkyLayer0", skybox_layer[0].c_str()); + if (!skybox_layer[1].IsEmpty()) + gtag->AddChild("SkyLayer1", skybox_layer[1].c_str()); + if (!skybox_shader.IsEmpty()) + gtag->AddChild("SkyShader", skybox_shader.c_str()); + + gtag->AddChild("TimeOfDay", time_of_day); + + gtag->AddChild("AmbientIntensity", ambient_intensity); + gtag->AddChild("TargetExposure", target_exposure); + + gtag->AddChild("FogNear", fog_near); + gtag->AddChild("FogFar", fog_far); + + gtag->AddChild(fog_color.AsMetaTag("FogColor")); + } + else + __ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL); + } + + // Physics. + if ((save_flag & SceneIOPhysic) && physic_world.IsValid()) + if (Tag *ptag = root->AddChild("Physics")) + ptag->AddChild("Frequency", 1.f / physic_world->GetTimestep()); + + // Current camera. + if (current_camera) + if (MItem *ci = LocateManagedItem(current_camera)) + root->AddChild("CurrentCamera", ci->name); + } + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_physic_world_interface.cpp b/include/engine/scene3d/scene_physic_world_interface.cpp new file mode 100644 index 0000000..0b254ce --- /dev/null +++ b/include/engine/scene3d/scene_physic_world_interface.cpp @@ -0,0 +1,57 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_physic_world_interface.h" + #include "scene3d/mitem_event_interface.h" + #include "scene3d/scene.h" + #include "physic/physic_world.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void IScenePhysicWorld::PhysicStep(float timestep, bool pre_tick) +{ + if (pre_tick) + { + scene->SynchronizePhysics(); + + // Pre-tick, step physics. + scene->scene_event->OnPhysicStep(scene, true); + + ArrayListForeachPtr(MItem *, item, scene->GetActiveList()) + switch (item->GetItemType()) + { + default: + if (!item->physic_item || (item->physic_item_desc.physic_mode == PhysicItemDesc::Mode_None)) + break; + + case Type_Instance: + item->item_event->OnPhysicStep(item, true); + break; + } + + + } + else + { + // End of tick, dispatch collision events. + for (uint n = 0; n < scene->physic_world->GetCollisionPairCount(); ++n) + { + CollisionPair pair; + if (!scene->physic_world->GetCollisionPair(n, pair)) + continue; + + MItem *item_a = (MItem *)pair.a->GetUserPointer(), + *item_b = (MItem *)pair.b->GetUserPointer(); + if (item_a && item_a->item_event.IsValid() && item_b && item_b->item_event.IsValid()) { + item_a->item_event->OnCollision(item_a, item_b, pair); + item_b->item_event->OnCollision(item_b, item_a, pair); + } + } + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_preloader.cpp b/include/engine/scene3d/scene_preloader.cpp new file mode 100644 index 0000000..528806f --- /dev/null +++ b/include/engine/scene3d/scene_preloader.cpp @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "core/render_resource_factory.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +bool Scene::PreloadResources(GS::Render::ResourceFactory &rf, const char *uri) +{ + __LOG_H__ << "Preloading scene '" << uri << "' resources.\n"; + + using namespace GS::NML; + + File file; + if (!Parser::Load(uri, file)) + return false; + + if (Tag *items = file.GetTag("Scene:Items;")) + { + NMLTagForeach(t, *items) + if (t->name == "MObject") + if (Tag *g = t->GetTypedTag("Object:Geometry;", Variant::VariantString)) + rf.LoadGeometry(g->GetString()); + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_profiler.cpp b/include/engine/scene3d/scene_profiler.cpp new file mode 100644 index 0000000..b0f12f3 --- /dev/null +++ b/include/engine/scene3d/scene_profiler.cpp @@ -0,0 +1,111 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "physic/physic_world.h" + #include "core/renderer.h" + + using namespace GS; + using namespace GS::S3D; + + +namespace GS { + +// +class ProfilerRenderer +{ + Renderer &render; + RasterFont **font; + + float &x, &y; + + Renderer::WriterConfig config; + + Color title_color; + +static const int indent_width = 16; +static const int col_a_x = 180, col_b_x = 256; + + void DisplaySystem(const char *label, const Benchmark &bench) + { + float x_h = x; + render.Write(*font[0], label, x_h, y, config, 1, &title_color); + + float x_a = x + col_a_x; + render.Write(*font[0], String::Format("%0.02fms", bench.GetMs()), x_a, y, config, 1, &title_color); + float x_b = x + col_b_x; + render.Write(*font[0], bench.GetMs() ? String::Format("%.01ffps", 1000.f / bench.GetMs()) : "-", x_b, y, config, 1, &title_color); + + render.Write(*font[0], "\n", x, y, config, 1, &title_color); + } + void DisplaySystem(const char *label, const Benchmark &bench, const Benchmark &parent) + { + float x_h = x; + render.Write(*font[0], label, x_h, y, config, 1, &title_color); + + float x_a = x + col_a_x; + render.Write(*font[0], String::Format("%0.02fms", bench.GetMs()), x_a, y, config, 1, &title_color); + float x_b = x + col_b_x; + render.Write(*font[0], String::Format("%d%%", parent.GetMs() ? int(bench.GetMs() * 100.f / parent.GetMs()) : 0), x_b, y, config, 1, &title_color); + + render.Write(*font[0], "\n", x, y, config, 1, &title_color); + } + void RenderSystem(const Profiler::System *sys, const Profiler::System *parent, int indent_level) + { + float x_s = x; + x += indent_level * indent_width; + + if (parent) + DisplaySystem(sys->label, sys->profile, parent->profile); + else DisplaySystem(sys->label, sys->profile); + + x = x_s; + + ListForeachPtr(Profiler::System *, sub, sys->sub_systems) + RenderSystem(sub, sys, indent_level + 1); + } + +public: + + void DisplayHeader(const char *header) + { + render.Write(*font[1], String(header) << "\n\n", x, y, config, 1, &title_color); + } + + void StartRender() + { + render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + render.SetViewMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + render.SetProjectionMatrix(Matrix4::IdentityMatrix()); + } + void Render(const Profiler &profiler) + { + ListForeachPtr(Profiler::System *, sys, profiler.root_systems) + RenderSystem(sys, NULL, 0); + } + + ProfilerRenderer(Renderer &r, RasterFont *f[2], float &_x, float &_y) : render(r), font(f), x(_x), y(_y), config(false), title_color(1, 1, 1) {} +}; + +} // GS + +//------------------------------------------------------------------------------ +void SceneProfiler::ResetProfiles() +{ + Profiler::ResetProfiles(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::DrawProfilerText(Renderer &render, RasterFont *font[2], float &x, float &y) +{ + ProfilerRenderer prof_render(render, font, x, y); + + prof_render.StartRender(); + prof_render.DisplayHeader(String::Format("Scene: %d item, %d active (%d%%)", item_list.GetCount(), active_list.GetCount(), item_list.GetCount() ? (active_list.GetCount() * 100) / item_list.GetCount() : 100)); + prof_render.Render(profiler); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_render.cpp b/include/engine/scene3d/scene_render.cpp new file mode 100644 index 0000000..eb87e9c --- /dev/null +++ b/include/engine/scene3d/scene_render.cpp @@ -0,0 +1,105 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/mobject.h" + #include "scene3d/memitter.h" + #include "scene3d/mterrain.h" + #include "scene3d/mitem_event_interface.h" + #include "ui/ui.h" + #include "core/renderer.h" + #include "core/camera.h" + + using namespace GS; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void Scene::PushRenderable(Renderer &renderer) +{ + ScopedSystemProfile(profiler.push_to_render); + + { + ScopedSystemProfile(profiler.push_active_list); + + ArrayListForeachPtr(MItem *, ci, active_list) + if (Core::Item *b = ci->GetBaseItem()) + { + // Check exclusion. + if (b->item_flags.IsSet(ItemFlagInvisible)) + continue; + if (ci->mitem_flags.IsSet(MItem::Flag_EditorHidden)) + continue; + + // Render objects and emitters. + switch (ci->GetItemType()) + { + case Type_Emitter: + renderer.PushRenderable((Core::Emitter *)b); + break; + case Type_Terrain: + renderer.PushRenderable((Core::Terrain *)b); + break; + + default: break; + } + } + } + + // Push culling systems. + { + ScopedSystemProfile(profiler.push_simple_culling); + renderer.PushRenderable(&simple_culling_system); + } + { + ScopedSystemProfile(profiler.push_octree_culling); + renderer.PushRenderable(&octree_culling_system); + } +} +void Scene::Render(Renderer &renderer) +{ + renderer.SetEnvironmentInterface(irenderer_environment); + + scene_event->OnRender(this); + + if (!flags.IsSet(FlagRenderless)) + { + PushRenderable(renderer); + + renderer.BeginDrawList(); + renderer.RenderList(); + renderer.EndDrawList(); + + renderer.DeleteRenderableList(); + } + + renderer.SetEnvironmentInterface(NULL); + + scene_event->OnRenderDone(this); +} +void Scene::RenderUI(Renderer &renderer, GPU::TriangleBatch *batch) +{ + if (renderer.ideal_render_system_vr_resolution.x != -1) + { + uint w, h; + renderer.GetOutputWindow()->GetSize(w, h); + renderer.dimensions.Set(w, h); + renderer.SetViewport(fRect(0, 0, w, h)); + } + + ui->Render(renderer, batch); + + scene_event->OnRenderUIDone(this); + + ui->RenderGlobalFade(renderer); + + if(renderer.ideal_render_system_vr_resolution.x != -1) + { + renderer.dimensions.Set(renderer.ideal_render_system_vr_resolution.x, renderer.ideal_render_system_vr_resolution.y); + renderer.ideal_render_system_vr_resolution.x = -1; + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_renderer_environment_interface.cpp b/include/engine/scene3d/scene_renderer_environment_interface.cpp new file mode 100644 index 0000000..dc42a7d --- /dev/null +++ b/include/engine/scene3d/scene_renderer_environment_interface.cpp @@ -0,0 +1,161 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_renderer_environment_interface.h" + #include "scene3d/mlight.h" + #include "scene3d/scene.h" + #include "physic/physic_world.h" + #include "core/renderer.h" + #include "sort/sort.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +float IEnvironment::GetClock() const +{ return scene->GetClock()->Getf(); } +float IEnvironment::GetTimeOfDay() const +{ return scene->time_of_day; } +Render::Shader *IEnvironment::GetSkyboxShader() const +{ return scene->render_data ? scene->render_data->skybox_shader.c_ptr() : NULL; } +bool IEnvironment::GetSkyboxLayers(Render::sTexture layers[2]) const +{ + if (scene->render_data.IsValid()) + for (uint n = 0; n < 2; ++n) + layers[n] = scene->render_data->skybox_layer[n]; + + return layers[0].IsValid() && layers[1].IsValid(); +} +void IEnvironment::GetEnvironmentProbe(Render::sTexture &radiance, Render::sTexture &irradiance) const +{ + if (scene->render_data.IsValid()) + { + radiance = scene->render_data->radiance_probe; + irradiance = scene->render_data->irradiance_probe; + } +} +bool IEnvironment::IsFogEnabled() const +{ return scene->fog_far > 0.f; } +bool IEnvironment::GetFogConfiguration(Color &color, float &fog_near, float &fog_far) const +{ + if (scene->fog_far < 0.f) + return false; + + color = scene->fog_color; + fog_near = scene->fog_near; + fog_far = scene->fog_far; + return true; +} +Color IEnvironment::GetClearColor() const +{ return scene->background_color; } +Color IEnvironment::GetAmbientColor() const +{ return scene->ambient_color * scene->ambient_intensity; } +static float CompareLightPriority(const MLight *a, const MLight *b) { return a->GetPriority() - b->GetPriority(); } +void IEnvironment::GetLightsInFrustum(const Vector4 &world_pos, const Frustum &frustum, List &list, uint limit) const +{ + list.Clear(); + + // On very large scenes filtering items by type can become very slow. +#if 0 + nSharedList lights; + if (!scene->GetItemListByType(lights)) + return; +#else + List lights; + scene->GetLightList().Clone(lights); +#endif + lights.Sort(CompareLightPriority); + + ListForeachPtr(MLight *, l, lights) + { + if (!l->isActive()) + continue; + + // Check light range and clip distance. + if (l->range) + { + if (Vector4::Dist(world_pos, l->GetMatrix().GetRow(3)) >= (l->clip_distance + l->range)) + continue; + + // Check frustum intersection. + switch (l->model) + { + case Light::Model_Point: + if (frustum.ClassifySphere(l->GetMatrix().GetRow(3), l->range) == Frustum::Outside) + continue; + break; + + case Light::Model_Spot: + if (frustum.ClassifyFrustrum(l->frustum) == Frustum::Outside) + continue; + break; + + default: break; + } + } + + list.Add(l); + if (list.GetCount() == limit) + break; + } +} +void IEnvironment::GetClosestLights(const Vector4 &world_pos, List &list, uint limit) const +{ + list.Clear(); + +#if 0 + nSharedList lights; + if (!scene->GetItemListByType(lights)) + return; +#else + List lights; + scene->GetLightList().Clone(lights); +#endif + + Array ::Entry> array(lights.GetCount()); + if (!array) + __ERRRAW__(__LOG_E__ << "Failed to allocated sort structure.\n") + + int c = 0; + ListForeachPtr(MLight *, l, lights) + if (l->isActive()) + { + array[c].o = l; + array[c].v = Vector4::Dist2(world_pos, l->GetMatrix().GetRow(3)) * (1.f - l->GetPriority()); + ++c; + } + + Sort ::QuickSort(c, array); + for (int n = 0; n < c; n++) + { + list.Add(array[n].o); + if (list.GetCount() == limit) + break; + } +} +Camera *IEnvironment::GetCurrentCamera() const +{ return scene->current_camera; } +void IEnvironment::OnRenderUser(Renderer *renderer) const +{ + scene->scene_event->OnRenderUser(scene); + + // Debug physics. + if (scene->flags.IsSet(Scene::FlagDebugPhysics)) + if (PhysicWorld *world = scene->physic_world) + { + if (!world->HasDebugger()) + world->CreateDebugger(renderer); + + renderer->SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + renderer->ApplyCamera(); + + world->DrawDebug(*renderer, scene->current_camera, NULL/*profiler_font[0]*/, true); + world->DrawDebug(*renderer, scene->current_camera, NULL/*profiler_font[0]*/, false); + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_reset.cpp b/include/engine/scene3d/scene_reset.cpp new file mode 100644 index 0000000..a0d4282 --- /dev/null +++ b/include/engine/scene3d/scene_reset.cpp @@ -0,0 +1,31 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "log/log.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void Scene::Reset() +{ + __LOG_H__ << "Reset scene '" << name << "'.\n"; + + // Reset item sequence. + ListForeachPtr(MItem *, i, item_list) + i->ResetToInitialTransformation(); + ListForeachPtr(MItem *, i, item_list) + i->Reset(); + + scene_event->OnReset(this); + + // Reset all benchmark objects. + profiler.ResetProfiles(); + + flags.Raise(FlagEnd, false); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_script_unit.cpp b/include/engine/scene3d/scene_script_unit.cpp new file mode 100644 index 0000000..7f7dddc --- /dev/null +++ b/include/engine/scene3d/scene_script_unit.cpp @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_script_unit.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +bool SceneScriptUnit::Open() +{ + if (!Unit::Open()) + return false; + + render_callback = vm->GetObjectFromName("OnRender", self); + render_done_callback = vm->GetObjectFromName("OnRenderDone", self); + render_user_callback = vm->GetObjectFromName("OnRenderUser", self); + render_ui_done_callback = vm->GetObjectFromName("OnRenderUIDone", self); + + update_callback = vm->GetObjectFromName("OnUpdate", self); + physic_step_callback = vm->GetObjectFromName("OnPhysicStep", self); + + return true; +} +void SceneScriptUnit::Close() +{ + render_callback = NULL; + render_done_callback = NULL; + render_user_callback = NULL; + render_ui_done_callback = NULL; + + update_callback = NULL; + physic_step_callback = NULL; + + Unit::Close(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SceneScriptUnit::SceneScriptUnit(IVM *vm) : Unit(vm) {} +SceneScriptUnit::~SceneScriptUnit() { Close(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_scripted_object.cpp b/include/engine/scene3d/scene_scripted_object.cpp new file mode 100644 index 0000000..5ddd266 --- /dev/null +++ b/include/engine/scene3d/scene_scripted_object.cpp @@ -0,0 +1,25 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene_scripted_object.h" + #include "scene3d/scene_script_unit.h" + #include "script/script_engine_types.h" + #include "log/log.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +Unit *SceneScriptedObject::NewUnit() const +{ + Unit *unit = new SceneScriptUnit(vm); + if (!unit) + __ERR__(__LOG_E__ << "Failed to allocate new scene script unit.", NULL); + unit->SetInterfaceObject(scene, typetag_Scene3d); + return unit; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_setup.cpp b/include/engine/scene3d/scene_setup.cpp new file mode 100644 index 0000000..340e65c --- /dev/null +++ b/include/engine/scene3d/scene_setup.cpp @@ -0,0 +1,85 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/mobject.h" + #include "scene3d/instance.h" + #include "scene3d/mconstraint.h" + #include "core/resource_factories.h" + #include "script/scripted_object.h" + + using namespace GS; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void Scene::RenderSetup(Core::ResourceFactories *f, bool setup_items) +{ + __LOG__ << "Scene '" << name << "' render setup...\n"; + + if ((render_data = new RenderData) != NULL) + { + render_data->skybox_shader = f->render->LoadShader(skybox_shader); + for (uint n = 0; n < 2; ++n) + render_data->skybox_layer[n] = f->render->LoadTexture(skybox_layer[n]); + + render_data->radiance_probe = f->render->LoadTexture(radiance_probe); + render_data->irradiance_probe = f->render->LoadTexture(irradiance_probe); + } + + if (setup_items) + ListForeachPtr(MItem *, i, item_list) + if (Core::Item *b = i->GetBaseItem()) + b->RenderSetup(f); +} +void Scene::InstanceSetup() +{ + ListForeachPtr(MItem *, i, item_list) + if (i->GetItemType() == Type_Instance) + ((Instance *)i)->Instantiate(this); +} +void Scene::Setup(ToolMode tool_mode) +{ + __LOG_H__ << "Setup scene '" << name << "'.\n"; + + scene_event->OnSetup(this); + + // Setup items. + ListForeachPtr(MItem *, i, item_list) + i->Setup(tool_mode == ToolEdit ? NULL : physic_world.c_ptr()); + + scene_event->OnSetupDone(this); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::TestOptimizeGeometry(Render::Geometry *geo, uint octree_node_size) +{ + if (!geo) + return; + + // Avoid infinite recursion. + if (geo->shadow_proxy == geo) + geo->shadow_proxy = NULL; + if (geo->lod_proxy == geo) + geo->lod_proxy = NULL; + + TestOptimizeGeometry(geo->shadow_proxy, octree_node_size); + TestOptimizeGeometry(geo->lod_proxy, octree_node_size); +} +void Scene::OptimizeForRealtime(uint octree_node_size) +{ + List list; + ListForeachPtr(MItem *, i, item_list) + if (i->GetItemType() == Type_Object) + if (MObject *o = (MObject *)i) + if (o->render_data.IsValid() && o->render_data->geometry.IsValid()) + list.Add(o->render_data->geometry, true, false); + + for (uint n = 0; n < list.GetCount(); ++n) + TestOptimizeGeometry(list[n], octree_node_size); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_trigger.cpp b/include/engine/scene3d/scene_trigger.cpp new file mode 100644 index 0000000..143046e --- /dev/null +++ b/include/engine/scene3d/scene_trigger.cpp @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/mtrigger.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void Scene::UpdateTriggers() +{ + ListForeachPtr(MTrigger *, t, trigger_list) + if (t->isActive()) + { + t->ReadyItemList(); + + ArrayListForeachPtr(MItem *, i, active_list) + if (i->mitem_flags.IsSet(MItem::Flag_TriggerDetected)) // TODO make a dedicated list. + if (i->isActive() && t->IsInside(i->GetBaseItem()->GetMatrix().GetRow(3))) + t->MarkItem(i->GetBaseItem()); + + t->PurgeItemList(); + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/scene3d/scene_update.cpp b/include/engine/scene3d/scene_update.cpp new file mode 100644 index 0000000..4c792cb --- /dev/null +++ b/include/engine/scene3d/scene_update.cpp @@ -0,0 +1,234 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/scene.h" + #include "scene3d/mitem_event_interface.h" + #include "ui/ui.h" + #include "motion/motion_automation_source.h" + #include "automation/automation_source_group.h" + #include "physic/physic_world.h" + #include "core/object.h" + #include "core/camera.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + #include "sort/sort.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void Scene::SetAsScriptGlobalScene(Script::IVM *_vm) +{ + if (!_vm) + _vm = vm; + if (!_vm || !_vm->IsOpen()) + return; + + _vm->Set("g_scene", Script::Variant(this, Script::typetag_Scene3d)); + _vm->Set("g_clock_fq", Platform::Get().GetClockFrequency()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::SetMotion(const char *name, Automation::SourceGroup **group, float blend, Automation::Player::AddSourceMode mode, float weight) +{ + if (group) + *group = new Automation::SourceGroup; + + SceneMotion *scene_motion = NULL; + ListForeachPtr(SceneMotion *, m, motion.motions) + if (m->name == name) + { + scene_motion = m; + break; + } + + if (scene_motion) + { + // Start item motions. + ListForeachPtr(SceneMotion::ItemMotion *, m, scene_motion->item_motions) + if (MItem *i = ItemFromUid(m->uid)) + i->automation_player->StartAutomation(new Automation::MotionSource(m->motion, group ? *group : NULL), blend, mode, weight); + } + else // fallback to the legacy per-item set motion + ArrayListForeachPtr(MItem *, item, GetActiveList()) + if (Motion *motion = item->automation_player->GetMotion(name)) + item->automation_player->StartAutomation(new Automation::MotionSource(motion, group ? *group : NULL), blend, mode, weight); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::SynchronizePhysics() +{ + Matrix4 m; + ArrayListForeachPtr(MItem *, item, active_list) + if (item->physic_item) + switch (item->physic_item_desc.physic_mode) + { + case PhysicItemDesc::Mode_Kinematic: + case PhysicItemDesc::Mode_Static: + item->physic_item->SetEngineMatrix(item->GetBaseItem()->GetMatrix()); + break; + + case PhysicItemDesc::Mode_Dynamic: + case PhysicItemDesc::Mode_Vehicle: + case PhysicItemDesc::Mode_Character: + item->physic_item->GetGraphicMatrix(m); + item->physic_item->SetEngineMatrix(m); + item->GetBaseItem()->SetMatrix(m); + break; + + default: break; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::UpdateItemTransformation(MItem *i, const Time &dt) +{ + i->Update(dt); + + if (Core::Item *b = i->GetBaseItem()) + { + if (i->mitem_flags.IsSet(MItem::Flag_Billboard)) + { + Vector4 p, s; + + if (Core::Item *link = b->GetParent()) + { + p = b->GetPosition() * link->GetMatrix(); + s = b->GetScale() * link->GetScale(); + } + else + { + p = b->GetPosition(); + s = b->GetScale(); + } + + Matrix3 view_matrix(Matrix3::FromMatrix4(current_camera ? current_camera->GetMatrix() : Matrix4::IdentityMatrix()) * Matrix3::RotationMatrixZAxis(b->GetRotation().z)); + Matrix4 billboard_matrix(Matrix4::TransformationMatrix(p, view_matrix, s)); + b->SnapshotTransformation(billboard_matrix, false, true); + } + + /* + [EJ] Force matrix update here so that const references can access + up-to-date informations. + */ + b->GetMatrix(); + b->GetInverseMatrix(); + } +} +void Scene::Update(uint eval_flag) +{ + ScopedSystemProfile(profiler.update); + + { + ScopedSystemProfile(profiler.process_queues); + + ProcessItemRemovalQueue(); + /* + Note: This step is intentionally delayed for one update in order to + evaluate newly activated items before displaying them. + */ + ProcessItemActivationQueue(); + + /* + Store item previous position/rotation (disregarding the inactive flag). + Note: This is done here because the physic system will alter item's matrix. + */ + ArrayListForeachPtr(MItem *, i, active_list) + if (Core::Item *b = i->GetBaseItem()) + b->SetPreviousMatrix(b->GetMatrix()); + } + + // Update clock. + if (clock->GetRefCount() == 1) // Do not update external clock. + clock->Update(); + Time dt = Time::fromSec(clock->GetDeltaf()); + + // Update triggers (result is cached in trigger). + if (eval_flag & SceneUpdateTrigger) + { + ScopedSystemProfile(profiler.update_triggers); + UpdateTriggers(); + } + + // Update physics. + if (physic_world.IsValid() && (eval_flag & SceneUpdatePhysic)) + { + { + ScopedSystemProfile(profiler.physic_step); + physic_world->Step(dt); + } + { + ScopedSystemProfile(profiler.synchronize_physics); + SynchronizePhysics(); + } + } + + // Update item transformations. + { + ScopedSystemProfile(profiler.update_item_transformation); + + // Evaluate items and hierarchies (matrix). + #if 0 + Array > hierarchy_in(active_list.GetCount()), hierarchy_out(active_list.GetCount()); + + int count = 0; + ArrayListForeachPtr(MItem *, i, active_list) + if (Item *b = i->GetBaseItem()) + { + hierarchy_in[count].o = i; + hierarchy_in[count].v = 0; + for (Item *p = b; p; p = p->GetParent()) + ++hierarchy_in[count].v; + ++count; + } + + Array > *sorted = nSort::ByteSort(count, &hierarchy_in, &hierarchy_out); + + for (int n = 0; n < count; ++n) + UpdateItemTransformation((*sorted)[n].o, dt); + #else + ArrayListForeachPtr(MItem *, i, active_list) + UpdateItemTransformation(i, dt); + #endif + } + + { + ScopedSystemProfile(profiler.update_skin); + + // Synchronize all skins with the final matrices. + ArrayListForeachPtr(MItem *, i, active_list) + if (i->GetItemType() == Type_Object) + ((Object *)i->GetBaseItem())->UpdateSkin(); + } + + // Script events. + if (eval_flag & SceneUpdateEvent) + { + { + ScopedSystemProfile(profiler.scene_on_update); + scene_event->OnUpdate(this); + } + + { + ScopedSystemProfile(profiler.items_on_update); + ArrayListForeachPtr(MItem *, i, active_list) + i->item_event->OnUpdate(i); + } + } + + // Update UI. + if (ui) + { + ScopedSystemProfile(profiler.ui_update); + ui->Update(); + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/script/script_debugger.cpp b/include/engine/script/script_debugger.cpp new file mode 100644 index 0000000..f7d9978 --- /dev/null +++ b/include/engine/script/script_debugger.cpp @@ -0,0 +1,159 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_debugger.h" + #include "metafile/nml.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void IDebugger::DereferenceVarTree(const List &tree) +{ + ListForeachPtr(DebuggerVariable *, v, tree) + { + DereferenceVarTree(v->member_list); + v->referenced = false; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SourceBreakpoint *IDebugger::FindSourceBreakpoint(const char *source, int line) +{ + ListForeachPtr(SourceBreakpoint *, bp, source_breakpoint_list) + if ((bp->source == source) && (bp->line == line)) + return bp; + return NULL; +} +SourceBreakpoint *IDebugger::AddSourceBreakpoint(const char *source, int line) +{ + SourceBreakpoint *bp = FindSourceBreakpoint(source, line); + if (!bp) + if ((bp = new SourceBreakpoint(source, line)) != NULL) + source_breakpoint_list.Add(bp); + return bp; +} +bool IDebugger::RemoveSourceBreakpoint(SourceBreakpoint *breakpoint) +{ return source_breakpoint_list.Remove(breakpoint); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool IDebugger::SetBreakpoints(const NML::Tag &tag) +{ + if (tag.name != "SetBreakpoints") + return false; + + source_breakpoint_list.Clear(); + + NMLTagForeach(bp, tag) + if (bp->name == "Breakpoint") + { + NML::Tag *ts = bp->GetTypedTag("Source;", GS::Variant::VariantString), + *tl = bp->GetTypedTag("Line", GS::Variant::VariantInteger); + if (ts && tl) + AddSourceBreakpoint(ts->GetString(), tl->GetInteger()); + } + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String IDebugger::GetStackFrameLocals() +{ + String data; + + data << ""; + + return data; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void IDebugger::SetDebugStackFrame(int level) +{ + if (level == -1) + level = GetStackFrameIndex(); + + if (level != debug_stack_frame) + { + debug_stack_frame = level; + local_var_tree.Clear(); + RefreshStackFrameLocalsCache(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void IDebugger::Suspend() +{ + is_suspended = true; +} +void IDebugger::Resume() +{ + is_suspended = false; + + if (!IsStepping()) + local_var_tree.Clear(); +} +void IDebugger::StepInto() +{ + is_stepping = true; + step_to_callstack_depth = -1; + Resume(); +} +void IDebugger::StepOut() +{ + is_stepping = true; + step_to_callstack_depth = GetCallstackDepth() > 0 ? GetCallstackDepth() - 1 : 0; + Resume(); +} +void IDebugger::Step() +{ + is_stepping = true; + step_to_callstack_depth = GetCallstackDepth(); + Resume(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void IDebugger::CheckSuspendOnBreakpoint(const char *source, int line) +{ + if (SourceBreakpoint *bp = FindSourceBreakpoint(source, line)) + Suspend(); +} +void IDebugger::CheckSuspendOnStep() +{ + if ((GetCallstackDepth() <= step_to_callstack_depth) || (step_to_callstack_depth == -1)) + { + Suspend(); + is_stepping = false; + } + if (IsSuspended()) + RefreshStackFrameLocalsCache(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void IDebugger::Reset() +{ + is_suspended = false; + is_stepping = false; + step_to_callstack_depth = -1; +} +//------------------------------------------------------------------------------ + +IDebugger::IDebugger() +{ + Reset(); +} +IDebugger::~IDebugger() +{} diff --git a/include/engine/script/script_engine_types.cpp b/include/engine/script/script_engine_types.cpp new file mode 100644 index 0000000..16e58dc --- /dev/null +++ b/include/engine/script/script_engine_types.cpp @@ -0,0 +1,89 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_engine_types.h" + + +//------------------------------------------------------------------------------ +const char *GS::Script::CObjectTypeToString(GS::Script::CObjectType type) +{ + static const char *types[typetag_End] = + { + "Undefined", + "Deleted", + + "Engine", + "ScriptVM", + "ResourceSet", + "Project", + "Renderer", + "Raytracer", + "Mixer", + "Scene3d", + "Clock", + + "Font", + "RasterFont", + "Scene2d", + "UICursor", + "Window", + "Item2d", + "Sprite2d", + "Widget", + "SizerWidget", + "ContainerWidget", + "SpacerWidget", + "CanvasWidget", + "TextWidget", + "BitmapWidget", + "CheckWidget", + "Picture", + + "Group", + "Item", + "Camera", + "Object", + "Light", + "Instance", + "Emitter", + "ParticleModel", + "Motion", + "Trigger", + "Path", + + "Sound", + "Shader", + "Texture", + "Geometry", + "GeometryTemplate", + "Material", + "MaterialShader", + "ColShape", + "Constraint", + + "Metafile", + "Metatag", + "FileHandle", + + "InputDevice", + + "EditorPlugin", + + "ProjectScene", + "ProjectLayer", + + "AutomationSource", + "AutomationSourceGroup", + + "ResourceFactories", + + "PeerInterface", + "Peer", + }; + + return types[type]; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/script/script_engine_types.h b/include/engine/script/script_engine_types.h index 81bfc39..d240016 100644 --- a/include/engine/script/script_engine_types.h +++ b/include/engine/script/script_engine_types.h @@ -85,8 +85,6 @@ enum CObjectType typetag_PeerController, typetag_Peer, - typetag_WebSocketManager, - typetag_End }; diff --git a/include/engine/script/script_profiler.cpp b/include/engine/script/script_profiler.cpp new file mode 100644 index 0000000..a42d1a8 --- /dev/null +++ b/include/engine/script/script_profiler.cpp @@ -0,0 +1,136 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_profiler.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +Profiler::FunctionProfile *Profiler::GetFunctionProfile(const char *source, const char *func, int line, FunctionProfile *caller) +{ + // Check for profiled function. + FunctionProfile *profile = NULL; + ListForeachPtr(FunctionProfile *, f_profile, function_map) + if ( + (f_profile->func == func) && + (f_profile->caller_function == caller) + ) + { + profile = f_profile; + break; + } + + // Create a new function profile. + if (!profile) + { + profile = new FunctionProfile(source, func, line); + if (!profile) + __LOG_E__ << "Failed to allocate a new function profile.\n"; + + // Register caller. + profile->caller_function = caller; + + // Add the newly created function as a child of the caller function profile. + if (caller) + caller->callee_function.Add(profile); + + function_map.Add(profile); + } + return profile; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Profiler::Start(const char *session_id) +{ + id = session_id; + function_map.Clear(); + function_list.Clear(); + + current_function_profile = NULL; + + profiler_clock = Platform::Get().GetClock(); + total_clock = 0; + + profiling = true; +} +int Profiler::GetChildTotalClock(FunctionProfile *profile) +{ + int child_total_clock = 0; + ListForeachPtr(FunctionProfile *, c_profile, profile->callee_function) + child_total_clock += GetChildTotalClock(c_profile); + return profile->self_clock + child_total_clock; +} +void Profiler::End() +{ + ListForeachPtr(FunctionProfile *, f_profile, function_map) + f_profile->total_clock = GetChildTotalClock(f_profile); + + // Build the function list from the call graph function map. + ListForeachPtr(FunctionProfile *, f_profile, function_map) + { + // Check list if function is already present. + FunctionProfile *profile = NULL; + ListForeachPtr(FunctionProfile *, l_profile, function_list) + if (l_profile->func == f_profile->func) + { + profile = l_profile; + break; + } + + // If not, create a new list entry. + if (!profile) + { + profile = new FunctionProfile(f_profile->source.c_str(), f_profile->func.c_str(), f_profile->line); + function_list.Add(profile); + } + + // Merge this function contribution. + profile->hit_count += f_profile->hit_count; + profile->self_clock += f_profile->self_clock; + profile->total_clock += f_profile->total_clock; + } + + profiling = false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Profiler::Update(int type, FunctionProfile *profile) +{ + // Update clock. + int current_clock = Platform::Get().GetClock(), + dt_clock = current_clock - profiler_clock; + profiler_clock = current_clock; + + // Update current profile. + if (current_function_profile) + { + current_function_profile->Update(dt_clock, 0); + total_clock += dt_clock; + } + + // Get profile. + switch (type) + { + case 'c': + current_function_profile = profile; + current_function_profile->Hit(); + break; + + case 'r': + current_function_profile = NULL; + break; + case 'l': + break; + } +} +//------------------------------------------------------------------------------ + +Profiler::Profiler() : profiling(false), current_function_profile(NULL) {} diff --git a/include/engine/script/script_unit.cpp b/include/engine/script/script_unit.cpp new file mode 100644 index 0000000..e3291c4 --- /dev/null +++ b/include/engine/script/script_unit.cpp @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_unit.h" + #include "script/script_object.h" + #include "script/script_variant.h" + #include "log/log.h" + + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +bool Unit::SetupFunctionCall(const char *func, const Object *func_object) +{ + if (!vm || !self || !vm->SetupFunctionCall(func, func_object, self)) + return false; + return vm->SetFunctionCallContext(Variant(iface_object, iface_type)); +} +bool Unit::PushUserObjectFunctionCallArgument(void *p, uint type, bool managed) +{ return vm->PushArgument(Variant(p, type)); } +bool Unit::PushFunctionCallArgument(const Variant &arg) +{ return vm->PushArgument(arg); } +bool Unit::DoFunctionCall(Variant *return_value) +{ return vm->DoFunctionCall(return_value); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Unit::Open() +{ + if (!vm) + return false; + if (self) + return true; + + if (script_file.IsEmpty() || script_class.IsEmpty()) + return true; + + // Instantiate class. + if (!vm->CompileFile(script_file) || !vm->SetupFunctionCall(script_class)) + return false; + + Variant rv; + if (!vm->DoFunctionCall(&rv) || (rv.type != Variant::Type_ScriptObject)) + { + vm->Kill(String::Format("Function call to '%s' failed.", script_class.c_str())); + return false; + } + self = rv.object; + rv.object = NULL; // Detach object from the variant so that it does not get deleted. + + // Send parameters to the instance. + ListForeachPtr(GS::Variant *, v, parm_list) + vm->Set(v->id, Variant(*v), self); + + return true; +} +void Unit::Close() +{ + // Note: Do not delete the parameter list from here. + _safe_delete(self); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Unit::Unit(IVM *_vm) : vm(_vm) +{ + iface_object = NULL; + iface_type = (uint)~0; + self = NULL; +} +Unit::~Unit() +{ + ListDeleteAllPtr(GS::Variant *, parm_list) + Close(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/script/script_unit_nml.cpp b/include/engine/script/script_unit_nml.cpp new file mode 100644 index 0000000..3bceca5 --- /dev/null +++ b/include/engine/script/script_unit_nml.cpp @@ -0,0 +1,131 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_unit.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::Script; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool Unit::FromMetaTag(Tag &tag) +{ + if (tag.name != "ScriptUnit") + __ERR__(__LOG_E__ << "Could not parse script unit, incorrect root tag (" << tag.name << ").\n", false) + + script_class.Clear(); + script_file.Clear(); + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "ScriptPath") + script_file = pt->GetString(); + + else if (pt->name == "Script") // legacy path (convert to explicit @core) + { + script_file = pt->GetString(); + if (script_file.StartsWith("builtin/")) + script_file = String("@core/") + script_file; + } + else if (pt->name == "Class") + script_class = pt->GetString(); + + // Parse instance parameters. + else if (pt->name == "ParmList") + { + NMLTagForeach(c, *pt) + { + Tag *id = c->GetTag("Id"), *vl = c->GetTag("Value"); + + if (id && vl) + { + GS::Variant *parm = NULL; + + switch (vl->GetType()) + { + case GS::Variant::VariantBool: + parm = new GS::Variant(id->GetString(), vl->GetBool()); + break; + case GS::Variant::VariantInteger: + parm = new GS::Variant(id->GetString(), vl->GetInteger()); + break; + case GS::Variant::VariantFloat: + parm = new GS::Variant(id->GetString(), vl->GetReal()); + break; + case GS::Variant::VariantString: + parm = new GS::Variant(id->GetString(), vl->GetString()); + break; + + default: + __LOG_W__ << "parameter '" << id->GetString() << "' type is invalid.\n"; + break; + } + if (parm) + parm_list.Add(parm); + } + else __LOG_W__ << "Incomplete script parameter declaration ignored.\n"; + } + } + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Unit::AsMetaTag() const +{ + Tag *root = new Tag("ScriptUnit"); + if (!root) + __ERR__(__LOG_E__ << "Could not serialize script unit. Failed to create root tag.\n", NULL) + + // Store script. + if (!script_file.IsEmpty()) + root->AddChild("ScriptPath", script_file.c_str()); + if (!script_class.IsEmpty()) + root->AddChild("Class", script_class.c_str()); + + // Store instance parameters. + if (parm_list.GetCount()) + { + if (Tag *parmlist = root->AddChild("ParmList")) + { + ListForeachPtr(GS::Variant *, v, parm_list) + { + if (Tag *parm = parmlist->AddChild("Parm")) + { + parm->AddChild("Id", v->id); + + switch (v->GetType()) + { + case GS::Variant::VariantBool: + parm->AddChild("Value", v->b_value); + break; + case GS::Variant::VariantInteger: + parm->AddChild("Value", v->i_value); + break; + case GS::Variant::VariantFloat: + parm->AddChild("Value", v->f_value); + break; + case GS::Variant::VariantString: + parm->AddChild("Value", v->s_value); + break; + } + } + else __LOG_W__ << "Failed to serialize instance parameter '" << v->id << "'.\n"; + } + } + else __LOG_W__ << "Failed to serialize instance parameter list.\n"; + } + + if (!root->GetChildCount()) + _safe_delete(root); + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/script/script_variant.cpp b/include/engine/script/script_variant.cpp new file mode 100644 index 0000000..478e5d9 --- /dev/null +++ b/include/engine/script/script_variant.cpp @@ -0,0 +1,164 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_variant.h" + #include "script/script_object.h" + #include "script/script_vm.h" + + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +bool Variant::operator == (const Variant &b) const +{ + return + ( + (type == b.type) && + (variant == b.variant) && + (object_owner == b.object_owner) && + (object == b.object) && + (ptr == b.ptr) && + (typetag == b.typetag) + ); +} +bool Variant::operator != (const Variant &b) const +{ return !(*this == b); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Variant::Set() +{ + type = Type_None; + if (object_owner) + _safe_delete(object); + object = NULL; +} +void Variant::Set(bool v) +{ + Set(); + type = Type_Variant; + variant = v; +} +void Variant::Set(int v) +{ + Set(); + type = Type_Variant; + variant = v; +} +void Variant::Set(uint v) +{ + Set(); + type = Type_Variant; + variant = (int)v; +} +void Variant::Set(float v) +{ + Set(); + type = Type_Variant; + variant = v; +} +void Variant::Set(const char *v) +{ + Set(); + type = Type_Variant; + variant = v; +} +void Variant::Set(const GS::Variant &v) +{ + Set(); + type = Type_Variant; + variant = v; +} +void Variant::Set(Object *o, bool own) +{ + Set(); + type = Type_ScriptObject; + object_owner = own; + object = o; +} +void Variant::Set(const void *p, size_t size) +{ + Set(); + type = Type_Variant; + variant.SetBinary(p, size); +} +void Variant::Set(void *_ptr, uint _ptr_id) +{ + Set(); + type = Type_UserObject; + ptr = _ptr; + typetag = _ptr_id; + object = NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant::Variant() +{ + type = Type_None; + object = NULL; +} +Variant::Variant(const GS::Variant &v) +{ + type = Type_Variant; + variant = v; + object = NULL; +} +Variant::Variant(bool v) +{ + type = Type_Variant; + variant = v; + object = NULL; +} +Variant::Variant(int v) +{ + type = Type_Variant; + variant = v; + object = NULL; +} +Variant::Variant(uint v) +{ + type = Type_Variant; + variant = (int)v; + object = NULL; +} +Variant::Variant(float v) +{ + type = Type_Variant; + variant = v; + object = NULL; +} +Variant::Variant(const char *v) +{ + type = Type_Variant; + variant = v; + object = NULL; +} +Variant::Variant(Object *o, bool own) +{ + type = Type_ScriptObject; + object_owner = own; + object = o; +} +Variant::Variant(const void *_ptr, size_t size) +{ + type = Type_Variant; + variant.SetBinary(_ptr, size); + object = NULL; +} +Variant::Variant(void *_ptr, uint _ptr_id) +{ + type = Type_UserObject; + ptr = _ptr; + typetag = _ptr_id; + object = NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant::~Variant() +{ Set(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/script/script_vm.cpp b/include/engine/script/script_vm.cpp new file mode 100644 index 0000000..f2b84e5 --- /dev/null +++ b/include/engine/script/script_vm.cpp @@ -0,0 +1,42 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_vm.h" + #include "filesystem/filesystem.h" + #include "platform.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +bool IVM::CompileFile(const char *uri, const Object *context) +{ + Array data; + if (!Platform::Get().io->FileLoad(uri, data)) + return false; + + return Compile(data, data.GetCount(), context, uri); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void IVM::SetDebugInterface(IDebug *i, bool) +{ + debug_interface = i; +} +void IVM::Kill(const char *reason) +{ + if (debug_interface) + debug_interface->OnFatalError(reason); + state = StateDead; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +IVM::IVM() : state(StateOk) {} +IVM::~IVM() {} +//------------------------------------------------------------------------------ diff --git a/include/engine/script/script_vm_debug_profile_base.cpp b/include/engine/script/script_vm_debug_profile_base.cpp new file mode 100644 index 0000000..9a5199e --- /dev/null +++ b/include/engine/script/script_vm_debug_profile_base.cpp @@ -0,0 +1,107 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/script_vm_debug_profile_base.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +String IDebuggerProfiler::ConvertCallStackToMetaString(const AutoList &callstack, int current_stack_frame) +{ + String data = "", frame->source.c_str(), frame->function.c_str(), frame->line); + if (level == current_stack_frame) + data += ""; + data += ">\n"; + ++level; + } + data += ">"; + return data; +} +String IDebuggerProfiler::GetCallstack() +{ + AutoList callstack; + vm->GetCallStack(callstack); + return ConvertCallStackToMetaString(callstack, debugger->GetDebugStackFrame()); +} +String IDebuggerProfiler::GetDebugStackFrameLocals() +{ + debugger->RefreshStackFrameLocalsCache(); + return debugger->GetStackFrameLocals(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void IDebuggerProfiler::Kill() +{ +/* + // Kill the VM in order to escape infinite loops. + SquirrelVM &squirrel_vm = (SquirrelVM &)vm; + if (squirrel_vm.VM()) + sq_setalive(squirrel_vm.VM(), false); +*/ + + // FIXME +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void IDebuggerProfiler::OnStep(char type, const char *source, int line, const char *func) +{ + // FIXME the stack querying system should be abstracted and go through VM interface calls. +/* + if (profiler.IsValid()) + { + HSQUIRRELVM hvm = ((SquirrelVM &)vm).VM(); + + // Update profiler if currently profiling. + if (profiler.IsProfiling()) + { + Profiler::FunctionProfile *profile = 0; + + SQStackInfos si; + int depth = 0; + while (SQ_SUCCEEDED(sq_stackinfos(hvm, depth++, &si))) + ; + while (depth > 0) + if (SQ_SUCCEEDED(sq_stackinfos(hvm, --depth, &si))) + profile = profiler.GetFunctionProfile(si.source, si.funcname, (int)si.line, profile); + + if (profile) + profiler.Update((int)type, profile); + } + } +*/ + + if (debugger.IsValid()) + { + // Check for breakpoint. + debugger->CheckSuspendOnBreakpoint(source, line); + + // Refresh the debugger UI. + debugger->SetDebugStackFrame(debugger->GetStackFrameIndex()); + + if (debugger->IsStepping()) + debugger->CheckSuspendOnStep(); + + if (debugger->IsSuspended()) // might now be suspended after the previous step check + OnSuspendExecution(source, line); + + // Suspend execution. + while (debugger->IsSuspended() && (vm->GetState() != IVM::StateDead)) + if (!OnUpdateSuspendedExecution()) // wait for handler resume signal + debugger->Resume(); + } +} +//------------------------------------------------------------------------------ + +IDebuggerProfiler::IDebuggerProfiler(IVM *script_vm, IDebugger *idbg) : vm(script_vm), debugger(idbg) {} diff --git a/include/engine/script/scripted_object.cpp b/include/engine/script/scripted_object.cpp new file mode 100644 index 0000000..d71298c --- /dev/null +++ b/include/engine/script/scripted_object.cpp @@ -0,0 +1,78 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script/scripted_object.h" + #include "script/script_unit.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::Script; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +Unit *ScriptedObject::AddUnit(Unit *unit) +{ + unit_list.Add(unit); + return unit; +} +bool ScriptedObject::RemoveUnit(Unit *unit) +{ + if (!unit || !unit_list.Remove(unit)) + return false; + _safe_delete(unit); + return true; +} +Unit *ScriptedObject::GetUnit(const char *script_file, const char *script_class) const +{ + ListForeachPtr(Unit *, unit, GetUnitList()) + if ((unit->script_file == script_file) && (unit->script_class == script_class)) + return unit; + return NULL; +} +void ScriptedObject::RemoveAllUnit() +{ ListDeleteAllPtr(Unit *, unit_list) } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool ScriptedObject::FromMetaTag(Tag &tag) +{ + if (tag.name != "ScriptedObject") + __ERR__(__LOG_E__ << "Could not parse scripted object, incorrect root tag (" << tag.name << ").\n", false) + + ListDeleteAllPtr(Unit *, unit_list) + + NMLTagForeach(pt, tag) + { + if (pt->name == "ScriptUnit") + { + if (Unit *unit = AddUnit(NewUnit())) + if (unit->FromMetaTag(*pt)) + unit->Open(); + } + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *ScriptedObject::AsMetaTag() const +{ + if (!GetUnitList().GetCount()) + return NULL; + + Tag *root = new Tag("ScriptedObject"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + // Dump script units. + ListForeachPtr(Unit *, unit, GetUnitList()) + root->AddChild(unit->AsMetaTag()); + + return root; +} +//------------------------------------------------------------------------------ + +ScriptedObject::~ScriptedObject() +{ RemoveAllUnit(); } diff --git a/include/engine/ui/ui.cpp b/include/engine/ui/ui.cpp new file mode 100644 index 0000000..b25432c --- /dev/null +++ b/include/engine/ui/ui.cpp @@ -0,0 +1,174 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui.h" + #include "ui/ui_camera.h" + #include "ui/ui_sprite.h" + #include "ui/ui_ace_manager.h" + #include "ui/ui_scene_script_event.h" + #include "ui/ui_scene_scripted_object.h" + #include "ui/ui_item_script_event.h" + #include "ui/ui_item_scripted_object.h" + #include "script/script_engine_types.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void Scene::SetClock(Core::Clock *c) +{ clock = c ? c : new Core::Clock; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::SetCurrentCamera(Camera *camera) +{ current_camera = camera ? camera : default_camera.c_ptr(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Item *Scene::ItemFromName(const char *name, Item *parent) const +{ + if (parent) + { + ListForeachPtr(Item *, i, parent->GetChildren()) + if (i->name == name) + return i; + } + else + { + ListForeachPtr(Item *, i, item_list) + if (i->name == name) + return i; + } + return NULL; +} +Item *Scene::ItemFromUid(uint uid) const +{ + ListForeachPtr(Item *, i, item_list) + if (i->GetUid() == uid) + return i; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Scene::GetGlobalFadeEffect() const +{ return global_fade_color.w; } +void Scene::SetGlobalFadeEffect(float o) +{ global_fade_color.w = Types::Clamp(o); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::SetupItemComponents(Item *i) +{ + i->scripted_object = new ItemScriptedObject(i, vm); + if (vm) + i->item_event = new ItemScriptEvent; +} +void Scene::AddItem(Item *i, bool setup_components) +{ + i->uid = current_item_uid++; + + if (setup_components) + SetupItemComponents(i); + + g_ui_messenger.BroadcastMessage(UIMsg_AddingItem, this, (void *)i); + item_list.Add(i); + g_ui_messenger.BroadcastMessage(UIMsg_ItemAdded, this, (void *)i); +} +bool Scene::RemoveItem(Item *i) +{ + g_ui_messenger.BroadcastMessage(UIMsg_DeletingItem, this, (void *)i); + + if (lock == i) + lock = NULL; + item_list.Remove(i); + + g_ui_messenger.BroadcastMessage(UIMsg_ItemDeleted, this, (void *)i); + return true; +} +void Scene::DeleteAllItems() +{ + while (List ::Item *i = item_list.GetRoot()) + RemoveItem(i->Object()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Scene::ExecCommand(ACE::Command *cmd, float dt) +{ + float k = dt / cmd->duration_left; + + switch (cmd->code) + { + case ACE_globalfade: + global_fade_color.w = Types::Clamp(global_fade_color.w + (cmd->parm[0] - global_fade_color.w) * k); + return true; + } + return ACE::Unit::ExecCommand(cmd, dt); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::RenderSetup(Core::ResourceFactories *f) +{ + ListForeachPtr(Item *, item, item_list) + item->RenderSetup(f); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::Setup() +{ + scene_event->OnSetup(this); + + // Setup items. + ListForeachPtr(Item *, i, item_list) + i->Setup(); +} +void Scene::Reset() +{ + scene_event->OnReset(this); +} +void Scene::Clear() +{ + scene_event->OnDelete(this); + + window_skin = NULL; + global_fade_color.Set(0, 0, 0, 0); + + item_list.Clear(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Scene::Scene(Script::IVM *script_vm) +{ + vm = script_vm; + lock = NULL; + + current_item_uid = 0; + + clock = new Core::Clock; + + default_camera = new Camera; + default_camera->resolution.Set(1280, 960); + + current_camera = default_camera; + + scene_event = vm ? new SceneScriptEvent : new ISceneEvent; + scripted_object = new SceneScriptedObject(vm, this); + + global_fade_color.Set(0, 0, 0, 0); +} +Scene::~Scene() +{ + Clear(); + if (vm) + vm->InvalidateNativeReference((void *)this); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_ace_manager.cpp b/include/engine/ui/ui_ace_manager.cpp new file mode 100644 index 0000000..16f4da4 --- /dev/null +++ b/include/engine/ui/ui_ace_manager.cpp @@ -0,0 +1,30 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_ace_manager.h" + #include "core/ace.h" + #include "memory/nauto_ptr.h" + + +//------------------------------------------------------------------------------ +GS::ACE::Manager *GS::S2D::ACEManager::Get() +{ + static AutoPtr ui_manager; + + if (!ui_manager) + { + ui_manager = new GS::ACE::Manager; + ui_manager->DefineACECommand("toalpha", ACE_toalpha, 1); + ui_manager->DefineACECommand("toposition", ACE_toposition, 2); + ui_manager->DefineACECommand("toscale", ACE_toscale, 2); + ui_manager->DefineACECommand("toangle", ACE_toangle, 1); + ui_manager->DefineACECommand("show", ACE_show, 0); + ui_manager->DefineACECommand("hide", ACE_hide, 0); + ui_manager->DefineACECommand("globalfade", ACE_globalfade, 1); + } + return ui_manager; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_camera.cpp b/include/engine/ui/ui_camera.cpp new file mode 100644 index 0000000..9ef529a --- /dev/null +++ b/include/engine/ui/ui_camera.cpp @@ -0,0 +1,9 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_camera.h" + + using namespace GS::S2D; diff --git a/include/engine/ui/ui_cursor.cpp b/include/engine/ui/ui_cursor.cpp new file mode 100644 index 0000000..edf3317 --- /dev/null +++ b/include/engine/ui/ui_cursor.cpp @@ -0,0 +1,301 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "ui/ui_cursor.h" + #include "ui/ui.h" + #include "ui/ui_window.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +bool Scene::CallEventHandler(Cursor *cursor, EventCode event_code, EventTable *event_table) +{ + EventHandler *handler = event_table ? event_table->GetHandler(event_code) : NULL; + if (!handler) + return false; + + if (vm->SetupFunctionCall(NULL, handler->GetHandler(), handler->GetContext())) + { + AutoPtr table_object(vm->CreateTable()); + + table_object->Set("sprite", Script::Variant(cursor->current_state.item, Script::typetag_Window)); + table_object->Set("window", Script::Variant(cursor->current_state.item, Script::typetag_Window)); + + table_object->Set("widget", Script::Variant(cursor->current_state.widget, Script::typetag_Widget)); + + if (cursor->current_state.widget) + table_object->Set("id", Script::Variant(cursor->current_state.widget->GetId())); + + table_object->Set("cursor_id", cursor->id); + table_object->Set("x", cursor->current_state.x); + table_object->Set("y", cursor->current_state.y); + table_object->Set("dx", cursor->current_state.x - cursor->previous_state.x); + table_object->Set("dy", cursor->current_state.y - cursor->previous_state.y); + table_object->Set("down", cursor->current_state.down); + + // Cursor position in sprite. + if (cursor->current_state.item) + { + Vector2 c_pos = cursor->current_state.item->ScreenToLocal(Vector2(cursor->current_state.x, cursor->current_state.y)); + table_object->Set("local_x", c_pos.x); + table_object->Set("local_y", c_pos.y); + + if (cursor->previous_state.item == cursor->current_state.item) + { + Vector2 p_pos = cursor->previous_state.item->ScreenToLocal(Vector2(cursor->previous_state.x, cursor->previous_state.y)); + table_object->Set("local_dx", c_pos.x - p_pos.x); + table_object->Set("local_dy", c_pos.y - p_pos.y); + } + else + { + table_object->Set("local_dx", 0); + table_object->Set("local_dy", 0); + } + } + + vm->PushArgument(event_code); + vm->PushArgument(table_object.c_ptr()); + + if (!vm->DoFunctionCall()) + __ERR__(__LOG_E__ << "Event handler (" << event_code << ") call failed. The handler parameters should be (event, table).\n", false) + + return true; + } + return false; +} +void Scene::CallEventHandler(Cursor *cursor, Widget *widget, EventCode event_code, bool can_propagate) +{ + for (Widget *base = widget; base; base = base->GetParent()) + { + if (CallEventHandler(cursor, event_code, base->GetEventTable())) + return; + if (!can_propagate) + break; + } + + // Try the sprite event handler. + if (can_propagate && cursor->current_state.item.IsValid()) + CallEventHandler(cursor, event_code, cursor->current_state.item->GetEventTable()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Widget *Scene::RecurseWidgetBelowCursor(Window *window, Widget *widget, int mx, int my) +{ + if (!window || !widget) + return NULL; + + ListForeachPtr(Widget *, c, widget->GetChildren()) + { + Rect rect(c->GetRect()); + if (!c->IsHidden() && window->LocalToScreen(rect).Inside(mx, my)) + { + Widget *sub_w = RecurseWidgetBelowCursor(window, c, mx, my); + return sub_w ? sub_w : c; + } + } + return widget; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::ProcessCursorEnterLeaveWidget(Cursor *cursor, Window *window, Widget *widget) +{ + if (widget && !widget->IsHidden()) + { + // Process on widget. + iRect screen_rect = window->LocalToScreen(widget->GetRect()); + + if (screen_rect.Inside((int)cursor->current_state.x, (int)cursor->current_state.y)) + { + if (!screen_rect.Inside((int)cursor->previous_state.x, (int)cursor->previous_state.y)) + CallEventHandler(cursor, widget, Event_CursorEnter, false); + } + else + if (screen_rect.Inside((int)cursor->previous_state.x, (int)cursor->previous_state.y)) + CallEventHandler(cursor, widget, Event_CursorLeave, false); + + // Process on widget children. + ListForeachPtr(Widget *, c, widget->GetChildren()) + ProcessCursorEnterLeaveWidget(cursor, window, c); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::UpdateCursor(Cursor *cursor) +{ + Cursor::State &p_state = cursor->previous_state, + &c_state = cursor->current_state, + &down_state = cursor->down_state; + + // Assert lock sprite validity. + if (lock && !item_list.Find(lock)) + lock = NULL; + + // Move cursor position in system reference. + Vector4 c_ui = screen_to_ui * Vector4(c_state.x, c_state.y, 1); +// __LOG__ << "x: " << c_ui.x << ", y: " << c_ui.y << "\n"; + + c_state.x = c_ui.x; + c_state.y = c_ui.y; + + // Determine the current sprite under the cursor. + if (lock) + c_state.item = lock; + + else + { + float min_z_order = FLT_MAX; + + c_state.item = NULL; + for (List ::Item *e = item_list.GetLast(); e; e = e->Previous()) + { + Item *i = e->Object(); + + switch (i->GetItemType()) + { + case Item::Type_Sprite: + case Item::Type_Window: + { + Sprite *s = (Sprite *)i; + + if (s->opacity == 0.0) + break; + if (s->sprite_flags.IsSet(Sprite::FlagNonSensitive)) + break; + + Rect wrect(s->GetRect()); + + if (s->LocalToScreen(wrect).Inside((int)c_state.x, (int)c_state.y) && (min_z_order > s->GetZOrder())) + { + min_z_order = s->GetZOrder(); + c_state.item = s; + } + } + break; + } + } + } + + // Determine the current widget under the cursor. + c_state.widget = NULL; + if (c_state.item && (c_state.item->GetItemType() == Item::Type_Window)) + { + Window *w = (Window *)c_state.item.c_ptr(); + c_state.widget = RecurseWidgetBelowCursor(w, w->GetBaseWidget(), (int)c_state.x, (int)c_state.y); + } + +// State must be complete from here on. + + // Store down state. + if (c_state.down && !p_state.down) + down_state = c_state; + + // Handle cursor up event (done here so that the down_state widget/sprite will always catch the event). + if (p_state.down && !c_state.down) + { + if (down_state.widget) + CallEventHandler(cursor, down_state.widget, Event_CursorUp); + else if (down_state.item) + CallEventHandler(cursor, Event_CursorUp, down_state.item->GetEventTable()); + } + + // Handle hit/down/move cursor events. + if (c_state.widget) + { + if (p_state.down && !c_state.down) + { + if (c_state.widget == down_state.widget) + CallEventHandler(cursor, c_state.widget, Event_CursorHit); + } + + if (!p_state.down && c_state.down) + CallEventHandler(cursor, c_state.widget, Event_CursorDown); + + if ((c_state.widget == p_state.widget) && ((c_state.x != p_state.x) || (c_state.y != p_state.y))) + CallEventHandler(cursor, c_state.widget, Event_CursorMove); + } + else + if (c_state.item) + { + if (p_state.down && !c_state.down) + { + if (c_state.item == down_state.item) + CallEventHandler(cursor, Event_CursorHit, c_state.item->GetEventTable()); + } + + if (!p_state.down && c_state.down) + CallEventHandler(cursor, Event_CursorDown, c_state.item->GetEventTable()); + + if ((c_state.item == p_state.item) && ((c_state.x != p_state.x) || (c_state.y != p_state.y))) + CallEventHandler(cursor, Event_CursorMove, c_state.item->GetEventTable()); + } + + // Handle enter/leave cursor events. + if (c_state.item) + { + if (c_state.item->GetItemType() == Item::Type_Window) + { + Window *w = (Window *)c_state.item.c_ptr(); + ProcessCursorEnterLeaveWidget(cursor, w, w->GetBaseWidget()); + } + if (c_state.item != p_state.item) + CallEventHandler(cursor, Event_CursorEnter, c_state.item->GetEventTable()); + } + if (p_state.item) + { + if (p_state.item->GetItemType() == Item::Type_Window) + { + Window *w = (Window *)p_state.item.c_ptr(); + ProcessCursorEnterLeaveWidget(cursor, w, w->GetBaseWidget()); + } + if (p_state.item != c_state.item) + CallEventHandler(cursor, Event_CursorLeave, p_state.item->GetEventTable()); + } + +#if 0 + if ((c_state.x != p_state.x) || (c_state.y != p_state.y)) + { + __LOG__ << "CURSOR ID = " << cursor->id << "\n"; + __LOG__ << "\n"; + __LOG__ << "X = " << c_state.x << ", Y = " << c_state.y << "\n"; + + if (c_state.item) + __LOG__ << "PX = " << c_state.item->GetPosition().x << ", PY = " << c_state.item->GetPosition().y << "\n"; + + if (Sprite *sprite = (Sprite *)c_state.item) + { + __LOG__ << "SPRITE = "; + if (sprite) + __LOG__ << (int)sprite; + else + __LOG__ << "None"; + } + + __LOG__ << ", WIDGET = "; + if (c_state.widget) + { + __LOG__ << (int)c_state.widget << " (Id = " << c_state.widget->GetId() << "), type = " << c_state.widget->GetType() << "\n"; + nRect rect = c_state.widget->GetRect(); + __LOG__ << "SX = " << rect.sx << ", SY = " << rect.sy << ", W = " << rect.GetWidth() << ", EY = " << rect.GetHeight() << "\n"; + } + else + __LOG__ << "None"; + + __LOG__ << "\n"; + } +#endif + + p_state = c_state; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_event_handler.cpp b/include/engine/ui/ui_event_handler.cpp new file mode 100644 index 0000000..379412b --- /dev/null +++ b/include/engine/ui/ui_event_handler.cpp @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_event_handler.h" + + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +EventHandler *EventTable::GetHandler(EventCode code) const +{ + ListForeachPtr(EventHandler *, h, handler_list) + if (h->GetCode() == code) + return h; + return NULL; +} +EventHandler *EventTable::SetHandler(EventCode code, GS::Script::Object *h, GS::Script::Object *c) +{ + EventHandler *handler = GetHandler(code); + + if (!handler) + { + handler = new EventHandler(code); + handler_list.Add(handler); + } + + handler->handler = h; + handler->context = c; + return handler; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void EventTable::DeleteHandler(EventCode code) +{ + handler_list.Remove(GetHandler(code)); +} +bool EventTable::HasHandlerContext(EventCode code) const +{ + EventHandler *handler = GetHandler(code); + if (!handler) + return false; + return asbool(handler); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_group.cpp b/include/engine/ui/ui_group.cpp new file mode 100644 index 0000000..9aa90ac --- /dev/null +++ b/include/engine/ui/ui_group.cpp @@ -0,0 +1,20 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_group.h" + + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +bool Group::IsMember(const Item *item) const +{ + ListForeachPtr(Item *, i, item_list) + if (i == item) + return true; + return false; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_item.cpp b/include/engine/ui/ui_item.cpp new file mode 100644 index 0000000..97fb5dc --- /dev/null +++ b/include/engine/ui/ui_item.cpp @@ -0,0 +1,162 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_item.h" + #include "ui/ui_item_automated_property_provider.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void Item::SetParent(Item *item) +{ + if (parent) + parent->GetChildren().Remove(this); + + if ((parent = item) != NULL) + parent->GetChildren().Add(this); +} +bool Item::Inherits(const Item *item) const +{ + if (this == item) + return true; + for (Item *p = GetParent(); p; p = p->GetParent()) + if (p == item) + return true; + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Item::SnapshotTransformation(const Matrix3 &matrix) +{ + Vector4 p = matrix.GetRow(2); + SetPosition(p.x, p.y); + + Vector2 u(matrix.m[0][0], matrix.m[1][0]), + v(matrix.m[0][1], matrix.m[1][1]); + + SetScale(u.Len(), v.Len()); + + u.Normalize(); + + float a = Math::ACos(u.x); + if (u.y < 0.f) + a = 2.f * Math::Pi - a; + + SetRotation(a); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Item::ComputeMatrix() +{ + local_matrix = Matrix3::RotationMatrixZAxis(angle); + local_matrix.m[0][2] = position.x; + local_matrix.m[1][2] = position.y; + local_matrix = local_matrix * Matrix3(scale.x, 0, 0, 0, scale.y, 0, -pivot.x * scale.x, -pivot.y * scale.y, 1); + + if (GetParent()) + { + GetParent()->ComputeMatrix(); + matrix = GetParent()->GetMatrix() * local_matrix; + } + else + matrix = local_matrix; + + matrix.Inverse(imatrix); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +iRect Item::GetRect() const +{ return iRect(0, 0, (int)size.x, (int)size.y); } +iRect Item::GetScreenRect() const +{ + Vector4 _v[4], _o[4]; + + _v[0].Set(0, 0, 1); + _v[1].Set(size.x, 0, 1); + _v[2].Set(size.x, size.y, 1); + _v[3].Set(0, size.y, 1); + + matrix.Apply(_o, _v, 4); + + Vector4 mn = _o[0], mx = _o[0]; + for (int n = 1; n < 4; ++n) + { + mn = Vector4::Minimum(mn, _o[n]); + mx = Vector4::Maximum(mx, _o[n]); + } + return iRect((int)mn.x, (int)mn.y, (int)mx.x, (int)mx.y); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +iRect Item::LocalToScreen(const iRect &r) const +{ + Vector4 sxy((float)r.sx, (float)r.sy, 1, 1), exy((float)r.ex, (float)r.ey, 1, 1); + Vector4 tsxy = sxy * matrix, texy = exy * matrix; + return iRect((int)tsxy.x, (int)tsxy.y, (int)texy.x, (int)texy.y); +} +iRect Item::ScreenToLocal(const iRect &r) const +{ + Vector4 sxy((float)r.sx, (float)r.sy, 1, 1), exy((float)r.ex, (float)r.ey, 1, 1); + Vector4 tsxy = sxy * imatrix, texy = exy * imatrix; + return iRect((int)tsxy.x, (int)tsxy.y, (int)texy.x, (int)texy.y); +} +Vector2 Item::LocalToScreen(const Vector2 &v) const +{ + Vector4 o = Vector4(v.x, v.y, 1) * matrix; + return Vector2(o.x, o.y); +} +Vector2 Item::ScreenToLocal(const Vector2 &v) const +{ + Vector4 o = Vector4(v.x, v.y, 1) * imatrix; + return Vector2(o.x, o.y); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Item::Setup() +{ + item_event->OnSetup(this); + item_event->OnSetupDone(this); +} +void Item::Reset() +{ + SetPivot(0, 0); + SetScale(1, 1); + SetZOrder(0.5); + SetRotation(0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Item::Item() +{ + uid = uint(~0); + + item_flags.Raise(Flag_ItemActive); + + type = Type_None; + + parent = 0; + Reset(); + + item_event = new IItemEvent; + automation_player = new GS::Automation::Player; + automation_player->property_provider = new Automation::ItemPropertyProvider(this); +} +Item::~Item() +{ + SetParent(NULL); + ListForeachPtr(Item *, c, children) + c->SetParent(NULL); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_item_automated_property_provider.cpp b/include/engine/ui/ui_item_automated_property_provider.cpp new file mode 100644 index 0000000..d7bdd86 --- /dev/null +++ b/include/engine/ui/ui_item_automated_property_provider.cpp @@ -0,0 +1,50 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_item_automated_property_provider.h" + #include "ui/ui_item.h" + + using GS::Quaternion; + using namespace GS::Core; + using namespace GS::S2D::Automation; + + +//------------------------------------------------------------------------------ +bool ItemPropertyProvider::GetProperty(MotionChannel::Type type, float &v) +{ + switch (type) + { + case MotionChannel::XPos: v = item->GetPosition().x; return true; + case MotionChannel::YPos: v = item->GetPosition().y; return true; + case MotionChannel::ZRot: v = item->GetRotation(); return true; + case MotionChannel::XScl: v = item->GetScale().x; return true; + case MotionChannel::YScl: v = item->GetScale().y; return true; + } + return false; +} +bool ItemPropertyProvider::SetProperty(MotionChannel::Type type, float v) +{ + Vector2 t; + switch (type) + { + case MotionChannel::XPos: t = item->GetPosition(); item->SetPosition(v, t.y); return true; + case MotionChannel::YPos: t = item->GetPosition(); item->SetPosition(t.x, v); return true; + case MotionChannel::ZRot: item->SetRotation(v); return true; + case MotionChannel::XScl: t = item->GetScale(); item->SetScale(v, t.y); return true; + case MotionChannel::YScl: t = item->GetScale(); item->SetScale(t.x, v); return true; + } + return false; +} +Quaternion ItemPropertyProvider::GetRotation() const +{ + return Quaternion::FromEuler(0, 0, item->GetRotation()); +} +bool ItemPropertyProvider::SetRotation(const Quaternion &q) +{ + item->SetRotation(q.AsMatrix3().AsEuler().z); + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_item_nml.cpp b/include/engine/ui/ui_item_nml.cpp new file mode 100644 index 0000000..e751f82 --- /dev/null +++ b/include/engine/ui/ui_item_nml.cpp @@ -0,0 +1,93 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_item.h" + #include "math/vector_nml.h" + #include "log/log.h" + + using namespace GS::S2D; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool Item::FromMetaTag(Tag &tag) +{ + if (tag.name != "Item") + __ERR__(__LOG_E__ << "Could not parse sprite, incorrect root tag (" << tag.name << ").\n", false) + + Reset(); + + NMLTagForeach(pt, tag) + { + if (pt->name == "Uid") + uid = pt->GetUnsigned(); + else if (pt->name == "Name") + name = pt->GetString(); + + else if (pt->name == "Active") + item_flags |= Flag_ItemActive; + + else if (pt->name == "Position") + tVectorFromMetaTag(position, *pt); + else if (pt->name == "Size") + { + Vector2 v; + tVectorFromMetaTag(v, *pt); + SetSize(v.x, v.y); + } + else if (pt->name == "Pivot") + tVectorFromMetaTag(pivot, *pt); + else if (pt->name == "Scale") + tVectorFromMetaTag(scale, *pt); + else if (pt->name == "Angle") + angle = pt->GetReal(); + else if (pt->name == "ZOrder") + zorder = pt->GetReal(); + + else if (pt->name == "ScriptedObject") + { + if (scripted_object) + scripted_object->FromMetaTag(*pt); + } + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Item::AsMetaTag() const +{ + Tag *root = new Tag("Item"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild("Name", name.toUtf8()); + root->AddChild("Uid", GetUid()); + + if (item_flags.IsSet(Flag_ItemActive)) + root->AddChild("Active"); + + root->AddChild(tVectorAsMetaTag(position, "Position")); + root->AddChild(tVectorAsMetaTag(size, "Size")); + + if ((pivot.x != 0) || (pivot.y != 0)) + root->AddChild(tVectorAsMetaTag(pivot, "Pivot")); + if ((scale.x != 1) || (scale.y != 1)) + root->AddChild(tVectorAsMetaTag(scale, "Scale")); + + if (GetZOrder() != 0.5) + root->AddChild("ZOrder", GetZOrder()); + if (GetRotation() != 0) + root->AddChild("Angle", angle); + + // Components. + if (scripted_object.IsValid()) + root->AddChild(scripted_object->AsMetaTag()); + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_item_script_event.cpp b/include/engine/ui/ui_item_script_event.cpp new file mode 100644 index 0000000..e1e053e --- /dev/null +++ b/include/engine/ui/ui_item_script_event.cpp @@ -0,0 +1,81 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_item_script_event.h" + #include "ui/ui_item_scripted_object.h" + #include "ui/ui_item_script_unit.h" + #include "ui/ui_item.h" + #include "physic/physic_world.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + + using namespace GS::Script; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void ItemScriptEvent::OnSetup(Item *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnSetup")) + unit->DoFunctionCall(); +} +void ItemScriptEvent::OnSetupDone(Item *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnSetupDone")) + unit->DoFunctionCall(); +} +void ItemScriptEvent::OnReset(Item *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnReset")) + unit->DoFunctionCall(); +} +void ItemScriptEvent::OnActivate(Item *item, bool activate) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((ItemScriptUnit *)unit)->activation_callback && unit->SetupFunctionCall("OnActivate", ((ItemScriptUnit *)unit)->activation_callback)) + { + unit->PushFunctionCallArgument(activate); + unit->DoFunctionCall(); + } +} +void ItemScriptEvent::OnUpdate(Item *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((ItemScriptUnit *)unit)->update_callback && unit->SetupFunctionCall("OnUpdate", ((ItemScriptUnit *)unit)->update_callback)) + unit->DoFunctionCall(); +} +void ItemScriptEvent::OnPhysicStep(Item *item, bool step_taken) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((ItemScriptUnit *)unit)->physic_callback && unit->SetupFunctionCall("OnPhysicStep", ((ItemScriptUnit *)unit)->physic_callback)) + { + unit->PushFunctionCallArgument(step_taken); + unit->DoFunctionCall(); + } +} + +void ItemScriptEvent::OnRenderDone(Item *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnRenderDone")) + unit->DoFunctionCall(); +} +void ItemScriptEvent::OnRenderUser(Item *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (((ItemScriptUnit *)unit)->render_user_callback && unit->SetupFunctionCall("OnRenderUser", ((ItemScriptUnit *)unit)->render_user_callback)) + unit->DoFunctionCall(); +} +void ItemScriptEvent::OnDelete(Item *item) +{ + ListForeachPtr(Unit *, unit, item->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnDelete")) + unit->DoFunctionCall(); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_item_script_unit.cpp b/include/engine/ui/ui_item_script_unit.cpp new file mode 100644 index 0000000..367e761 --- /dev/null +++ b/include/engine/ui/ui_item_script_unit.cpp @@ -0,0 +1,45 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_item_script_unit.h" + + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +bool ItemScriptUnit::Open() +{ + if (!Script::Unit::Open()) + return false; + + update_callback = vm->GetObjectFromName("OnUpdate", self); + trigger_callback = vm->GetObjectFromName("OnTrigger", self); + activation_callback = vm->GetObjectFromName("OnActivate", self); + physic_callback = vm->GetObjectFromName("OnPhysicStep", self); + collision_callback = vm->GetObjectFromName("OnCollision", self); + collisionex_callback = vm->GetObjectFromName("OnCollisionEx", self); + render_user_callback = vm->GetObjectFromName("OnRenderUser", self); + return true; +} +void ItemScriptUnit::Close() +{ + update_callback = NULL; + trigger_callback = NULL; + activation_callback = NULL; + physic_callback = NULL; + physic_sleep_callback = NULL; + collision_callback = NULL; + collisionex_callback = NULL; + render_user_callback = NULL; + + Script::Unit::Close(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ItemScriptUnit::ItemScriptUnit(GS::Script::IVM *vm) : Unit(vm) {} +ItemScriptUnit::~ItemScriptUnit() { Close(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_item_scripted_object.cpp b/include/engine/ui/ui_item_scripted_object.cpp new file mode 100644 index 0000000..235e5b9 --- /dev/null +++ b/include/engine/ui/ui_item_scripted_object.cpp @@ -0,0 +1,27 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_item_scripted_object.h" + #include "ui/ui_item_script_unit.h" + #include "ui/ui_item.h" + #include "script/script_engine_types.h" + #include "log/log.h" + + using namespace GS::Script; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +Unit *ItemScriptedObject::NewUnit() const +{ + Unit *unit = new ItemScriptUnit(vm); + if (!unit) + __ERR__(__LOG_E__ << "Failed to allocate new item script unit.", NULL); + + unit->SetInterfaceObject(item, Script::typetag_UIItem); + return unit; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_message.cpp b/include/engine/ui/ui_message.cpp new file mode 100644 index 0000000..88b4cc8 --- /dev/null +++ b/include/engine/ui/ui_message.cpp @@ -0,0 +1,11 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_message.h" + + using namespace GS::S2D; + + GS::Messaging::Broadcaster GS::S2D::g_ui_messenger; diff --git a/include/engine/ui/ui_nml.cpp b/include/engine/ui/ui_nml.cpp new file mode 100644 index 0000000..5481f3a --- /dev/null +++ b/include/engine/ui/ui_nml.cpp @@ -0,0 +1,216 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui.h" + #include "ui/ui_window.h" + #include "ui/ui_group.h" + #include "core/tool_mode.h" + #include "script/scripted_object.h" + #include "script/script_unit.h" + #include "timing/benchmark.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::NML; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +bool Scene::FromMetaFileStoreGroup(const char *path, Group **group, uint flag, GS::ToolMode tool_mode, int load_level) +{ + NML::File file; + if (!NML::Parser::Load(path, file)) + return false; + + if (Tag *scene_tag = file.GetTag("Scene2D")) + { + if (FromMetaTagStoreGroup(*scene_tag, group, flag, tool_mode, load_level)) + name = path; + } + else + __ERR__(__LOG_E__ << "No tag in '" << path << "'.\n", false) + + if (group && group[0]) + group[0]->name = path; + + return true; +} +static bool ShouldLoadItem(GS::ToolMode mode, Tag *pt, uint flag, int load_level) +{ + if (pt->GetTag("Item:ToolSpecific;") || pt->GetTag("Item:Helper;")) + { + if (!(flag & SceneIOHelper)) + return false; + + // Do not load tool specific items in no tool or project preview modes. + if ((mode == GS::NoTool) || (mode == GS::ToolProjectPreview)) + return false; + + // Do not load tool specific items in no tool mode above the first load level. + if (load_level > 0) + return false; + } + return true; +} +template static T *LoadItemDerived(Scene *scene, T *i, GS::Map &uid_map, Tag *t, uint type_flag, const uint load_flag, int load_level, GS::ToolMode tool_mode) +{ + if (!(load_flag & type_flag) || !ShouldLoadItem(tool_mode, t, load_flag, load_level)) + { + delete i; + return NULL; + } + + scene->SetupItemComponents(i); + + if (i->FromMetaTag(*t)) + { + uint olduid = i->GetUid(); // uid from source scene + scene->AddItem(i, false); // add to live scene + uid_map.Add(olduid, i->GetUid()); // store map from source to live scene + } + return i; +} +bool Scene::FromMetaTagStoreGroup(const Tag &tag, Group **group, uint load_flag, GS::ToolMode tool_mode, int load_level) +{ + if (tag.name != "Scene2D") + __ERR__(__LOG_E__ << "Could not parse UI scene, incorrect root tag (" << tag.name << ").\n", false) + + Benchmark bench(true); + + // Read items and setup uid remap array. + Map uid_map; + + if (Tag *itag = tag.GetTag("Items")) + { + // Item count in scene. + uint item_to_load = 0; + NMLTagForeach(pt, *itag) + if (Tag *item_tag = pt->GetTag("Item;")) + item_to_load++; + + NMLTagForeach(pt, *itag) + { + Item *citem = NULL; + + if (pt->name == "Sprite") + citem = LoadItemDerived(this, new Sprite, uid_map, pt, SceneIOSprite, load_flag, load_level, tool_mode); + else if (pt->name == "Window") + citem = LoadItemDerived(this, new Window, uid_map, pt, SceneIOWindow, load_flag, load_level, tool_mode); + else + __LOG_W__ << "Unexpected <" << pt->name << "> sub-tag in .\n"; + + if (citem) + { + // Add item to the scene group. + if (group && group[0]) + group[0]->item_list.Add(citem); + } + } + } + + // Script unit. + if (load_flag & SceneIOScript) + { + if (Tag *stag = tag.GetTag("ScriptedObject")) + scripted_object->FromMetaTag(*stag); + + #if 1 // Compatibility + else + if (Tag *stag = tag.GetTag("ScriptUnit")) + if (Script::Unit *unit = scripted_object->AddUnit(scripted_object->NewUnit())) + unit->FromMetaTag(*stag); + #endif + } + + // Motion sets. + if (load_flag & SceneIOMotion) + if (Tag *ctag = tag.GetTag("SceneMotionContainer")) + motion.FromMetaTag(*ctag, &uid_map); + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Scene::IsItemToBeSaved(Item *i, const Group *group, uint flag) const +{ + if (!i) + return false; + + // Filter out irrelevant items. + if (group && !group->IsMember(i)) + return false; + + switch (i->GetItemType()) + { + case Item::Type_Sprite: if (!(flag & SceneIOSprite)) return false; break; + case Item::Type_Window: if (!(flag & SceneIOWindow)) return false; break; + } + return true; +} +Tag *Scene::LinkInfoAsMetaTag(Item *i, const Group *group, uint flag) const +{ + if (!IsItemToBeSaved(i, group, flag)) + return NULL; + + Item *l = i->GetParent(); + if (!l) + return NULL; + + if (!IsItemToBeSaved(l, group, flag)) + return NULL; + + // Save link information. + Tag *tag = new Tag("Link"); + if (tag) + { + tag->AddChild("Item", i->GetUid()); + tag->AddChild("Link", l->GetUid()); + } + return tag; +} +Tag *Scene::AsMetaTag(const Group *group, uint save_flag, GS::ToolMode tool_mode) const +{ + Tag *root = new Tag("Scene2D"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + // Write script object. + if (scripted_object.IsValid() && !group) + root->AddChild(scripted_object->AsMetaTag()); + + // Write motion sets. + if (save_flag & SceneIOMotion) + root->AddChild(motion.AsMetaTag()); + + // Write managed items. + if (Tag *itag = root->AddChild("Items")) + ListForeachPtr(Item *, i, item_list) + { + if (group && !group->item_list.Find(i)) + continue; + + switch (i->GetItemType()) + { + case Item::Type_Sprite: if (!(save_flag & SceneIOSprite)) continue; break; + case Item::Type_Window: if (!(save_flag & SceneIOWindow)) continue; break; + } + + itag->AddChild(i->AsMetaTag()); + } + else + __ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL); + + // Write link informations. + if (Tag *ltag = root->AddChild("Links")) + ListForeachPtr(Item *, i, item_list) + ltag->AddChild(LinkInfoAsMetaTag(i, group, save_flag)); + else + __ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL) + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_profiler.cpp b/include/engine/ui/ui_profiler.cpp new file mode 100644 index 0000000..4add972 --- /dev/null +++ b/include/engine/ui/ui_profiler.cpp @@ -0,0 +1,24 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui.h" + #include "core/core_profiler.h" + #include "core/raster_font.h" + #include "core/renderer.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void S2D::Scene::DrawProfilerText(Renderer &r, Render::RasterFont *font[2], float &x, float &y) +{ + Color title_color(0.75, 0.5, 1); + Renderer::WriterConfig config(false); + + r.Write(*font[1], "Scene 2D:\n\n", x, y, config, 1, &title_color); + r.Write(*font[0], String::Format("Window count = %d\n\n", item_list.GetCount()), x, y, config, 1, &Color::Yellow); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_render.cpp b/include/engine/ui/ui_render.cpp new file mode 100644 index 0000000..cc8feed --- /dev/null +++ b/include/engine/ui/ui_render.cpp @@ -0,0 +1,89 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui.h" + #include "ui/ui_camera.h" + #include "ui/ui_sprite.h" + #include "core/renderer.h" + #include "gpu/gpu_triangle_batch.h" + + using namespace GS; + using namespace S2D; + + +//------------------------------------------------------------------------------ +static float ItemCompareDrawOrder(const S2D::Item *c, const S2D::Item *n) +{ return -(c->GetZOrder() - n->GetZOrder()); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::SetRenderMatrices(Renderer &renderer) +{ + const Vector2 &resolution = current_camera->resolution; + float k_ar = (renderer.GetOutputAspectRatio() * renderer.GetGlobalAspectRatio()) / (resolution.y / resolution.x); + + // UI to normalized screen and back. + ui_to_screen = Matrix3::TranslationMatrix(Vector2(0.5f, 0.5f)) * + ( + (offset_matrix * Matrix3::ScaleMatrix(Vector2(k_ar / resolution.x, 1.f / resolution.y))) * + (Matrix3::TranslationMatrix(Vector2(-resolution.x * 0.5f, -resolution.y * 0.5f)) * current_camera->GetInverseMatrix()) + ); + ui_to_screen.Inverse(screen_to_ui); + + // Render matrices. + Matrix4 identity(Matrix4::IdentityMatrix()); + renderer.SetViewMatrix(identity, &identity); + renderer.SetWorldMatrix(identity, &identity); + + Matrix3 projection(2.f * k_ar / resolution.x, 0, 0, 0, -2.f / resolution.y, 0, -1.f * k_ar, 1.f, 0.0f); // z = 0.0f + projection = offset_matrix * (projection * current_camera->GetInverseMatrix()); + renderer.SetProjectionMatrix(Matrix4::FromMatrix3(projection)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::Render(Renderer &renderer, GPU::TriangleBatch *batch) +{ + // Enforce window positioning. + item_list.MergeSort(ItemCompareDrawOrder); + + // Render items. + SetRenderMatrices(renderer); + ListForeachPtr(Item *, i, item_list) + if (i->item_flags.IsSet(Item::Flag_ItemActive)) + switch (i->GetItemType()) + { + case Item::Type_Sprite: + case Item::Type_Window: + ((Sprite *)i)->Render(renderer, batch); + break; + } + + if (batch) + batch->Flush(); +} +void Scene::RenderGlobalFade(Renderer &renderer) +{ + if (global_fade_color.w < 0.01f) + return; + + renderer.SetProjectionMatrix(Matrix4::IdentityMatrix()); + + // Setup attributes. + Vector4 vtx_attr[4]; + vtx_attr[0].Set(-1, -1, 1); + vtx_attr[1].Set(1, -1, 1); + vtx_attr[2].Set(1, 1, 1); + vtx_attr[3].Set(-1, 1, 1); + + Color color_attr[4]; + for (uint n = 0; n < 4; ++n) + color_attr[n] = global_fade_color; + + ushort idx[6] = { 2, 1, 0, 3, 2, 0 }; + renderer.DrawTriangle(2, vtx_attr, idx, color_attr, NULL, NULL, Core::Material::Blend_Alpha, Core::Material::Render_NoZTest); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_scene_script_event.cpp b/include/engine/ui/ui_scene_script_event.cpp new file mode 100644 index 0000000..417e90e --- /dev/null +++ b/include/engine/ui/ui_scene_script_event.cpp @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_scene_script_event.h" + #include "ui/ui_script_unit.h" + #include "ui/ui.h" + #include "script/scripted_object.h" + + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void SceneScriptEvent::OnSetup(Scene *scene) +{ + ListForeachPtr(Script::Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnSetup")) + unit->DoFunctionCall(0); +} +void SceneScriptEvent::OnReset(Scene *scene) +{ + ListForeachPtr(Script::Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnReset")) + unit->DoFunctionCall(0); +} +void SceneScriptEvent::OnUpdate(Scene *scene) +{ + ListForeachPtr(Script::Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnUpdate", ((SceneUnit *)unit)->frame_callback)) + unit->DoFunctionCall(0); +} +void SceneScriptEvent::OnDelete(Scene *scene) +{ + ListForeachPtr(Script::Unit *, unit, scene->scripted_object->GetUnitList()) + if (unit->SetupFunctionCall("OnDelete")) + unit->DoFunctionCall(0); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_scene_scripted_object.cpp b/include/engine/ui/ui_scene_scripted_object.cpp new file mode 100644 index 0000000..76e43c1 --- /dev/null +++ b/include/engine/ui/ui_scene_scripted_object.cpp @@ -0,0 +1,25 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_scene_scripted_object.h" + #include "ui/ui_script_unit.h" + #include "script/script_engine_types.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +Script::Unit *SceneScriptedObject::NewUnit() const +{ + Script::Unit *unit = new SceneUnit(vm); + if (!unit) + __ERR__(__LOG_E__ << "Failed to allocate new UI scene script unit.", NULL); + unit->SetInterfaceObject(scene, Script::typetag_Scene2d); + return unit; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_script_unit.cpp b/include/engine/ui/ui_script_unit.cpp new file mode 100644 index 0000000..b935242 --- /dev/null +++ b/include/engine/ui/ui_script_unit.cpp @@ -0,0 +1,32 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_script_unit.h" + + using namespace GS::Script; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +bool SceneUnit::Open() +{ + if (!Unit::Open()) + return false; + + frame_callback = vm->GetObjectFromName("OnUpdate", self); + return true; +} +void SceneUnit::Close() +{ + frame_callback = NULL; + Unit::Close(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SceneUnit::SceneUnit(IVM *vm) : Unit(vm) {} +SceneUnit::~SceneUnit() { Close(); } +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_sprite.cpp b/include/engine/ui/ui_sprite.cpp new file mode 100644 index 0000000..9c8b08d --- /dev/null +++ b/include/engine/ui/ui_sprite.cpp @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_sprite.h" + #include "ui/ui_ace_manager.h" + #include "core/render_resource_factory.h" + #include "core/camera.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void Sprite::RenderSetup(Core::ResourceFactories *f) +{ + if ((render_data = new RenderData)) + if (f && f->render) + if (!texture.IsEmpty()) + render_data->texture = f->render->LoadTexture(texture); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Sprite::ExecCommand(ACE::Command *cmd, float dt) +{ + float k = dt / cmd->duration_left; + + switch (cmd->code) + { + case ACE_toalpha: + opacity = Types::Clamp(opacity + (cmd->parm[0] - opacity) * k); + return true; + + case ACE_toposition: + position.x += (cmd->parm[0] - position.x) * k; + position.y += (cmd->parm[1] - position.y) * k; + SetPosition(position.x, position.y); + return true; + + case ACE_toscale: + scale.x += (cmd->parm[0] - scale.x) * k; + scale.y += (cmd->parm[1] - scale.y) * k; + return true; + + case ACE_toangle: + angle += (Units::Deg(cmd->parm[0]) - angle) * k; + SetRotation(angle); + return true; + } + return ACE::Unit::ExecCommand(cmd, dt); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Sprite::Sprite() +{ + opacity = 1; + + uv_origin.Set(0, 0); + + type = Type_Sprite; + event_table = new EventTable; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_sprite_nml.cpp b/include/engine/ui/ui_sprite_nml.cpp new file mode 100644 index 0000000..5a8d11d --- /dev/null +++ b/include/engine/ui/ui_sprite_nml.cpp @@ -0,0 +1,95 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_sprite.h" + #include "ui/ui.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::S2D; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +bool Sprite::FromMetaTag(Tag &tag) +{ + if (tag.name != "Sprite") + __ERR__(__LOG_E__ << "Could not parse sprite, incorrect root tag (" << tag.name << ").\n", false) + + opacity = 1.f; + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "Item") + Item::FromMetaTag(*pt); + + else if (pt->name == "Opacity") + opacity = pt->GetReal(); + + else if (pt->name == "Flag") + { + NMLTagForeach(st, *pt) + { + if (st->name == "FlipU") + sprite_flags.Raise(FlagFlipU, true); + else if (st->name == "FlipV") + sprite_flags.Raise(FlagFlipV, true); + + else if (st->name == "Opaque") + sprite_flags |= FlagBlendOpaque; + else if (st->name == "Additive") + sprite_flags |= FlagBlendAdditive; + + else if (st->name == "NonSensitive") + sprite_flags |= FlagNonSensitive; + else if (st->name == "ResolutionInvariant") + sprite_flags |= FlagResolutionInvariant; + else if (st->name == "TransformUV") + sprite_flags |= FlagTransformUV; + } + } + else if (pt->name == "Texture") + texture = pt->GetString(); + + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Sprite::AsMetaTag() const +{ + Tag *root = new Tag("Sprite"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(Item::AsMetaTag()); + + if (opacity != 1.f) + root->AddChild("Opacity", opacity); + if ((type == Type_Sprite) && !texture.IsEmpty()) + root->AddChild("Texture", texture.c_str()); + + if (Tag *flag_tag = root->AddChild("Flag")) + { + if (sprite_flags.IsSet(FlagFlipU)) + flag_tag->AddChild("FlipU"); + if (sprite_flags.IsSet(FlagFlipV)) + flag_tag->AddChild("FlipV"); + if (sprite_flags.IsSet(FlagNonSensitive)) + flag_tag->AddChild("NonSensitive"); + if (sprite_flags.IsSet(FlagBlendAdditive)) + flag_tag->AddChild("Additive"); + if (sprite_flags.IsSet(FlagResolutionInvariant)) + flag_tag->AddChild("ResolutionInvariant"); + if (sprite_flags.IsSet(FlagTransformUV)) + flag_tag->AddChild("TransformUV"); + } + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_sprite_render.cpp b/include/engine/ui/ui_sprite_render.cpp new file mode 100644 index 0000000..03de67e --- /dev/null +++ b/include/engine/ui/ui_sprite_render.cpp @@ -0,0 +1,113 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_sprite.h" + #include "gpu/gpu_triangle_batch.h" + #include "core/renderer.h" + + using namespace GS::Render; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void Sprite::Render(Renderer &render, GS::GPU::TriangleBatch *batch) +{ + if (render_data.IsNull()) + return; + if (opacity < 0.003f) + return; + + ComputeMatrix(); + + // Test visibility. + bool should_show = true; + + float final_opacity = opacity; + for (Item *p = GetParent(); p; p = p->GetParent()) + if (Sprite *sp = (Sprite *)p) + final_opacity *= sp->opacity; + + if (final_opacity < 0.003f) + should_show = false; + + // Compute hierarchy matrix, opacity and visibility. + if (sprite_flags.IsSet(FlagSnapToPixel)) + { + matrix.m[0][2] = Math::Floor(matrix.m[0][2]); + matrix.m[1][2] = Math::Floor(matrix.m[1][2]); + } + + if (!should_show) // [EJ] do not move before matrix is updated + return; + + Texture *t = render_data->texture; + if (t && t->format != Texture::FormatInvalid) + { + Vector4 vtx[4]; + vtx[0].Set(0, 0, 1); + vtx[1].Set(size.x, 0, 1); + vtx[2].Set(size.x, size.y, 1); + vtx[3].Set(0, size.y, 1); + + Vector4 vtx_attr[4]; + matrix.Apply(vtx_attr, vtx, 4); // transform on the CPU for the batch system + + Color color_attr[4]; + for (uint n = 0; n < 4; ++n) + color_attr[n].Set(1, 1, 1, final_opacity); + + Vector2 uv_attr[4]; + + float su = uv_origin.x / float(t->GetWidth()), + sv = uv_origin.y / float(t->GetHeight()), + eu = (uv_origin.x + size.x) / float(t->GetWidth()), + ev = (uv_origin.y + size.y) / float(t->GetHeight()); + + if (sprite_flags.IsSet(FlagFlipU)) Types::swap(su, eu); + if (sprite_flags.IsSet(FlagFlipV)) Types::swap(sv, ev); + + if (sprite_flags.IsSet(FlagTransformUV)) + { + Vector4 s_uv[4], o_uv[4]; + + s_uv[0].Set(su, sv, 1); + s_uv[1].Set(eu, sv, 1); + s_uv[2].Set(eu, ev, 1); + s_uv[3].Set(su, ev, 1); + + uv_matrix.Apply(o_uv, s_uv, 4); + for (int n = 0; n < 4; ++n) + uv_attr[n].Set(o_uv[n].x, o_uv[n].y); + } + else + { + uv_attr[0].Set(su, sv); + uv_attr[1].Set(eu, sv); + uv_attr[2].Set(eu, ev); + uv_attr[3].Set(su, ev); + } + + // Blend mode. + using Core::Material; + + Material::BlendOperator blend_op; + + if (sprite_flags.IsSet(FlagBlendOpaque)) + blend_op = final_opacity < 1.f ? Material::Blend_Alpha : Material::Blend_None; + else blend_op = sprite_flags.IsSet(FlagBlendAdditive) ? Material::Blend_Add : Material::Blend_Alpha; + + Material::RenderWord render_word = Material::RenderWord(Material::Render_NoZWrite | Material::Render_NoZTest); + + // Draw. + ushort idx[6] = { 0, 1, 2, 0, 2, 3 }; + + if (batch) + batch->DrawTriangle(2, 4, vtx_attr, idx, color_attr, uv_attr, render_data->texture, blend_op, render_word); + else + render.DrawTriangle(2, vtx_attr, idx, color_attr, uv_attr, render_data->texture, blend_op, render_word); + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_update.cpp b/include/engine/ui/ui_update.cpp new file mode 100644 index 0000000..e9ba634 --- /dev/null +++ b/include/engine/ui/ui_update.cpp @@ -0,0 +1,70 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui.h" + #include "ui/ui_camera.h" + #include "ui/ui_sprite.h" + #include "ui/ui_ace_manager.h" + #include "ui/ui_scene_script_event.h" + #include "ui/ui_scene_scripted_object.h" + #include "ui/ui_item_script_event.h" + #include "ui/ui_item_scripted_object.h" + #include "script/script_engine_types.h" + #include "script/script_variant.h" + #include "log/log.h" + + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void Scene::SetAsScriptGlobalScene(GS::Script::IVM *_vm) +{ + if (!_vm) + _vm = vm; + if (!_vm || !_vm->IsOpen()) + return; + + _vm->Set("g_scene", GS::Script::Variant(this, GS::Script::typetag_Scene2d)); + _vm->Set("g_clock_fq", GS::Platform::Get().GetClockFrequency()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Scene::Update() +{ + if (clock->GetRefCount() == 1) + clock->Update(); + float dt = clock->GetDeltaf(); + + // ACE update. + ACEManager::Get()->UpdateACEUnit(this, dt); + + ListForeachPtr(Item *, i, item_list) + { + i->automation_player->Evaluate(Time::fromSec(dt)); + + switch (i->GetItemType()) + { + case Item::Type_Sprite: + case Item::Type_Window: + { + Sprite *s = (Sprite *)i; + ACEManager::Get()->UpdateACEUnit(s, dt); + } + break; + } + } + + // + // Script events. +// if (eval_flag & SceneUpdateEvent) + { + scene_event->OnUpdate(this); + ListForeachPtr(Item *, i, item_list) + i->item_event->OnUpdate(i); + } +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_window.cpp b/include/engine/ui/ui_window.cpp new file mode 100644 index 0000000..b16845a --- /dev/null +++ b/include/engine/ui/ui_window.cpp @@ -0,0 +1,365 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_window.h" + #include "ui/widget_text.h" + #include "core/renderer_toolbox.h" + #include "core/render_resource_factory.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +iRect Window::GetRect() const +{ + if (!window_flags.IsSet(Window::FlagNoDecoration)) + if (skin.IsValid()) + return iRect(0, 0, (int)size.x, (int)skin->top->GetHeight()); + return iRect(0, 0, (int)size.x, (int)size.y); +} +iRect Window::GetClientRect() const +{ + if (!window_flags.IsSet(Window::FlagNoDecoration)) + if (skin.IsValid()) + return iRect(skin->left->GetWidth(), skin->top_left->GetHeight(), int(size.x - skin->right->GetWidth()), int(size.y - skin->bottom_right->GetHeight())); + return iRect(0, 0, (int)size.x, (int)size.y); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Window::SetSize(float _w, float _h) +{ + uint w = (uint)_w, h = (uint)_h; + + if (cache.IsValid()) + { + if (w > cache->GetWidth() || h > cache->GetHeight() || w < (cache->GetWidth() / 2) || h < (cache->GetHeight() / 2)) + { + cache->AllocAs(w, h); + if (render_data && render_data->texture) + render_data->texture->Resize(w, h); + } + } + Invalidate(); + + Sprite::SetSize(_w, _h); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Widget *Window::GetTitleWidget() const +{ return title_widget; } +void Window::SetTitleWidget(Widget *w) +{ + title_widget = w; + Invalidate(); +} +Widget *Window::GetBaseWidget() const +{ return base_widget; } +void Window::SetBaseWidget(Widget *w) +{ + base_widget = w; + Invalidate(); +} +Widget *Window::GetWidget(uint id) +{ return base_widget ? base_widget->GetChild(id) : NULL; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Window::ComposeSkin() +{ + if (skin.IsNull()) + return; + + cache->Fill(0, 0, 0, 0); + + // Fill main area. + Rect rect(GetRect()); + rect.sx = skin->top_left->GetWidth(); + rect.sy = skin->top_left->GetHeight(); + rect.ex -= skin->bottom_right->GetWidth(); + rect.ey -= skin->bottom_right->GetHeight(); + Color _skin_color(skin->color); + cache->Fill(_skin_color.x, _skin_color.y, _skin_color.z, _skin_color.w, &rect); + + // Blit corners. + Picture::Blit(*skin->top_left, *cache); + + rect = GetRect(); + rect.sx = rect.ex - skin->top_right->GetWidth(); + Picture::Blit(*skin->top_right, *cache, NULL, &rect); + + rect = GetRect(); + rect.sy = rect.ey - skin->bottom_left->GetHeight(); + Picture::Blit(*skin->bottom_left, *cache, NULL, &rect); + + rect = GetRect(); + rect.sx = rect.ex - skin->bottom_right->GetWidth(); + rect.sy = rect.ey - skin->bottom_right->GetHeight(); + Picture::Blit(*skin->bottom_right, *cache, NULL, &rect); + + // Window left side. + { + int height = GetRect().GetHeight() - skin->top_left->GetHeight() - skin->bottom_left->GetHeight(); + + int *dst = (int *)cache->GetData(); + dst += skin->top_left->GetHeight() * cache->GetWidth(); + + int *src = 0; + for (int s = 0, _s = 0; s < height; ++s) + { + if (!src || (++_s == (int)skin->left->GetHeight())) + { + src = (int *)skin->left->GetData(); + _s = 0; + } + for (uint x = 0; x < skin->left->GetWidth(); ++x) + dst[x] = src[x]; + src += skin->left->GetWidth(); + dst += cache->GetWidth(); + } + } + + // Window right side. + { + int height = GetRect().GetHeight() - skin->top_right->GetHeight() - skin->bottom_right->GetHeight(); + + int *dst = (int *)cache->GetData(); + dst += skin->top_right->GetHeight() * cache->GetWidth() + GetRect().ex - skin->right->GetWidth(); + + int *src = 0; + for (int s = 0, _s = 0; s < height; ++s) + { + if (!src || (++_s == (int)skin->right->GetHeight())) + { + src = (int *)skin->right->GetData(); + _s = 0; + } + for (uint x = 0; x < skin->right->GetWidth(); ++x) + dst[x] = src[x]; + src += skin->right->GetWidth(); + dst += cache->GetWidth(); + } + } + + // Window top side. + { + int block_width = skin->top->GetWidth(); + int width = GetRect().GetWidth() - skin->top_left->GetWidth() - skin->top_right->GetWidth(), height = skin->top->GetHeight(); + + int *src = (int *)skin->top->GetData(), *dst = (int *)cache->GetData(); + dst += skin->top_left->GetWidth(); + + for (int y = 0; y < height; ++y) + { + for (int x = 0, _x = 0; x < width; ++x) + { + dst[x] = src[_x++]; + if (_x == block_width) + _x = 0; + } + src += skin->top->GetWidth(); + dst += cache->GetWidth(); + } + } + + // Window bottom side. + { + int block_width = skin->bottom->GetWidth(); + int width = GetRect().GetWidth() - skin->bottom_left->GetWidth() - skin->bottom_right->GetWidth(), height = skin->bottom->GetHeight(); + + int *src = (int *)skin->bottom->GetData(), *dst = (int *)cache->GetData(); + dst += skin->bottom_left->GetWidth() + (GetRect().ey - height) * cache->GetWidth(); + + for (int y = 0; y < height; ++y) + { + for (int x = 0, _x = 0; x < width; ++x) + { + dst[x] = src[_x++]; + if (_x == block_width) + _x = 0; + } + src += skin->bottom->GetWidth(); + dst += cache->GetWidth(); + } + } + + // + { + int height = GetRect().ey - skin->bottom_right->GetHeight() - skin->top_left->GetHeight(), width = GetRect().GetWidth(); + + // + uint *dst = (uint *)cache->GetData(); + dst += cache->GetWidth() * skin->top_left->GetHeight();// + system.skin_left->GetWidth(); + float alpha = 1.f; + + int segment_height = (height * 70) / 100; + float alpha_step = (0.85f - alpha) / (float)segment_height; + + for (int y = 0; y < segment_height; ++y) + { + uint int_alpha = (uint(alpha * 255.f)) & 0xff; + // uint scan_color = nColor::ARGBtoRGBA((system.skin_color & 0xffffff00) + int_alpha); + for (int x = 0; x < width; ++x) + dst[x] = (((((dst[x] >> 24) & 0xff) * int_alpha) >> 8) << 24) + (dst[x] & 0x00ffffff);//scan_color; + dst += cache->GetWidth(); + alpha += alpha_step; + } + + segment_height = height - segment_height; + alpha_step = (1.f - alpha) / (float)segment_height; + + for (int y = 0; y < segment_height; ++y) + { + uint int_alpha = (uint(alpha * 255.f)) & 0xff; + // uint scan_color = nColor::ARGBtoRGBA((system.skin_color & 0xffffff00) + int_alpha); + for (int x = 0; x < width; ++x) + dst[x] = (((((dst[x] >> 24) & 0xff) * int_alpha) >> 8) << 24) + (dst[x] & 0x00ffffff);//scan_color; + dst += cache->GetWidth(); + alpha += alpha_step; + } + } +} +void Window::Compose() +{ + if (cache.IsNull()) + return; + + if (background_picture) + { + cache->Fill(0, 0, 0, 0); + Picture::Blit(*background_picture, *cache); + } + else + { + bool skinned = false; + if (!window_flags.IsSet(Window::FlagNoDecoration)) + if (skin.IsValid()) + skinned = true; + + if (skinned) + ComposeSkin(); + + cache->Fill(background_color.x, background_color.y, background_color.z, background_color.w); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Window::Invalidate() +{ + if (base_widget) + base_widget->Invalidate(); + if (title_widget) + title_widget->Invalidate(); + + window_flags.Raise(FlagCacheDirty | FlagRenderDirty); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Window::RenderSetup(Core::ResourceFactories *f) +{ + if ((render_data = new Sprite::RenderData)) + if (f && f->render) + { + render_data->texture = f->render->NewTexture(); + render_data->texture->Create(NULL, (int)size.x, (int)size.y, Render::Texture::FormatRGBA8, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource)); + + window_flags.Raise(FlagRenderDirty); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Window::Render(Renderer &renderer, GPU::TriangleBatch *batch) +{ + // Compose. + bool has_title = !(window_flags.IsSet(Window::FlagNoTitleBar) || background_picture); + + if (base_widget) + { + base_widget->Refresh(); + + if (base_widget->IsDirty()) + { + Invalidate(); + + // Compose window skin. + Compose(); + + // Compose window content. + Rect compose_rect(GetRect()); + + if (has_title && skin) + { + compose_rect.sx = skin->top_left->GetWidth(); + compose_rect.sy = skin->title_bottom + 4; + compose_rect.ex -= skin->bottom_right->GetWidth(); + compose_rect.ey -= skin->bottom_right->GetHeight(); + } + + if (cache.IsValid()) + base_widget->Compose(*cache, compose_rect); + } + } + else + if (window_flags.IsSet(FlagCacheDirty)) + Compose(); + + // Compose the window title. + if (has_title && skin) + { + iRect title_rect(skin->top_left->GetWidth(), skin->title_top, GetRect().GetWidth() - skin->top_right->GetWidth(), skin->title_bottom); + if (cache.IsValid()) + title_widget->Compose(*cache, title_rect); + } + + if (window_flags.IsSet(FlagRenderDirty)) + if (render_data.IsValid() && render_data->texture.IsValid()) + { + render_data->texture->Blit((const char *)cache->GetData(), cache->GetWidth(), cache->GetHeight()); + window_flags.Remove(FlagRenderDirty); + } + + Sprite::Render(renderer, batch); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Window::SetSkin(WindowSkin *s) +{ + if ((skin = s)) + if (title_widget->GetType() == WidgetTypeText) + if (TextWidget *t = (TextWidget *)title_widget.c_ptr()) + { + Color skin_color(skin->title_color); + + t->SetFont(s->title_font); + t->SetFontColor(skin_color.x, skin_color.y, skin_color.z); + t->SetFontSize(s->title_size); + t->SetTextAlignment(TextState::Center); + } + + Invalidate(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Window::Window() +{ + window_flags.Set(FlagCacheDirty); + + type = Type_Window; + cache = new Picture; + + background_color.Set(0.f, 0.f, 0.f, 0.f); + title_widget = new TextWidget(-1, "Window Title"); + + SetSize(320, 200); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_window_nml.cpp b/include/engine/ui/ui_window_nml.cpp new file mode 100644 index 0000000..28e0cbe --- /dev/null +++ b/include/engine/ui/ui_window_nml.cpp @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/ui_window.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::NML; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +bool Window::FromMetaTag(Tag &tag) +{ + if (tag.name != "Window") + __ERR__(__LOG_E__ << "Could not parse window, incorrect root tag (" << tag.name << ").\n", false) + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "Sprite") + Sprite::FromMetaTag(*pt); + + else if (pt->name == "Flag") + { + NMLTagForeach(st, *pt) + { + if (st->name == "NoDecoration") + window_flags |= FlagNoDecoration; + else if (st->name == "NoTitle") + window_flags |= FlagNoTitleBar; + } + } + else + __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +Tag *Window::AsMetaTag() const +{ + Tag *root = new Tag("Window"); + if (!root) + __ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL) + + root->AddChild(Sprite::AsMetaTag()); + + if (Tag *style_tag = new Tag("Flag")) + { + if (window_flags.IsSet(FlagNoDecoration)) + style_tag->AddChild("NoDecoration"); + if (window_flags.IsSet(FlagNoTitleBar)) + style_tag->AddChild("NoTitle"); + } + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/ui_window_skin.cpp b/include/engine/ui/ui_window_skin.cpp new file mode 100644 index 0000000..fbcfff7 --- /dev/null +++ b/include/engine/ui/ui_window_skin.cpp @@ -0,0 +1,7 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "ui/ui_window_skin.h" diff --git a/include/engine/ui/widget.cpp b/include/engine/ui/widget.cpp new file mode 100644 index 0000000..8c38a95 --- /dev/null +++ b/include/engine/ui/widget.cpp @@ -0,0 +1,169 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/widget.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void Widget::SetParent(Widget *w) +{ + if (w != parent) + { + if (parent) + parent->children.Remove(this); + + parent = w; + + if (parent) + parent->children.Add(this); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Widget::SetHidden(bool h) +{ + if (h != hidden) + { + hidden = h; + dirty = true; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Widget *Widget::GetChild(int id) +{ + if (GetId() == id) + return this; + + ListForeachPtr(Widget *, w, GetChildren()) + if (Widget *match = w->GetChild(id)) + return match; + + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Widget::Invalidate() +{ dirty = true; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +iRect Widget::GetRect() const +{ return iRect(rect.sx, rect.sy, rect.ex, rect.ey); } +void Widget::SetBorderSize(float t, float b, float l, float r) +{ + border_size.Set(t, b, l, r); + Invalidate(); +} +void Widget::SetHAlign(Align a) +{ + h_align = a; + Invalidate(); +} +void Widget::SetVAlign(Align a) +{ + v_align = a; + Invalidate(); +} +void Widget::SetFormattingSize(const Vector2 &s) +{ + format = s; + Invalidate(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector2 Widget::GetFormat() const +{ + switch (GetType()) + { + case WidgetTypeHSizer: + case WidgetTypeVSizer: + break; + + default: + return format; + } + + // Combine all child formats. + Vector2 total_format(0, 0); + + ListForeachPtr(Widget *, w, GetChildren()) + { + Vector2 child_format = w->GetFormat(); + + switch (GetType()) + { + case WidgetTypeHSizer: + total_format.x += child_format.x; + total_format.y = total_format.y > child_format.y ? total_format.y : child_format.y; + break; + + case WidgetTypeVSizer: + total_format.x = total_format.x > child_format.x ? total_format.x : child_format.x; + total_format.y += child_format.y; + break; + } + } + return total_format * format; +} +//------------------------------------------------------------------------------ + +//-------------------------------------------------------------------------------------- +iRect Widget::FormatOutputRect(const iRect &rect, const iRect &clip_rect) +//-------------------------------------------------------------------------------------- +{ + iRect out_rect(clip_rect.sx, clip_rect.sy, clip_rect.sx + rect.GetWidth(), clip_rect.sy + rect.GetHeight()); + + switch (h_align) + { + case AlignLeft: break; + case AlignMiddle: out_rect = out_rect.Offset((clip_rect.GetWidth() - rect.GetWidth()) / 2, 0); break; + case AlignRight: out_rect = out_rect.Offset(clip_rect.GetWidth() - rect.GetWidth(), 0); break; + case AlignGrow: out_rect.ex = clip_rect.ex; break; + } + switch (v_align) + { + case AlignTop: break; + case AlignMiddle: out_rect = out_rect.Offset(0, (clip_rect.GetHeight() - rect.GetHeight()) / 2); break; + case AlignBottom: out_rect = out_rect.Offset(0, clip_rect.GetHeight() - rect.GetHeight()); break; + case AlignGrow: out_rect.ey = clip_rect.ey; break; + } + return out_rect; +} + +//------------------------------------------------------------------------------ +Widget::Widget(int id) +{ + object_id = id; + + parent = NULL; + + format.Set(1, 1); + SetBorderSize(); + + h_align = AlignMiddle; + v_align = AlignMiddle; + + dirty = true; + hidden = false; + + type = WidgetTypeBase; + event_table = new EventTable; +} +Widget::~Widget() +{ + SetParent(NULL); + ListForeachPtr(Widget *, c, children) + c->SetParent(NULL); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/widget_bitmap.cpp b/include/engine/ui/widget_bitmap.cpp new file mode 100644 index 0000000..ed7feda --- /dev/null +++ b/include/engine/ui/widget_bitmap.cpp @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "widget_bitmap.h" + + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void BitmapWidget::SetPicture(GS::Picture *p) +{ + if (picture != p) + { + picture = p; + Invalidate(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +BitmapWidget::BitmapWidget(int id, GS::Picture *p) : DrawableWidget(id) +{ + SetPicture(p); + type = WidgetTypeBitmap; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/widget_canvas.cpp b/include/engine/ui/widget_canvas.cpp new file mode 100644 index 0000000..ac5a1a1 --- /dev/null +++ b/include/engine/ui/widget_canvas.cpp @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/widget_canvas.h" + + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +bool CanvasWidget::Allocate(uint width, uint height) +{ + if (!picture->AllocAs(width, height, GS::PixelFormat::RGBA8)) + return false; + + dirty = true; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +CanvasWidget::CanvasWidget(int id, uint width, uint height) : DrawableWidget(id) +{ + type = WidgetTypeCanvas; + picture = new GS::Picture(width, height); +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/widget_check.cpp b/include/engine/ui/widget_check.cpp new file mode 100644 index 0000000..d11f116 --- /dev/null +++ b/include/engine/ui/widget_check.cpp @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "ui/widget_check.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void CheckWidget::SetState(bool b_state) +{ + state = b_state; +// check_bitmap.SetPicture(state ? "scene2d/ui_check_true.tga" : "scene2d/ui_check_false.tga"); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void CheckWidget::Refresh() +{ + check_bitmap.Refresh(); + label.Refresh(); + dirty = check_bitmap.IsDirty() || label.IsDirty(); +} +void CheckWidget::Invalidate() +{ + check_bitmap.Invalidate(); + label.Invalidate(); + Widget::Invalidate(); +} +void CheckWidget::Compose(Picture &output, const iRect &out_rect) +{ + if (hidden || !dirty) + return; + + rect = out_rect; + rect.sy += (int)border_size.x; + rect.ey -= (int)border_size.y; + rect.sx += (int)border_size.z; + rect.ex -= (int)border_size.w; + + // Compose check box and label. + Rect check_rect(rect), label_rect(rect); + + if (check_bitmap.GetPicture()) + { + check_rect.ex = check_rect.sx + (check_bitmap.GetPicture()->GetWidth() * 3) / 2; + label_rect.sx = check_rect.ex; + } + check_bitmap.Compose(output, check_rect); + label.Compose(output, label_rect); + + dirty = false; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/widget_drawable.cpp b/include/engine/ui/widget_drawable.cpp new file mode 100644 index 0000000..21da64a --- /dev/null +++ b/include/engine/ui/widget_drawable.cpp @@ -0,0 +1,66 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "widget_drawable.h" + #include "picture/pict.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void DrawableWidget::Compose(Picture &output, const iRect &clip_rect) +{ + if (hidden || !dirty || !picture) + return; + + if (picture) + rect.Set(0, 0, picture->GetWidth(), picture->GetHeight()); + else rect.Set(0, 0, 0, 0); + + iRect out_rect = Widget::FormatOutputRect(rect, clip_rect), + blit_rect = out_rect.Intersection(clip_rect); + + if (blit_rect.GetWidth() > rect.GetWidth()) + blit_rect.ex = blit_rect.sx + rect.GetWidth(); + if (blit_rect.GetHeight() > rect.GetHeight()) + blit_rect.ey = blit_rect.sy + rect.GetHeight(); + + int src_offsetx = blit_rect.sx - out_rect.sx, + src_offsety = blit_rect.sy - out_rect.sy; + uchar *ptr = picture->GetData() + (src_offsety * picture->GetWidth() + src_offsetx) * 4, + *pds = output.GetData() + (blit_rect.sy * output.GetWidth() + blit_rect.sx) * 4; + + for (int y = 0; y < blit_rect.GetHeight(); ++y) + { + uchar *psc = ptr, *spt = pds; + + for (int x = 0; x < blit_rect.GetWidth(); ++x) + { + uchar alpha = psc[3]; + + uchar a_blend = Picture::AlphaCompositeAlpha(spt[3], alpha); + spt[0] = Picture::AlphaCompositeColor(spt[0], psc[0], spt[3], alpha, a_blend); + spt[1] = Picture::AlphaCompositeColor(spt[1], psc[1], spt[3], alpha, a_blend); + spt[2] = Picture::AlphaCompositeColor(spt[2], psc[2], spt[3], alpha, a_blend); + spt[3] = a_blend; + + spt += 4; + psc += 4; + } + + ptr += picture->GetWidth() * 4; + pds += output.GetWidth() * 4; + } + rect = out_rect; + dirty = false; +} +DrawableWidget::DrawableWidget(int id) : Widget(id) +{ + type = WidgetTypeDrawable; + picture = NULL; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/widget_sizer.cpp b/include/engine/ui/widget_sizer.cpp new file mode 100644 index 0000000..8e8f8a9 --- /dev/null +++ b/include/engine/ui/widget_sizer.cpp @@ -0,0 +1,114 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "widget_sizer.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +Widget *SizerWidget::Add(Widget *widget) +{ + if (widget) + widget->SetParent(this); + return widget; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SizerWidget::Invalidate() +{ + ListForeachPtr(Widget *, c, children) + c->Invalidate(); + Widget::Invalidate(); +} +void HSizerWidget::Refresh() +{ + ListForeachPtr(Widget *, c, children) + { + c->Refresh(); + if (c->IsDirty()) + dirty = true; + } +} +void HSizerWidget::Compose(Picture &output, const iRect &out_rect) +{ + if (hidden || !dirty || !children.GetCount()) + return; + + rect = out_rect; + rect.sy += (int)border_size.x; + rect.ey -= (int)border_size.y; + rect.sx += (int)border_size.z; + rect.ex -= (int)border_size.w; + + iRect wid_rect(rect); + + float tsz = 0.f; + ListForeachPtr(Widget *, c, children) + if (!c->IsHidden()) + tsz += c->GetFormat().x; + + float stx = (float)out_rect.GetWidth() / tsz; + ListForeachPtr(Widget *, c, children) + if (!c->IsHidden()) + { + float cell_size = stx * c->GetFormat().x; + wid_rect.ex = wid_rect.sx + (int)cell_size; + c->Compose(output, wid_rect); + wid_rect.sx += (int)cell_size; + } + else + c->Validate(); + + dirty = false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void VSizerWidget::Refresh() +{ + ListForeachPtr(Widget *, c, children) + { + c->Refresh(); + if (c->IsDirty()) + dirty = true; + } +} +void VSizerWidget::Compose(Picture &output, const iRect &out_rect) +{ + if (hidden || !dirty || !children.GetCount()) + return; + + rect = out_rect; + rect.sy += (int)border_size.x; + rect.ey -= (int)border_size.y; + rect.sx += (int)border_size.z; + rect.ex -= (int)border_size.w; + + iRect wid_rect(rect); + + float tsy = 0.f; + ListForeachPtr(Widget *, c, children) + if (!c->IsHidden()) + tsy += c->GetFormat().y; + + float sty = (float)out_rect.GetHeight() / tsy; + ListForeachPtr(Widget *, c, children) + if (!c->IsHidden()) + { + float cell_size = sty * c->GetFormat().y; + wid_rect.ey = wid_rect.sy + (int)cell_size; + c->Compose(output, wid_rect); + wid_rect.sy += (int)cell_size; + } + else + c->Validate(); + + dirty = false; +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/widget_staticcontainer.cpp b/include/engine/ui/widget_staticcontainer.cpp new file mode 100644 index 0000000..ce2f486 --- /dev/null +++ b/include/engine/ui/widget_staticcontainer.cpp @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/widget_staticcontainer.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------- +ContainerCell *ContainerWidget::GetCell(const Widget *widget) const +//------------------------------------------------------------------------- +{ + ListForeachPtr(ContainerCell *, cell, cell_list) + if (cell->widget == widget) + return cell; + return NULL; +} + +//------------------------------------------------------------------------------ +Widget *ContainerWidget::Add(Widget *widget, const iRect &cell_rect) +{ + if (!widget) + __ERR__(__LOG_E__ << "Cannot create a cell for a NULL widget.\n", NULL) + + ContainerCell *cell = new ContainerCell; + if (!cell) + __ERR__(__LOG_E__ << "Failed to allocate new container cell.\n", NULL) + + widget->SetParent(this); + + cell->cell_rect = cell_rect; + cell->widget = widget; + cell_list.Add(cell, true, false); + + children.Add(widget); + + return widget; +} +bool ContainerWidget::Remove(Widget *widget) +{ + ContainerCell *e = GetCell(widget); + if (!e) + return false; + + cell_list.Remove(e); + _safe_delete(e); + + children.Remove(widget); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------ +void ContainerWidget::Invalidate() +//------------------------------------------------ +{ + ListForeachPtr(ContainerCell *, cell, cell_list) + cell->widget->Invalidate(); + Widget::Invalidate(); +} + +//--------------------------------------------- +void ContainerWidget::Refresh() +//--------------------------------------------- +{ + ListForeachPtr(ContainerCell *, cell, cell_list) + { + cell->widget->Refresh(); + if (cell->widget->IsDirty()) + dirty = true; + } +} + +//------------------------------------------------------------------------------ +void ContainerWidget::Compose(Picture &output, const iRect &out_rect) +{ + if (hidden || !dirty || !cell_list.GetCount()) + return; + + rect = out_rect; + ListForeachPtr(ContainerCell *, cell, cell_list) + if (!cell->widget->IsHidden()) + cell->widget->Compose(output, cell->cell_rect.Offset(rect.sx, rect.sy)); + else + cell->widget->Validate(); + + dirty = false; +} +ContainerWidget::~ContainerWidget() +{ + /* + Only cells are deleted here since children are handled by the base + Widget class destructor. + */ + ListDeleteAllPtr(ContainerCell *, cell_list) +} +//------------------------------------------------------------------------------ diff --git a/include/engine/ui/widget_text.cpp b/include/engine/ui/widget_text.cpp new file mode 100644 index 0000000..e6b2f0a --- /dev/null +++ b/include/engine/ui/widget_text.cpp @@ -0,0 +1,92 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ui/widget_text.h" + + using namespace GS; + using namespace GS::S2D; + + +//------------------------------------------------------------------------------ +void TextWidget::SetTextState(const TextState &_state) +{ + // Avoid useless invalidation. + if (Memory::Compare(&state, &_state, sizeof(TextState))) + { + state = _state; + Invalidate(); + } +} +void TextWidget::GetTextState(TextState &_state) const +{ _state = state; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void TextWidget::SetText(const char *t) +{ + text = t; + Invalidate(); +} +void TextWidget::SetFont(FontEx *f) +{ + if (state.font != f) + { + state.font = f; + Invalidate(); + } +} +void TextWidget::SetFontSize(int s) +{ + state.SetSize(s); + if (state.font.IsValid()) + state.font->SetPixelSize(s); + Invalidate(); +} +void TextWidget::SetFontColor(float red, float green, float blue, float alpha) +{ + state.color.Set(red * 255.f, green * 255.f, blue * 255.f, alpha * 255.f); + Invalidate(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void TextWidget::Refresh() +{ + if (!state.font || !dirty) + return; + rect = state.font->GetTextBoundRect(text); +} +void TextWidget::Compose(Picture &output, const iRect &clip_rect) +{ + iRect text_rect = FontRenderer::Format(text.c_str(), state, clip_rect), + out_rect = Widget::FormatOutputRect(text_rect, clip_rect); + + rect = FontRenderer::Compose(output, text.c_str(), state, out_rect, clip_rect); + dirty = false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +TextWidget::TextWidget(int id, const char *t, FontEx *font, int s) : Widget(id) +{ + type = WidgetTypeText; + + state.format = TextState::Line; + state.alignment = TextState::Left; + + h_align = AlignGrow; + + SetText(t); + SetFont(font); + + SetFontSize(s); + SetFontColor(1, 1, 1); + SetColumnWidth(80); + + state.SetTracking(FontRenderer::default_text_tracking); + state.SetLeading(FontRenderer::default_text_heading); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/ascii/ascii_encoder.cpp b/include/framework/ascii/ascii_encoder.cpp new file mode 100644 index 0000000..eded125 --- /dev/null +++ b/include/framework/ascii/ascii_encoder.cpp @@ -0,0 +1,228 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ascii/ascii_encoder.h" + #include "log/log.h" + + +//--------------------------------------------------------------------------- +#define FEED_OUT(out_c) \ +{ \ + if (out) \ + { \ + if (olen < max) \ + out[olen] = (uchar)(out_c); \ + else \ + break; \ + } \ + olen++; \ +} +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +#define FEED_IN(in_v) \ +{ \ + if (!len) \ + { \ + __LOG_W__ << "input buffer underflow.\n"; \ + break; \ + } \ + (in_v) = (int)*in++; \ + len--; \ +} +//--------------------------------------------------------------------------- + +/* + + From UUencode wikipedia. + ------------------------ + + (...) + Uuencode repeatedly takes in a group of three bytes, adding trailing zeros + if there are less than three bytes left. These 24 bits are split into four + groups of six which are treated as numbers between 0 and 63. + Decimal 32 is added to each number and they are ouput as ASCII characters + which will lie in the range 32 (space) to 32+63 = 95 (underscore). + ASCII characters greater than 95 may also be used; however, only the six + right-most bits are relevant. + Each group of sixty output characters (corresponding to 45 input bytes) is + output as a separate line preceded by an 'M' (ASCII code 77 = 32+45). + At the end of the input, if there are N output characters left after the + last group of sixty and N>0 then they will be preceded by the character + whose code is 32+N. + (...) + +*/ + +//----------------------------------------------------------------------------- +uint nAsciiEncoder::UUEncode(const uchar *in, size_t len, uchar *out, size_t max) +{ + uint olen = 0, n; + + while (len) + { + uchar *p = out ? &out[olen] : NULL; + FEED_OUT(0) // Dummy feed. + + for (n = 0; (n < 15) && len; n++) + { + uchar a, b, c; + a = *in++; + len--; + if (len) { len--; b = *in++; } else b = 0; + if (len) { len--; c = *in++; } else c = 0; + + uint f = (a << 16) + (b << 8) + c; + uchar w, x, y, z; + + z = (f & 63) + 32; + y = ((f >> 6) & 63) + 32; + x = ((f >> 12) & 63) + 32; + w = ((f >> 18) & 63) + 32; + + FEED_OUT(w); + FEED_OUT(x); + FEED_OUT(y); + FEED_OUT(z); + } + if (p) + p[0] = (uchar)(n * 3 + 32); + FEED_OUT('\n') + } + return olen; +} +uint nAsciiEncoder::UUDecode(const uchar *in, size_t len, uchar *out, size_t max) +{ + uint olen = 0, n; + + while (len) + { + uint lsize; + FEED_IN(lsize); + lsize = (lsize - 32) / 3; + + if (len) + for (n = 0; n < lsize; n++) + { + int x, y, z, w; + FEED_IN(w); w -= 32; + FEED_IN(x); x -= 32; + FEED_IN(y); y -= 32; + FEED_IN(z); z -= 32; + + uchar a, b, c; + int f = (w << 18) + (x << 12) + (y << 6) + z; + a = (f >> 16) & 255; + b = (f >> 8) & 255; + c = f & 255; + + FEED_OUT(a); + FEED_OUT(b); + FEED_OUT(c); + } + + if (len) + FEED_IN(n); // Line jump. + } + return olen; +} +//----------------------------------------------------------------------------- + +/* + + From yEnc.org (revision 1.3) + ---------------------------- + + A typical encoding process might look something like this: + + 1. Fetch a character from the input stream. + 2. Increment the character's ASCII value by 42, modulo 256 + 3. If the result is a critical character (as defined in the previous + section), write the escape character to the output stream and increment + character's ASCII value by 64, modulo 256. + 4. Output the character to the output stream. + 5. Repeat from start. + + (...) + Under special circumstances, a single escape character (ASCII 3Dh, "=") is + used to indicate that the following output character is "critical", and + requires special handling. + + Critical characters include the following: + + ASCII 00h (NULL) + ASCII 0Ah (LF) + ASCII 0Dh (CR) + ASCII 3Dh (=) + + > ASCII 09h (TAB) -- removed in version (1.2) + +*/ + +//----------------------------------------------------------------------------- +uint nAsciiEncoder::yEncode(const uchar *in, size_t len, uchar *out, size_t max, uint line_length) +{ + if (line_length <= 0) + __ERR__(__LOG_E__ << "invalid line-feed size for yEncoding.\n", 0) + + uint olen = 0; + int cchr = (int)line_length; + + while (len--) + { + // Line-feed. + if (cchr <= 0) + { + FEED_OUT('\n') + cchr = (int)line_length; + } + + // yEnc. + int v = (int(*in++) + 42) % 256; + + switch (v) + { + case 0x00: + case 0x0a: + case 0x0d: + case 0x3d: + FEED_OUT(0x3d) + cchr--; + v = (v + 64) % 256; + break; + } + + FEED_OUT(v) + cchr--; + } + return olen; +} +uint nAsciiEncoder::yDecode(const uchar *in, size_t len, uchar *out, size_t max) +{ + uint olen = 0; + while (len--) + { + int v = (int)*in++; + + if (v == 0x0a) + FEED_IN(v) + if ((v == 0x0d) && (in[0] == 0x0a)) // [EJ support for Windows-style EOL] + { + ++in; + len--; + FEED_IN(v) + } + + if (v == 0x3d) + { + FEED_IN(v) + v = (v - 64) % 256; + } + FEED_OUT((v - 42) % 256) + } + return olen; +} +//----------------------------------------------------------------------------- diff --git a/include/framework/ascii/parser.cpp b/include/framework/ascii/parser.cpp new file mode 100644 index 0000000..6864031 --- /dev/null +++ b/include/framework/ascii/parser.cpp @@ -0,0 +1,189 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "ascii/parser.h" + #include "ntypes.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool AsciiParser::IsUpperCase(const char c) +{ return asbool((c >= 'A') && (c <= 'Z')); } +const char *AsciiParser::RunToEOS(const char *s, const char *e) +{ + while (s < e) + { + if (s[0] == '\\') + s += 2; // Jump modifiers. + else if (s[0] == '"') + break; + else s++; + } + return s; +} +bool AsciiParser::IsConstantFloat(const char *s, const char *e) +{ + const char *eoc = SkipEntry(s, e); + if (s[0] == '-') + { + s++; + eoc = SkipEntry(s, e); + } + while (s < eoc) + { + if ((s[0] == '.') || (s[0] == 'f')) + return true; + s++; + } + return false; +} +const char *AsciiParser::Find(const char *s, const char *e, char f) +{ + for (;;) + { + s = SkipSpace(s, e); + if (s == e) + return NULL; + if (s[0] == '(') + s = RunToEOG(s, e, '(', ')'); + else + { + if (s[0] == f) + break; + s++; + } + } + return s; +} +const char *AsciiParser::SkipEntry(const char *s, const char *e, bool skip_minus) +{ + { + while ( + (s[0] != 0x20) && + !((s[0] == 0xd) && (s[1] == 0xa)) && + (s[0] != 0x9) && + (s[0] != 0xa) && + (s[0] != 0xd) && + (s[0] != '/') && + (s[0] != '*') && + (s[0] != '+') && + (s[0] != '=') && + (s[0] != ';') && + (s[0] != ':') && + (s[0] != ',') && + (s[0] != '<') && + (s[0] != '>') && + (s[0] != '(') && + (s[0] != ')') && + (s[0] != '\"') + ) + { + if (!skip_minus && (s[0] == '-')) + break; + if (s == e) + break; + s++; + } + } + return s; +} +const char *AsciiParser::RunToEOL(const char *s, const char *e) +{ + while ( + ((s[0] != 0xd) || (s[1] != 0xa)) && + (s[0] != 0xa) && + (s[0] != 0xd) && + (s < e) + ) + s++; + + return s; +} +const char *AsciiParser::SkipEOL(const char *s, const char *e) +{ + if ((s[0] == 0xd) && (s[1] == 0xa)) + s += 2; + else if ((s[0] == 0xa) || (s[0] == 0xd)) + s++; + return s > e ? e : s; +} +const char *AsciiParser::RunToEOG(const char *s, const char *e, char op, char cl) +{ + uint pc = 0; + s++; + while (s < e) + { + if (s[0] == op) + pc++; + if (s[0] == cl) + { + if (!pc) + break; + pc--; + } + s++; + } + if (s == e) + return NULL; + return s; +} +const char *AsciiParser::RunToEOC(const char *s, const char *e) +{ + s += 2; + while (((s[0] != '*') || (s[1] != '/')) && (s < e)) + s += ((s[0] == 0xd) && (s[1] == 0xa)) ? 2 : 1; + return s >= e ? e : s + 2; +} +const char *AsciiParser::RunToEOE(const char *s, const char *e) +{ + while (s < e) + { + s = SkipSpace(s, e); + if (s[0] == '(') + s = RunToEOG(s, e, '(', ')'); + + else + if (s[0] == '\"') + { + s++; + while ((s < e) && (s[0] != '\"')) + s++; + if (s < e) + s++; + } + else + { + if ((s[0] == ',') || (s[0] == ';') ) + break; + s++; + } + } + return s; +} +const char *AsciiParser::SkipSpace(const char *s, const char *e) +{ + while (s < e) + { + if (s[0] == 0x20) s++; + else if ((s[0] == 0xd) && (s[1] == 0xa)) s += 2; + else if ((s[0] == '/') && (s[1] == '/')) s = RunToEOL(s, e); + else if ((s[0] == '/') && (s[1] == '*')) s = RunToEOC(s, e); + else if (s[0] == 0x9) s++; + else if (s[0] == 0xa) s++; + else if (s[0] == 0xd) s++; + // else if (s[0] == -17 && s[1] == -69 && s[2] == -65) s+=3; // remove the BOM from utf 8 file + else break; + } + return s; +} +const char *AsciiParser::NextEntry(const char *s, const char *e, bool skip_minus) +{ + s = SkipEntry(s, e, skip_minus); + s = SkipSpace(s, e); + return s; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/audio/audio_io.cpp b/include/framework/audio/audio_io.cpp new file mode 100644 index 0000000..8195b27 --- /dev/null +++ b/include/framework/audio/audio_io.cpp @@ -0,0 +1,52 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "audio/audio_io.h" + #include "filesystem/filesystem.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + + template<> AudioIO *Singleton ::i = NULL; + + +//------------------------------------------------------------------------------ +void AudioIO::RegisterStreamFactory(IAudioStreamFactory *f) +{ stream_factories.Add(f); } +void AudioIO::RegisterSampleFactory(ISampleFactory *f) +{ sample_factories.Add(f); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ISample *AudioIO::LoadSample(const char *path, const char *format) +{ + String fmt(format); + if (Platform::Get().io->Exists(path)) + ListForeachPtr(ISampleFactory *, codec, sample_factories) + if (ISample *sample = codec->Load(path)) + { + if (!fmt || (fmt == sample->GetFormat())) + return sample; + _safe_delete(sample); + } + + return NULL; +} +IAudioStream *AudioIO::OpenStream(const char *path, const char *format) +{ + String fmt(format); + if (Platform::Get().io->Exists(path)) + ListForeachPtr(IAudioStreamFactory *, codec, stream_factories) + if (IAudioStream *stream = codec->Open(path)) + { + if (!fmt || (fmt == stream->GetFormat())) + return stream; + _safe_delete(stream); + } + return NULL; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/audio/sample_stream_factory.cpp b/include/framework/audio/sample_stream_factory.cpp new file mode 100644 index 0000000..4298a7d --- /dev/null +++ b/include/framework/audio/sample_stream_factory.cpp @@ -0,0 +1,71 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "audio/sample_stream_factory.h" + #include "audio/sample_wav.h" + #include "audio/audio_io.h" + #include "audio/stream_interface.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +ISample *SampleStreamFactory::Load(const char *path) +{ + // Open stream... + AutoPtr stream(AudioIO::Get().OpenStream(path)); + if (stream.IsNull()) + return NULL; + + #define PCM_OUTPUT_GROW_STEP 16384 // PCM output grows 16k at a time. + + Array data, temp(stream->GetPCMBufferSize()); + size_t pcm_size = 0; + + // ...decode and dump PCM content to buffer. + forever + { + size_t avail = stream->GetPCM(temp.c_ptr()); + if (!avail) + { + if (stream->IsEOF()) + break; + continue; + } + + size_t r_size = pcm_size + avail; + if (r_size > data.GetSize()) + { + size_t size = (r_size / PCM_OUTPUT_GROW_STEP + 1) * PCM_OUTPUT_GROW_STEP; + + if (!data.Reallocate(size)) // no way to know the PCM output size, this is bad for memory fragmentation... + { + __LOG_W__ << "Failed to append pcm chunk to sample, output will be truncated.\n"; + break; + } + } + + Memory::Copy(&data[(int)pcm_size], temp.c_ptr(), avail); + pcm_size += avail; + } + + if (pcm_size == 0) + return NULL; + + // Commit to sample object. + __LOG__ << "OGG '" << path << "' -> PCM data size: " << pcm_size << " bytes.\n"; + uint sample_count = pcm_size / (stream->format.channels * stream->format.resolution / 8); + + // + AutoPtr sample(new SampleWav); + if (sample.IsNull()) + return NULL; + + sample->Set(data, sample_count, stream->format); + return sample.Detach(); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/audio/sample_wav.cpp b/include/framework/audio/sample_wav.cpp new file mode 100644 index 0000000..c2c3562 --- /dev/null +++ b/include/framework/audio/sample_wav.cpp @@ -0,0 +1,44 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "audio/sample_wav.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool SampleWav::GetSampleFormat(SampleFormat &fmt) const +{ + fmt = format; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Time SampleWav::GetDuration() const +{ return Time::fromMs(sample_count * 1000 / format.frequency); } +uint SampleWav::GetPCMDataSize() const +{ return format.GetPCMDataSize(sample_count); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +char *SampleWav::AllocAs(uint count, const SampleFormat &fmt) +{ + format = fmt; + if (!pcm_data.Allocate(format.GetPCMDataSize(count))) + __ERR__(__LOG_E__ << "Failed to allocate raw PCM sample buffer.\n", NULL) + + sample_count = count; + return pcm_data; +} +void SampleWav::Set(Array &pcm, uint count, const SampleFormat &fmt) +{ + pcm_data = pcm; + sample_count = count; + format = fmt; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/audio/sample_wav_factory.cpp b/include/framework/audio/sample_wav_factory.cpp new file mode 100644 index 0000000..5c32ed2 --- /dev/null +++ b/include/framework/audio/sample_wav_factory.cpp @@ -0,0 +1,119 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "audio/sample_wav_factory.h" + #include "audio/sample_wav.h" + #include "filesystem/filesystem.h" + #include "filesystem/io_handle.h" + #include "memory/endian.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +ISample *SampleWavFactory::Load(const char *path) +{ + AutoPtr h(Platform::Get().io->Open(path)); + if (h.IsNull()) + return NULL; + + // Verify format. + char header[4]; + h->Read(header, 4); + if (memcmp(header, "RIFF", 4)) + return NULL; + h->Seek(4); + h->Read(header, 4); + if (memcmp(header, "WAVE", 4)) + return NULL; + + // Create sample. + AutoPtr sample(new SampleWav); + if (sample.IsNull()) + return NULL; + + // Parse format. + bool has_format = false, has_data = false; + + struct Format + { + short wFormatTag; + unsigned short wChannels; + unsigned long dwSamplesPerSec; + unsigned long dwAvgBytesPerSec; + unsigned short wBlockAlign; + unsigned short wBitsPerSample; + }; + Format format; + + Memory::Set(&format, 0, sizeof(Format)); + + forever + { + // Chunk + size. + if (h->Read(header, 4) != 4) + break; + uint chunk_size = h->Read (); + + // WAV format tag. + if (!memcmp(header, "fmt ", 4)) + { + uint cs = chunk_size; + if (cs > sizeof(Format)) + { + __LOG_W__ << "Unexpected WAV 'format' chunk size. Found " << cs << ", expected " << (int)sizeof(Format) << ".\n"; + cs = sizeof(Format); + } + if (h->Read(&format, cs) != cs) + __ERR__(__LOG_E__ << "Mangled WAV 'format' chunk in '" << path << "'.\n", NULL) + + Endian::ToHost(&format.wFormatTag, 2, Endian::Intel); + Endian::ToHost(&format.wChannels, 2, Endian::Intel); + Endian::ToHost(&format.dwSamplesPerSec, 4, Endian::Intel); + Endian::ToHost(&format.dwAvgBytesPerSec, 4, Endian::Intel); + Endian::ToHost(&format.wBlockAlign, 2, Endian::Intel); + Endian::ToHost(&format.wBitsPerSample, 2, Endian::Intel); + + has_format = true; + + // Finish skipping tag. + if (cs != chunk_size) + h->Seek(chunk_size - cs); + } + + // WAV data tag. + else if (!memcmp(header, "data", 4)) + { + if (has_format) + { + char *pcm = sample->AllocAs(chunk_size / (format.wBitsPerSample / 8) / format.wChannels, SampleFormat(SampleFormat::Format_PCM, format.wChannels, format.dwSamplesPerSec, (uchar)format.wBitsPerSample)); + if (!pcm) + __ERR__(__LOG_E__ << "failed to allocate WAV data chunk for '" << path << "'.\n", NULL) + if (h->Read(pcm, chunk_size) != chunk_size) + __ERR__(__LOG_E__ << "mangled WAV 'data' chunk in '" << path << "'.\n", NULL) + } + else + __ERR__(__LOG_E__ << "WAV data with no format in '" << path << "'.\n", NULL) + + has_data = true; + } + else + h->Seek(chunk_size); + } + + if (!has_format || !has_data) + return NULL; + + SampleFormat sample_format; + if (!sample->GetSampleFormat(sample_format)) + return NULL; + + __LOG__ << "Sample format: " << sample_format.frequency / 1000 << "KHz@" << sample_format.resolution << "bit, " << sample_format.channels << " channel(s).\n"; + return sample.Detach(); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/bih/bih.cpp b/include/framework/bih/bih.cpp new file mode 100644 index 0000000..568d372 --- /dev/null +++ b/include/framework/bih/bih.cpp @@ -0,0 +1,34 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "bih/bih.h" + + using namespace GS::BIH; + + +//------------------------------------------------------------------------------ +Node::~Node() +{ + if (p) + if (axis != Math::AxisNone) + delete [] ((Node *)p); + + p = 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Tree::Free() +{ + root = NULL; + sarray.Free(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tree::Tree() : min_leaf_vcount(8) {} +Tree::~Tree() { Free(); } +//------------------------------------------------------------------------------ diff --git a/include/framework/bih/bih_build.cpp b/include/framework/bih/bih_build.cpp new file mode 100644 index 0000000..eee6854 --- /dev/null +++ b/include/framework/bih/bih_build.cpp @@ -0,0 +1,160 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "bih/bih.h" + #include "timing/benchmark.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::BIH; + + +//----------------------------------------------------------------------------- +static void HalveMinMax(MinMax &minmax, int n, bool trim_max) +{ + if (trim_max) + minmax.mx[n] = (minmax.mn[n] + minmax.mx[n]) * 0.5f; + else minmax.mn[n] = (minmax.mn[n] + minmax.mx[n]) * 0.5f; +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +void Tree::MakeNodeLeaf(Node *node, uint count, uint *p_sarray, MinMax * /*varray*/) +{ + leaf_count++; + node->axis = Math::AxisNone; + node->p = (void *)p_sarray; + node->count = count; +} +void Tree::DoNodeSplit(MinMax &minmax, uint count, uint *sarray, MinMax *varray, uint &pivot, Node *node, uint &split_axis) +{ + // Determine split axis. + Vector4 dt = minmax.mx - minmax.mn; + + if ((dt.x > dt.y) && (dt.x > dt.z)) + split_axis = 0; + else if ((dt.y > dt.x) && (dt.y > dt.z)) + split_axis = 1; + else + split_axis = 2; + + float split_coord = (minmax.mn[split_axis] + minmax.mx[split_axis]) * 0.5f; + + // Fill split arrays. + float extends[2]; + uint high = count; + + //-------------------------------------------------------------------------- + #define __INDICE_SWAP__(LO, HI) { uint swp = sarray[LO]; sarray[LO] = sarray[HI]; sarray[HI] = swp; } + //-------------------------------------------------------------------------- + #define __GET_EXTENDS__(I, S) { extends[0] = varray[sarray[I]].mn[S]; extends[1] = varray[sarray[I]].mx[S]; } + + pivot = 0; + while (pivot < high) + { + __GET_EXTENDS__(pivot, split_axis) + if ((extends[1] - split_coord) > (split_coord - extends[0])) + { // max + __INDICE_SWAP__(pivot, high - 1) + high--; + } + else + { // min + __INDICE_SWAP__(0, pivot) + pivot++; + } + } + + // Node extends. + node->split[0] = -FLT_MAX; + + uint n; + for (n = 0; n < pivot; ++n) + { + __GET_EXTENDS__(n, split_axis) + if (extends[1] > node->split[0]) + node->split[0] = extends[1] + 0.0001f; + } + node->split[1] = FLT_MAX; + for (; n < count; ++n) + { + __GET_EXTENDS__(n, split_axis) + if (extends[0] < node->split[1]) + node->split[1] = extends[0] - 0.0001f; + } +} +bool Tree::Split(MinMax &l_minmax, uint count, uint *p_sarray, MinMax *varray, Node *node, uint dpth) +{ + if ((count <= min_leaf_vcount) || (dpth == 64)) + { + if (dpth > depth) + depth = dpth; + MakeNodeLeaf(node, count, p_sarray, varray); + } + else + { + // Split node. + uint pivot, split_axis; + DoNodeSplit(l_minmax, count, p_sarray, varray, pivot, node, split_axis); + + // Distribute to children. + node_count += 2; + Node *children = new Node[2]; + if (!children) + __ERR__(__LOG_E__ << "Failed to allocate BIH node children.\n", false) + node->axis = (char)split_axis; + node->p = (void *)children; + + MinMax minmax_child = l_minmax; + HalveMinMax(minmax_child, split_axis, true); + Split(minmax_child, pivot, p_sarray, varray, &children[0], dpth + 1); + minmax_child = l_minmax; + HalveMinMax(minmax_child, split_axis, false); + Split(minmax_child, count - pivot, &p_sarray[pivot], varray, &children[1], dpth + 1); + } + return true; +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +bool Tree::Build(uint count, MinMax *varray) +{ + Benchmark build_bench(true); + + if (!count) + return false; + + // Initialize split array. + if (!sarray.Allocate(count)) + __ERR__(__LOG_E__ << "Failed to allocate BIH indice array.\n", false) + + uint n; + for (n = 0; n < count; ++n) + sarray[n] = n; + + // Get volume set bounding coordinates. + minmax = varray[0]; + for (n = 1; n < count; ++n) + minmax.Grow(varray[n]); + minmax.mn -= 0.0001f; + minmax.mx += 0.0001f; + + // Split. + leaf_count = 0; + node_count = 1; + depth = 0; + + if (!(root = new Node)) + __ERR__(__LOG_E__ << "Failed to allocate BIH root node.\n", false) + + bool success = Split(minmax, count, sarray, varray, root, 0); + + build_bench.Stop(); +// __LOG__ << "Done in " << build_bench.GetLastStepMs() << "ms. " << node_count << " nodes, " << leaf_count << " leaves, depth = " << depth << ".\n"; + return success; +} +//----------------------------------------------------------------------------- diff --git a/include/framework/bih/bih_intersect.cpp b/include/framework/bih/bih_intersect.cpp new file mode 100644 index 0000000..62dacc7 --- /dev/null +++ b/include/framework/bih/bih_intersect.cpp @@ -0,0 +1,55 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "bih/bih.h" + + using namespace GS; + using namespace GS::BIH; + + +//------------------------------------------------------------------------------ +uint Tree::IntersectNode(Node *node, MinMax &mm, uint *iarray, uint max) +{ + uint count = 0; + + if (node->axis == 3) + { + if (node->count > max) + return 0; + + Memory::Copy(iarray, (uint *)node->p, sizeof(uint) * node->count); + return node->count; + } + else + { + if (mm.mx[node->axis] > node->split[1]) + { + MinMax sub_mm = mm; + if (node->split[1] > sub_mm.mn[node->axis]) + sub_mm.mn[node->axis] = node->split[1]; + + uint added = IntersectNode(&((Node *)node->p)[1], sub_mm, iarray/* + count*/, max); + max -= added; count += added; + } + if (mm.mn[node->axis] < node->split[0]) + { + MinMax sub_mm = mm; + if (node->split[0] < sub_mm.mx[node->axis]) + sub_mm.mx[node->axis] = node->split[0]; + + uint added = IntersectNode(&((Node *)node->p)[0], sub_mm, iarray + count, max); + /*max -= added;*/ count += added; + } + } + return count; +} +uint Tree::Intersect(MinMax &in_mm, uint *iarray, uint max) +{ + if (root.IsNull() || !in_mm.TestOverlap(minmax)) + return 0; + return IntersectNode(root, in_mm, iarray, max); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/bih/bih_trace.cpp b/include/framework/bih/bih_trace.cpp new file mode 100644 index 0000000..8adc62a --- /dev/null +++ b/include/framework/bih/bih_trace.cpp @@ -0,0 +1,101 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "bih/bih.h" + + using namespace GS; + using namespace GS::BIH; + + +//------------------------------------------------------------------------------ +void Tree::Raytrace(Trace &trace, const Vector4 &s, const Vector4 &d, float l, void *parm) +{ + trace.has_i = false; + trace.i_t = -1; + trace.node_visited = 0; + trace.stack_pos = 0; + + // Intersect BIH bounding volume. + float tmin, tmax; + if (!minmax.IntersectRay(s, d, tmin, tmax)) + return; + + // Reject if intersection is too far away. + if ((l > 0) && (tmin >= l)) + return; + + // Initialize trace. + trace.s = s; + trace.d = d; + + tmax = ((l > 0) && (tmax > l)) ? l : tmax; + + // Iterative trace. + float i_t[2]; + + for (Node *node = root; node; ) + { + if (!trace.has_i || ((tmin < trace.i_t) && trace.want_closest)) // Only bother about rays that could lead to a closer hit. + { + while (node->axis != 3) + { + if (d[node->axis] == 0) // Axis aligned. + { + if (node->split[0] > s[node->axis]) + { + if (s[node->axis] > node->split[1]) + { + trace.stack[trace.stack_pos].node = &((Node *)node->p)[1]; + trace.stack[trace.stack_pos].tmin = tmin; + trace.stack[trace.stack_pos++].tmax = tmax; + } + node = &((Node *)node->p)[0]; + } + else if (s[node->axis] > node->split[1]) + node = &((Node *)node->p)[1]; + else break; // Empty space. + } + else + { + float idn = 1.f / d[node->axis]; + i_t[0] = (node->split[0] - s[node->axis]) * idn; + i_t[1] = (node->split[1] - s[node->axis]) * idn; + + int min = d[node->axis] > 0 ? 0 : 1, max = 1 - min; + + if (i_t[min] > tmin) + { + if (tmax > i_t[max]) + { + trace.stack[trace.stack_pos].node = &((Node *)node->p)[max]; + trace.stack[trace.stack_pos].tmin = (i_t[max] > tmin) ? i_t[max] : tmin; + trace.stack[trace.stack_pos++].tmax = tmax; + } + node = &((Node *)node->p)[min]; + tmax = (i_t[min] < tmax) ? i_t[min] : tmax; + } + else if (tmax > i_t[max]) + { + node = &((Node *)node->p)[max]; + tmin = (i_t[max] > tmin) ? i_t[max] : tmin; + } + else break; // Empty space. + } + trace.node_visited++; + } + if (node->axis == 3) + TraceLeaf(node, tmin, tmax, trace, parm); + } + + if (!trace.stack_pos) + break; + + node = trace.stack[--trace.stack_pos].node; + tmin = trace.stack[trace.stack_pos].tmin; + tmax = trace.stack[trace.stack_pos].tmax; + } +} +//------------------------------------------------------------------------------ diff --git a/include/framework/color/color.cpp b/include/framework/color/color.cpp new file mode 100644 index 0000000..2ee04b6 --- /dev/null +++ b/include/framework/color/color.cpp @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "color/color.h" + + using namespace GS; + + Color Color::White(1, 1, 1), + Color::Grey(0.5, 0.5, 0.5), + Color::Black(0, 0, 0), + Color::Red(1, 0, 0), + Color::Green(0, 1, 0), + Color::Blue(0, 0, 1), + Color::Yellow(1, 1, 0), + Color::Purple(1, 0, 1); + + +//------------------------------------------------------------------------------ +uint Color::AsInteger() const +{ + uint value; + uchar *pl = (uchar *)&(value); +#if (__PLATFORM_WINDOWS__ || __PLATFORM_LINUX__ || __PLATFORM_NINTENDO_WII__) + float tmp_x = (x * 255.f) + 256.f, + tmp_y = (y * 255.f) + 256.f, + tmp_z = (z * 255.f) + 256.f, + tmp_w = (w * 255.f) + 256.f; + + pl[0] = (uchar)((((int &)tmp_x) & 0x7fffff) >> 15); + pl[1] = (uchar)((((int &)tmp_y) & 0x7fffff) >> 15); + pl[2] = (uchar)((((int &)tmp_z) & 0x7fffff) >> 15); + pl[3] = (uchar)((((int &)tmp_w) & 0x7fffff) >> 15); +#else + pl[0] = (uchar)(Types::Clamp(x, 0.f, 1.f) * 255.f); + pl[1] = (uchar)(Types::Clamp(y, 0.f, 1.f) * 255.f); + pl[2] = (uchar)(Types::Clamp(z, 0.f, 1.f) * 255.f); + pl[3] = (uchar)(Types::Clamp(w, 0.f, 1.f) * 255.f); +#endif + return value; +} +void Color::FromInteger(uint value) +{ + const uchar *pl = (const uchar *)&(value); + const float i255 = 1.f / 255.f; + x = (float)(pl[0]) * i255; + y = (float)(pl[1]) * i255; + z = (float)(pl[2]) * i255; + w = (float)(pl[3]) * i255; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/data/nvariant.cpp b/include/framework/data/nvariant.cpp new file mode 100644 index 0000000..a77e38a --- /dev/null +++ b/include/framework/data/nvariant.cpp @@ -0,0 +1,280 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include + #include "data/nvariant.h" + #include "alloc/ialloc.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Variant::Reset() +{ + type = VariantNone; +} +void Variant::Free() +{ + switch (type) + { + case VariantString: + s_value.Clear(); + break; + + case VariantBinary: + _safe_delete_array(d_value); + d_size = 0; + break; + + default: + break; + } + type = VariantNone; +} +Variant::~Variant() +{ Free(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant &Variant::operator = (const Variant &v) +{ + switch (v.GetType()) + { + case VariantBool: *this = v.b_value; break; + case VariantInteger: *this = v.i_value; break; + case VariantFloat: *this = v.f_value; break; + case VariantString: *this = v.s_value; break; + case VariantBinary: + { + Free(); + void *v_data; size_t v_size; + if (v.GetBinary(v_data, v_size)) + SetBinary(v_data, v_size); + } + break; + + default: + Free(); + break; + } + return *this; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Variant::operator < (const Variant &b) const +{ + switch (GetType()) + { + case VariantBool: + if (b.GetType() == VariantBool) + return b_value < b.b_value; + break; + + case VariantInteger: + switch (b.GetType()) + { + case VariantInteger: return i_value < b.i_value; + case VariantFloat: return i_value < (int)b.f_value; + + default: break; + } + break; + + case VariantFloat: + switch (b.GetType()) + { + case VariantInteger: return f_value < (float)b.i_value; + case VariantFloat: return f_value < b.f_value; + + default: break; + } + break; + + default: break; + } + return false; +} +bool Variant::operator > (const Variant &b) const +{ return !(*this < b); } +bool Variant::operator == (const Variant &b) const +{ + switch (GetType()) + { + case VariantBool: + if (b.GetType() == VariantBool) + return b_value == b.b_value; + break; + + case VariantInteger: + switch (b.GetType()) + { + case VariantInteger: return i_value == b.i_value; + case VariantFloat: return i_value == (int)b.f_value; + + default: break; + } + break; + + case VariantFloat: + switch (b.GetType()) + { + case VariantInteger: return f_value == (float)b.i_value; + case VariantFloat: return f_value == b.f_value; + + default: break; + } + break; + + case VariantString: + if (b.GetType() == VariantString) + return s_value == b.s_value; + break; + + default: break; + } + return false; +} +bool Variant::operator != (const Variant &b) const +{ return !(*this == b); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant &Variant::operator = (const char *v) +{ + Free(); + s_value.Set(v); + type = VariantString; + return *this; +} +bool Variant::Get(const char * &v) const +{ + if (type != VariantString) + return false; + v = s_value.c_str(); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant &Variant::operator = (int v) +{ + Free(); + type = VariantInteger; + i_value = v; + return *this; +} +bool Variant::Get(int &v) const +{ + switch (type) + { + case VariantBool: v = b_value ? 1 : 0; return true; + case VariantInteger: v = i_value; return true; + case VariantFloat: v = (int)f_value; return true; + + default: break; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant &Variant::operator = (uint v) +{ + Free(); + type = VariantInteger; + u_value = v; + return *this; +} +bool Variant::Get(uint &v) const +{ + switch (type) + { + case VariantBool: v = b_value ? 1 : 0; return true; + case VariantInteger: v = u_value; return true; + case VariantFloat: v = (int)f_value; return true; + + default: break; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant &Variant::operator = (bool v) +{ + Free(); + type = VariantBool; + b_value = v; + return *this; +} +bool Variant::Get(bool &v) const +{ + switch (type) + { + case VariantBool: v = b_value; return true; + case VariantInteger: v = asbool(i_value); return true; + case VariantFloat: v = asbool(f_value); return true; + + default: break; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Variant &Variant::operator = (float v) +{ + Free(); + type = VariantFloat; + f_value = v; + return *this; +} +bool Variant::Get(float &v) const +{ + switch (type) + { + case VariantBool: v = b_value ? 1.f : 0.f; return true; + case VariantInteger: v = (float)i_value; return true; + case VariantFloat: v = f_value; return true; + + default: break; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Variant::SetBinary(const void *v, size_t size) +{ + Free(); + + d_value = new char[size]; + if (d_value) + { + memcpy(d_value, v, size); + d_size = size; + type = VariantBinary; + } + return true; +} +bool Variant::GetBinary(void *&data, size_t &size) const +{ + if (type != VariantBinary) + return false; + + data = (void *)new char[d_size]; + if (data == NULL) + { + size = 0; + return false; + } + + memcpy(data, d_value, d_size); + size = d_size; + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/data/registry.cpp b/include/framework/data/registry.cpp new file mode 100644 index 0000000..2a9605f --- /dev/null +++ b/include/framework/data/registry.cpp @@ -0,0 +1,86 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "data/registry.h" + + using namespace GS; + using GS::NML::Tag; + + +//------------------------------------------------------------------------------ +Tag *Registry::CreateKey(const char *path, const Variant *value, bool /*recursive*/) +{ + StringList tag_path_list; + String(path).TrimChar(';').Split(":", tag_path_list); + + Tag *ctag = NULL; + for (uint n = 0; n < tag_path_list.GetCount(); ++n) + { + String &tag_path = tag_path_list.ObjectAt(n); + + Tag *ntag = ctag ? ctag->GetTag(tag_path) : GetTag(tag_path); + if (ntag == NULL) + ntag = ctag ? ctag->AddChild(tag_path) : AddRoot(tag_path); + if ((ctag = ntag) == NULL) + return NULL; + } + + if (ctag && value) + { + ctag->GetValue() = *value; + RegistryKeyChange msg(path); + BroadcastMessage(RegistryMsg_KeyChange, this, &msg); + } + return ctag; +} +Tag *Registry::CreateKey(const char *path, const Variant &value, bool recursive) +{ return CreateKey(path, &value, recursive); } +bool Registry::DeleteKey(const char *path) +{ + StringList tag_path_list; + String(path).Split(":", tag_path_list); + + Tag *ctag = NULL, *ptag = NULL; + for (uint n = 0; n < tag_path_list.GetCount(); ++n) + { + ptag = ctag; + String &tag_path = tag_path_list.ObjectAt(n); + Tag *ntag = ctag ? ctag->GetTag(tag_path) : GetTag(tag_path); + if (!ntag) + return false; + ctag = ntag; + } + if (!ctag) + return false; + + if (ptag) + ptag->RemoveTag(ctag); + else + tags.Remove(ctag); + + _safe_delete(ctag); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Registry::GetReal(const char *path, float default_value) const +{ + Tag *tag = GetTag(path); + float v; + if (!tag || !tag->GetValue().Get(v)) + return default_value; + return v; +} +bool Registry::GetBool(const char *path, bool default_value) const +{ + Tag *tag = GetTag(path); + bool v; + if (!tag || !tag->GetValue().Get(v)) + return default_value; + return v; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/font/font_cache.cpp b/include/framework/font/font_cache.cpp new file mode 100644 index 0000000..1d75c85 --- /dev/null +++ b/include/framework/font/font_cache.cpp @@ -0,0 +1,93 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "font/font_cache.h" + #include "font/font_extended.h" + #include "filesystem/filesystem.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +FontEx *FontCache::GetFont(const char *name) const +{ + ListForeachPtr(FontAlias *, alias, font_aliases) + if (alias->font->GetName() == name) + return alias->font; + + return NULL; +} +FontAlias *FontCache::GetAlias(const char *alias) const +{ + ListForeachPtr(FontAlias *, font, font_aliases) + if (font->alias == alias) + return font; + return NULL; +} +FontEx *FontCache::GetAliasedFont(const char *alias) const +{ + FontAlias *fa = GetAlias(alias); + return fa ? fa->font.c_ptr() : NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +FontEx *FontCache::LoadFont(const char *path, const char *alias) +{ + // Look for an already loaded instance of the font. + FontEx *font = GetFont(path); + + // If font is not available, load it. + if (font == NULL) + { + IFont *base_font = font_factory->LoadFont(path); + if (base_font == NULL) + return NULL; + + // Wrap with an extended font. + font = new FontEx(base_font); + } + + // Format default alias if none provided. + String _alias(path); + _alias.FileCutPathAndExtension(); + if (!alias) + alias = _alias; + + // Drop current alias if existing. + FontAlias *font_alias = GetAlias(alias); + if (font_alias) + font_aliases.Remove(font_alias); + + // Create the alias. + font_alias = new FontAlias; + font_alias->alias = alias; + font_alias->font = font; + + font_aliases.Add(font_alias); + + __LOG__ << "Created a new font alias from '" << path << "' to '" << alias << "'.\n"; + return font; +} +void FontCache::DeleteAlias(const char *alias) +{ + ListForeachPtr(FontAlias *, a, font_aliases) + if (a->alias == alias) + font_aliases.Remove(a); +} +void FontCache::DeleteAllFont() +{ + font_aliases.Clear(); +} +//------------------------------------------------------------------------------ + +FontCache::~FontCache() +{ + // [EJ] Get rid of the fonts before the factory. + DeleteAllFont(); +} diff --git a/include/framework/font/font_extended.cpp b/include/framework/font/font_extended.cpp new file mode 100644 index 0000000..c74d0f3 --- /dev/null +++ b/include/framework/font/font_extended.cpp @@ -0,0 +1,47 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "font/font_extended.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool FontEx::SetPixelSize(int size) +{ + pixel_size = size; + return current_glyph_font.IsValid() ? current_glyph_font->SetPixelSize(size) : font->SetPixelSize(size); +} +bool FontEx::HasKerning() const +{ return current_glyph_font.IsValid() ? current_glyph_font->HasKerning() : font->HasKerning(); } +int FontEx::GetKerning(uint previous_codepoint, uint codepoint) const +{ return current_glyph_font.IsValid() ? current_glyph_font->GetKerning(previous_codepoint, codepoint) : font->GetKerning(previous_codepoint, codepoint); } + +int FontEx::GetHeight() const +{ return current_glyph_font.IsValid() ? current_glyph_font->GetHeight() : font->GetHeight(); } +int FontEx::GetAdvance() const +{ return current_glyph_font.IsValid() ? current_glyph_font->GetAdvance() : font->GetAdvance(); } + +bool FontEx::LoadGlyph(uint codepoint, bool for_render) +{ + current_glyph_font = font; + if (font->LoadGlyph(codepoint, for_render)) + return true; + + // Synchronize and try fallback. + if (fallback.IsNull()) + return false; + + fallback->SetPixelSize(pixel_size); + bool r = fallback->LoadGlyph(codepoint, for_render); + + if (r) + current_glyph_font = fallback; + return r; +} +bool FontEx::RenderCurrentGlyph(Picture &picture, const iPoint &position, const iRect &clip, const Color &color) +{ return current_glyph_font.IsValid() ? current_glyph_font->RenderCurrentGlyph(picture, position, clip, color) : font->RenderCurrentGlyph(picture, position, clip, color); } +//------------------------------------------------------------------------------ diff --git a/include/framework/font/font_renderer.cpp b/include/framework/font/font_renderer.cpp new file mode 100644 index 0000000..2af5160 --- /dev/null +++ b/include/framework/font/font_renderer.cpp @@ -0,0 +1,377 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "font/font_renderer.h" + #include "picture/pict.h" + #include "ascii/parser.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::AsciiParser; + + float FontRenderer::default_text_tracking = 0; + float FontRenderer::default_text_heading = 0; + +// +struct GS::SubString +{ + const char *entry; + int char_count; + int space_count; + int width; // 26.6 + int height; + + void Reset(const char *string) + { + entry = string; + char_count = 0; + space_count = 0; + width = 0; + height = 0; + } +}; + + int substring_count = 0; + SubString substring_array[1024]; + + +//------------------------------------------------------------------------------ +const char *FontRenderer::CheckCommand(const char *string, Command &command) +{ + command.code = CommandNone; + if (!string[0] || !string[1]) + return string; + + if ((string[0] == '~') && (string[1] == '~')) + { + //---------------------------------------------------------------------- + #define PARSE_COMPONENT(_C_, _M_)\ + {\ + string = SkipSpace(string + 1, eos);\ + command.vector._C_ = (float)String::atoi(string);\ + string = NextEntry(string, eos);\ + if (string[0] != (_M_))\ + {\ + command.code = CommandParseError;\ + __LOG_E__ << "Error parsing text command components.\n";\ + return NULL;\ + }\ + } + //---------------------------------------------------------------------- + + const char *eos = string + std::strlen(string); + + if (!strncmp("Color(", string + 2, 6) || !strncmp("COLOR(", string + 2, 6)) // [EJ] 1st may: range is [0;255] + { + command.code = CommandColor; + string += 7; + + const char *eop = Find(string, eos, ')'); + if (!eop) + { + command.code = CommandParseError; + return NULL; + } + + PARSE_COMPONENT(x, ','); + PARSE_COMPONENT(y, ','); + PARSE_COMPONENT(z, ','); + PARSE_COMPONENT(w, ')'); + string = eop + 1; + } + else if (!strncmp("Size(", string + 2, 5) || !strncmp("SIZE(", string + 2, 5)) + { + command.code = CommandSize; + + string += 6; + + const char *eop = Find(string, eos, ')'); + if (!eop) + { + command.code = CommandParseError; + return NULL; + } + + PARSE_COMPONENT(x, ')'); + string = eop + 1; + } + } + return string; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +const char *FontRenderer::FetchSubString(const char *string, SubString &substring, TextState &state, int max_width, int max_char) +{ + if (!string) + return NULL; + + // Jump over leading spaces. + forever + { + if (string[0] != ' ') + break; + + if (!string[0] || (string[0] == '\n')) + { + substring.Reset(NULL); + return string; + } + string++; + } + + // Start sub-string. + substring.Reset(string); + int previous_codepoint = 0; + + state.font->SetPixelSize(state.GetSize()); + max_width <<= 6; + + // Word cut point. + bool rollback_available = false; + SubString rollback_substring; + const char *rollback_string = NULL; + + int tracking = int(state.GetTracking() * 64.f); + + forever + { + Command command; + if ((string = CheckCommand(string, command)) == 0) + break; + + if (command.code == CommandNone) + { + if (string[0] == '\n') + { + string++; + break; + } + if ((string[0] == '\\') && (string[1] == 'n')) + { + string += 2; + break; + } + if (string[0] == 0) + break; + if ((max_char > 0) && (substring.char_count == max_char)) + break; + + // Get glyph. + uint codepoint; + int codelength = String::Utf8toUtf32((const uchar *)string, &codepoint); + + state.font->LoadGlyph(codepoint, false); + + // Retrieve glyph formatting informations. + int advance = state.font->GetAdvance(); + int kerning = (state.font->HasKerning() && (previous_codepoint != 0)) ? state.font->GetKerning(previous_codepoint, codepoint) : 0; + + // Width constraint. + if ((max_width > 0) && ((substring.width + advance) >= max_width)) + { + rollback_available = true; + break; + } + + substring.width += advance + kerning + tracking; + substring.height = Types::Max(state.font->GetHeight(), substring.height); + + // Count space. + if (string[0] == ' ') + { + substring.space_count++; + + // Store the word rollback position. + Command dummy_command; + CheckCommand(string, dummy_command); + + if ((dummy_command.code == CommandNone) && (string[1] != ' ')) + { + rollback_substring = substring; + rollback_string = string; + } + } + substring.char_count++; + + // Next glyph. + string += codelength ? codelength : 1; + previous_codepoint = codepoint; + } + else + switch (command.code) + { + case CommandColor: // Irrelevant when not composing. + break; + + case CommandSize: + state.SetSize((int)command.vector.x); + state.font->SetPixelSize(state.GetSize()); + break; + + default: break; + } + } + + // Rollback to the last word position. + if (rollback_available && rollback_string) + { + substring = rollback_substring; + string = rollback_string; + } + return string; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void FontRenderer::DrawSubString(SubString &line, Picture &output, TextState &state, const iRect &_out_rect, const iRect &clip_rect, int justification) +{ + const char *string = line.entry; + state.font->SetPixelSize(state.GetSize()); + + iRect out_rect(_out_rect); + uint previous_codepoint = 0; + + int tracking = int(state.GetTracking() * 64.f); + + for (int n = 0; n < line.char_count; ++n) + { + Command command; + string = CheckCommand(string, command); + + if (command.code == CommandNone) + { + // Get glyph. + uint codepoint; + int codelength = String::Utf8toUtf32((const uchar *)string, &codepoint); + + state.font->LoadGlyph(codepoint, true); + + // Retrieve glyph formatting informations. + int advance = state.font->GetAdvance(); + int kerning = (state.font->HasKerning() && (previous_codepoint != 0)) ? state.font->GetKerning(previous_codepoint, codepoint) : 0; + + // Render. + int px = out_rect.sx >> 6; + int py = (out_rect.sy + (line.height * 3) / 4) >> 6; // FIXME smells the hack... at best! + + state.font->RenderCurrentGlyph(output, iPoint(px, py), clip_rect, state.color); + + out_rect.sx += advance + kerning + tracking; + + // Next glyph. + string += codelength; + previous_codepoint = codepoint; + } + else + { + switch (command.code) + { + case CommandColor: + state.color = command.vector ;/// 255.f; + break; + + case CommandSize: + state.SetSize((int)command.vector.x); + state.font->SetPixelSize(state.GetSize()); + break; + + default: break; + } + --n; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +iRect FontRenderer::Format(const char *txt, const TextState &in_state, const iRect &out_rect) +{ + if (!in_state.font) + return iRect (0, 0, 0, 0); + + // Create working state. + TextState state = in_state; + + // Setup formatting rules. + int max_width = (state.format == TextState::Line) ? -1 : out_rect.GetWidth(), + max_char = (state.format != TextState::Column) ? -1 : state.column_width; + + // Fetch all substrings. + substring_count = 0; + while (txt && txt[0]) + txt = FetchSubString(txt, substring_array[substring_count++], state, max_width, max_char); + + // Create full text rectangle. + iRect text_rect; + text_rect.Set(0, 0, 0, 0); + + int leading = int(state.GetLeading() * 64); + + for (int n = 0; n < substring_count; ++n) + { + if (text_rect.ex < substring_array[n].width) + text_rect.ex = substring_array[n].width; + text_rect.ey += substring_array[n].height + leading; + } + if (substring_count > 0) + text_rect.ey -= leading; + + text_rect.ex = text_rect.ex / 64; + text_rect.ey = text_rect.ey / 64; + return text_rect; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +iRect FontRenderer::Compose(Picture &output, const char *txt, const TextState &in_state, const iRect &out_rect, const iRect &clip_rect) +{ + if (in_state.font.IsNull() || (output.GetPixelFormat().GetBpp() != 32)) + return iRect(0, 0, 0, 0); + + // Create working state. + TextState state = in_state; + int leading = int(state.GetLeading() * 64); + + // Draw substrings. + iRect work_out_rect(out_rect * 64); + + for (int n = 0; n < substring_count; ++n) + { + iRect line_rect(work_out_rect); + line_rect.ex = line_rect.sx + substring_array[n].width; + + int offset = 0, justification = 0; + + switch (state.alignment) + { + case TextState::Left: + offset = out_rect.sx * 64 - line_rect.sx; + break; + case TextState::Center: + offset = (out_rect.GetWidth() * 64 - line_rect.GetWidth()) / 2; + break; + case TextState::Right: + offset = out_rect.ex * 64 - line_rect.ex; + break; + + case TextState::Justify: + if (n < (substring_count - 1)) + justification = (out_rect.GetWidth() * 64 - line_rect.GetWidth()) / substring_array[n].space_count; + break; + + default: break; + } + + line_rect.sx += offset; + + DrawSubString(substring_array[n], output, state, line_rect, clip_rect, justification); + work_out_rect.sy += substring_array[n].height + leading; + } + return out_rect; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/geometry/bounding_box.cpp b/include/framework/geometry/bounding_box.cpp new file mode 100644 index 0000000..45eeef2 --- /dev/null +++ b/include/framework/geometry/bounding_box.cpp @@ -0,0 +1,342 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "geometry/bounding_box.h" + #include "metafile/nml.h" + #include "math/matrix4.h" + + using namespace GS; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +void OBB::Transform(const Matrix4 &mtx) +{ + Matrix3 rmtx = Matrix3::FromMatrix4(mtx); + bb_rotation = rmtx * bb_rotation; + bb_position = bb_position * rmtx + mtx.GetRow(3); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void OBB::ComputeMinMax(MinMax &minmax) +{ + Vector4 xtd(bb_scale * 0.5f); + Vector4 smt[4]; + + smt[0].Set(xtd.x, xtd.y, xtd.z); + smt[1].Set(-xtd.x, xtd.y, xtd.z); + smt[2].Set(xtd.x, -xtd.y, xtd.z); + smt[3].Set(xtd.x, xtd.y, -xtd.z); + + int n; + for (n = 0; n < 4; n++) + smt[n] = (smt[n] * bb_rotation).Abs(); + + minmax.mx = smt[0]; + for (n = 1; n < 4; n++) + { + if (smt[n].x > minmax.mx.x) minmax.mx.x = smt[n].x; + if (smt[n].y > minmax.mx.y) minmax.mx.y = smt[n].y; + if (smt[n].z > minmax.mx.z) minmax.mx.z = smt[n].z; + } + minmax.mn.x = -minmax.mx.x; + minmax.mn.y = -minmax.mx.y; + minmax.mn.z = -minmax.mx.z; + + minmax.mn += bb_position; + minmax.mx += bb_position; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool OBB::FromMetaTag(Tag &tag) +{ + Tag *t; + List ::Iterator i(tag.GetTags().GetRoot()); + + t = i.ObjectPtr(); + if (!t) return false; + bb_position.FromMetaTag(*t); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + bb_scale.FromMetaTag(*t); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + bb_rotation.FromMetaTag(*t); + return true; +} +Tag *OBB::AsMetaTag() +{ + Tag *root = new Tag("OBB"); + if (root) + { + root->AddChild(bb_position.AsMetaTag("Position")); + root->AddChild(bb_scale.AsMetaTag("Scale")); + root->AddChild(bb_rotation.AsMetaTag("Matrix")); + } + return root; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool MinMax::IntersectRay(const Vector4 &o, const Vector4 &d, float &tmin, float &tmax) +{ + tmin = 0; + tmax = FLT_MAX; + + for (uint n = 0; n < 3; ++n) + if (Math::EqualZero(d[n])) + { + if ((o[n] < mn[n]) || (o[n] > mx[n])) + return false; + } + else + { + float ood = 1.f / d[n]; + float t0 = (mn[n] - o[n]) * ood; + float t1 = (mx[n] - o[n]) * ood; + + if (t0 > t1) + { float swp = t1; t1 = t0; t0 = swp; } + + tmin = tmin < t0 ? t0 : tmin; + tmax = tmax < t1 ? tmax : t1; + + if (tmin > tmax) + return false; + } + return true; +} +bool MinMax::ClassifyLine(const Vector4 &p1, const Vector4 &direction, Vector4 &itr, Vector4 *n) const +{ + uint oc1, oc2; + + oc1 = cc_oc(mn, mx, p1); + if (oc1 == ClipNone) + { + // Point inside bounding box. + if (n) + n->Set(0, 0, 0); + itr = p1; + return true; + } + + oc2 = ss_oc(direction); + + // Same side. + if ((oc1 & oc2) > ClipNone) + return false; + + // Check intersections. + if (oc1 & (ClipRight | ClipLeft)) + { + if (oc1 & ClipRight) + { + if (n) + n->Set(1, 0, 0); + itr.x = mx.x; + } + else + { + if (n) + n->Set(-1, 0, 0); + itr.x = mn.x; + } + float x1 = direction.x; + float x2 = itr.x - p1.x; + itr.y = p1.y + x2 * direction.y / x1; + itr.z = p1.z + x2 * direction.z / x1; + + if ((itr.y <= mx.y) && (itr.y >= mn.y) && (itr.z <= mx.z) && (itr.z >= mn.z)) + return true; + } + if (oc1 & (ClipTop | ClipBottom)) + { + if (oc1 & ClipTop) + { + if (n) + n->Set(0, 1, 0); + itr.y = mx.y; + } + else + { + if (n) + n->Set(0, -1, 0); + itr.y = mn.y; + } + float y1 = direction.y; + float y2 = itr.y - p1.y; + itr.x = p1.x + y2 * direction.x / y1; + itr.z = p1.z + y2 * direction.z / y1; + + if ((itr.x <= mx.x) && (itr.x >= mn.x) && (itr.z <= mx.z) && (itr.z >= mn.z)) + return true; + } + if (oc1 & (ClipFront | ClipBack)) + { + if (oc1 & ClipBack) + { + if (n) + n->Set(0, 0, 1); + itr.z = mx.z; + } + else + { + if (n) + n->Set(0, 0, -1); + itr.z = mn.z; + } + float z1 = direction.z; + float z2 = itr.z - p1.z; + itr.x = p1.x + z2 * direction.x / z1; + itr.y = p1.y + z2 * direction.y / z1; + + if ((itr.x <= mx.x) && (itr.x >= mn.x) && (itr.y <= mx.y) && (itr.y >= mn.y)) + return true; + } + return false; +} +bool MinMax::ClassifySegment(const Vector4 &p1, const Vector4 &p2, Vector4 &itr, Vector4 *n) const +{ + uint oc1, oc2; + + oc1 = cc_oc(mn, mx, p1); + if (oc1 == ClipNone) + { + // Point inside bounding box. + if (n) + n->Set(0, 0, 0); + itr = p1; + return true; + } + + oc2 = cc_oc(mn, mx, p2); + if (oc2 == ClipNone) + { + // point inside bounding box + itr = p2; + return true; + } + + // Same side. + if ((oc1 & oc2) > ClipNone) + return false; + + // Check intersections. + if (oc1 & (ClipRight | ClipLeft)) + { + if (oc1 & ClipRight) + { + if (n) + n->Set(1, 0, 0); + itr.x = mx.x; + } + else + { + if (n) + n->Set(-1, 0, 0); + itr.x = mn.x; + } + + float x1 = p2.x - p1.x; + float x2 = itr.x - p1.x; + itr.y = p1.y + x2 * (p2.y - p1.y) / x1; + itr.z = p1.z + x2 * (p2.z - p1.z) / x1; + + if ( (itr.y <= mx.y) && + (itr.y >= mn.y) && + (itr.z <= mx.z) && + (itr.z >= mn.z) ) + return true; + } + if (oc1 & (ClipTop | ClipBottom)) + { + if (oc1 & ClipTop) + { + if (n) + n->Set(0, 1, 0); + itr.y = mx.y; + } + else + { + if (n) + n->Set(0, -1, 0); + itr.y = mn.y; + } + float y1 = p2.y - p1.y; + float y2 = itr.y - p1.y; + itr.x = p1.x + y2 * (p2.x - p1.x) / y1; + itr.z = p1.z + y2 * (p2.z - p1.z) / y1; + + if ( (itr.x <= mx.x) && + (itr.x >= mn.x) && + (itr.z <= mx.z) && + (itr.z >= mn.z) ) + return true; + } + if (oc1 & (ClipFront | ClipBack)) + { + if (oc1 & ClipBack) + { + if (n) + n->Set(0, 0, 1); + itr.z = mx.z; + } + else + { + if (n) + n->Set(0, 0, -1); + itr.z = mn.z; + } + float z1 = p2.z - p1.z; + float z2 = itr.z - p1.z; + itr.x = p1.x + z2 * (p2.x - p1.x) / z1; + itr.y = p1.y + z2 * (p2.y - p1.y) / z1; + + if ( (itr.x <= mx.x) && + (itr.x >= mn.x) && + (itr.y <= mx.y) && + (itr.y >= mn.y) ) + return true; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool MinMax::FromMetaTag(Tag &tag) +{ + Tag *t; + List ::Iterator i(tag.GetTags().GetRoot()); + + t = i.ObjectPtr(); + if (!t) return false; + mn.FromMetaTag(*t); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + mx.FromMetaTag(*t); + + return true; +} +Tag *MinMax::AsMetaTag() +{ + Tag *root = new Tag("MinMax"); + if (root) + { + root->AddChild(mn.AsMetaTag("Min")); + root->AddChild(mx.AsMetaTag("Max")); + } + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/geometry/curve.cpp b/include/framework/geometry/curve.cpp new file mode 100644 index 0000000..a097ad1 --- /dev/null +++ b/include/framework/geometry/curve.cpp @@ -0,0 +1,549 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "geometry/curve.h" + #include "sort/sort.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Curve::Update(const CurvePoint &p, const Time &t_epsilon) +{ + for (uint n = 0; n < points.GetCount(); ++n) + { + CurvePoint *point = points[n]; + if ((p.t >= (point->t - t_epsilon)) && (p.t <= (point->t + t_epsilon))) + { + point->v = p.v; + return; + } + } + Insert(p); +} +void Curve::Insert(const CurvePoint &k) +{ + int idx = GetPointIndex(k.t); + points.Insert(new CurvePoint(k), (idx == -1) ? points.GetCount() : idx); +} +void Curve::Append(const CurvePoint &k) +{ + points.Insert(new CurvePoint(k), points.GetCount()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Curve::Delete(CurvePoint *k) +{ + points.Remove(k); + delete k; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int Curve::GetPointIndex(const Time &t, bool t_greater) const +{ + if (points.GetCount() == 0) + return -1; + + if (t_greater) + { + for (uint n = 0; n < points.GetCount(); ++n) + if (points[n]->t > t) + return n; + } + else + { + for (int n = points.GetCount() - 1; n >= 0; --n) + if (points[n]->t <= t) + return n; + } + return -1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +TimeRange Curve::GetTimeRange() const +{ + return points.GetCount() == 0 ? TimeRange() : TimeRange(points[0]->t, points[points.GetCount() - 1]->t); +} +Range Curve::GetValueRange() const +{ + if (points.GetCount() == 0) + return Range (); + + Range range(points[0]->v, points[0]->v); + for (uint n = 1; n < points.GetCount(); ++n) + { + range.start = Types::Min(range.start, points[n]->v); + range.end = Types::Max(range.end, points[n]->v); + } + return range; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Curve::Optimize(uint point_count, const CurvePoint *skf, CurvePoint *dkf, float threshold) +{ + if (point_count < 3) + return 0; + + uint ckf = 0, n; + for (n = 1; n < (point_count - 1); n += 2) + { + float k = (skf[n].t - skf[n - 1].t).toSec() / (skf[n + 1].t - skf[n - 1].t).toSec(); + float iv = (skf[n - 1].v * k) + (skf[n + 1].v * (1.f - k)); + + dkf[ckf++] = skf[n - 1]; + if (fabs(skf[n].v - iv) > threshold) + dkf[ckf++] = skf[n]; + } + if (n == (point_count - 1)) + dkf[ckf++] = skf[point_count - 2]; + dkf[ckf++] = skf[point_count - 1]; + return point_count - ckf; +} +uint Curve::Optimize(float threshold) +{ + if (!points.GetCount()) + return 0; + + Array skf(points.GetCount(), Alloc::Curve), dkf(points.GetCount(), Alloc::Curve); + if (skf.IsNull() || dkf.IsNull()) + __ERR__(__LOG__ << "Not enough memory.\n", 0); + + // Freeze array. + for (uint n = 0; n < points.GetCount(); ++n) + skf[n] = *points[n]; + + // Optimize curve. + uint gain = Optimize(points.GetCount(), skf.c_ptr(), dkf.c_ptr(), threshold), out = points.GetCount() - gain; + + if (gain) + { + // Send back to curve. + if (!AllocatePoint(out)) + __ERR__(__LOG__ << "Failed to reallocate optimized array.\n", 0); + for (uint n = 0; n < points.GetCount(); ++n) + SetPoint(n, dkf[n]); + } + return gain; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Curve::AllocatePoint(uint n) +{ + ArrayListDeleteAllPtr(CurvePoint *, points) + while (n--) + if (!points.Add(new CurvePoint)) + return false; + + return true; +} +void Curve::SetPoint(uint i, const CurvePoint &p) const +{ *points[i] = p; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Curve::Sort() +{ + // Make sure there is work to do. + bool need_sorting = false; + for (uint n = 1; n < points.GetCount(); ++n) + if (points[n - 1]->t > points[n]->t) + { + need_sorting = true; + break; + } + if (!need_sorting) + return; + + // Sort keys. + uint count = points.GetCount(); + + Array ::Entry> entries(count); + for (uint n = 0; n < count; ++n) + { + entries[n].v = points[n]->t; + entries[n].o = points[n]; + } + GS::Sort::QuickSort(count, entries); + + // Drop current array and rewrite ordered one. + points.Clear(false); + for (uint n = 0; n < count; ++n) + points.Add(entries[n].o); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static float range(float v, float lo, float hi, int *i) +{ + float r = hi - lo; + + if (r == 0.f) + { + if (i) + *i = 0; + return lo; + } + + float v2 = v - lo; + if (v2 >= 0.f) + v2 = lo + v2 - r * floor(v2 / r); + else + v2 = hi + v2 - r * ceil(v2 / r); + + if (i) + *i = -(int)((v2 - v) / r + (v2 > v ? 0.5f : -0.5f)); + + return Types::Clamp(v2, lo, hi); +} +static void hermite(float t, float *h1, float *h2, float *h3, float *h4) +{ + float t2 = t * t, t3 = t * t2; + + *h2 = 3.f * t2 - t3 - t3; + *h1 = 1.f - *h2; + *h4 = t3 - t2; + *h3 = *h4 - t2 + t; +} +static float bezier(float x0, float x1, float x2, float x3, float t) +{ + float a, b, c, t2 = t * t, t3 = t * t2; + + c = 3.f * (x1 - x0); + b = 3.f * (x2 - x1) - c; + a = x3 - x0 - c - b; + + return a * t3 + b * t2 + c * t + x0; +} +static float bez2_time(float x0, float x1, float x2, float x3, float time, float *t0, float *t1) +{ + float t = *t0 + (*t1 - *t0) * 0.5f, v = bezier(x0, x1, x2, x3, t); + + if ((fabs(*t1 - *t0) > .0001f) && (fabs(time - v) > .0001f)) + { + if (v > time) + *t1 = t; + else + *t0 = t; + + return bez2_time(x0, x1, x2, x3, time, t0, t1); + } + return t; +} +static float bez2(const CurvePoint *key0, const CurvePoint *key1, float time) +{ + float x, y, t, t0 = 0.f, t1 = 1.f; + + if (key0->shape == CurvePoint::Shape_Bezier2) + x = key0->t.toSec() + key0->param[2]; + else + x = key0->t.toSec() + (key1->t - key0->t).toSec() / 3.f; + + t = bez2_time(key0->t.toSec(), x, key1->t.toSec() + key1->param[0], key1->t.toSec(), time, &t0, &t1); + + if (key0->shape == CurvePoint::Shape_Bezier2) + y = key0->v + key0->param[3]; + else + y = key0->v + key0->param[1] / 3.f; + + return bezier(key0->v, y, key1->param[1] + key1->v, key1->v, t); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Curve::Outgoing(const CurvePoint *key0, const CurvePoint *key1, const CurvePoint *keyp) const +{ + float a, b, d, t, out; + + switch (key1->shape) + { + case CurvePoint::Shape_Linear: + d = key1->v - key0->v; + if (keyp) + { + t = (key1->t - key0->t).toSec() / (key1->t - keyp->t).toSec(); + out = t * ((key0->v - keyp->v) + d); + } + else + out = d; + break; + + case CurvePoint::Shape_TCB: + a = (1 - key0->tension) + * (1 + key0->continuity) + * (1 + key0->bias); + b = (1 - key0->tension) + * (1 - key0->continuity) + * (1 - key0->bias); + d = key1->v - key0->v; + + if (keyp) + { + t = (key1->t - key0->t).toSec() / (key1->t - keyp->t).toSec(); + out = t * (a * (key0->v - keyp->v) + b * d); + } + else + out = b * d; + break; + + case CurvePoint::Shape_Bezier: + case CurvePoint::Shape_Hermite: + out = key0->param[0]; + if (keyp) + out *= (key1->t - key0->t).toSec() / (key1->t - keyp->t).toSec(); + break; + + case CurvePoint::Shape_Bezier2: + out = key0->param[3] * (key1->t - key0->t).toSec(); + if (fabs(key0->param[2]) > 1e-5f) + out /= key0->param[2]; + else + out *= 1e5f; + break; + + case CurvePoint::Shape_Step: + default: + out = 0; + break; + } + return out; +} +float Curve::Incoming(const CurvePoint *key0, const CurvePoint *key1, const CurvePoint *key2) const +{ + float a, b, d, t, in; + + switch (key1->shape) + { + case CurvePoint::Shape_Linear: + d = key1->v - key0->v; + if (key2) + { + t = (key1->t - key0->t).toSec() / (key2->t - key0->t).toSec(); + in = t * ((key2->v - key1->v) + d); + } + else + in = d; + break; + + case CurvePoint::Shape_TCB: + a = (1 - key1->tension) + * (1 - key1->continuity) + * (1 + key1->bias); + b = (1 - key1->tension) + * (1 + key1->continuity) + * (1 - key1->bias); + d = key1->v - key0->v; + + if (key2) + { + t = (key1->t - key0->t).toSec() / (key2->t - key0->t).toSec(); + in = t * (b * (key2->v - key1->v) + a * d); + } + else + in = a * d; + break; + + case CurvePoint::Shape_Bezier: + case CurvePoint::Shape_Hermite: + in = key1->param[0]; + if (key2) + in *= (key1->t - key0->t).toSec() / (key2->t - key0->t).toSec(); + break; + + case CurvePoint::Shape_Bezier2: + in = key1->param[1] * (key1->t - key0->t).toSec(); + if (fabs(key1->param[0]) > 1e-5f) + in /= key1->param[0]; + else in *= 1e5f; + break; + + case CurvePoint::Shape_Step: + default: + in = 0; + break; + } + return in; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Curve::Evaluate(Time t, float *p, LoopMode loop, Time loop_start, Time loop_end) const +{ + int point_count = points.GetCount(); + + if (point_count == 0) + { + *p = 0; + return; + } + if (point_count == 1) + { + *p = points[0]->v; + return; + } + + // Loop mode. + CurvePoint *skey = points[0], *ekey = points[point_count - 1]; + + loop_start = (loop_start == Time::Inf) ? skey->t : Types::Clamp(loop_start, skey->t, ekey->t); + loop_end = (loop_end == Time::Inf) ? ekey->t : Types::Clamp(loop_end, skey->t, ekey->t); + + int noff = 0; + float offset = 0; + if (t < loop_start) + { + switch (loop) + { + case Reset: + *p = 0.f; + return; + + default: + case Constant: + Evaluate(loop_start, p, loop, loop_start, loop_end); + return; + case Repeat: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL)); + break; + case Oscillate: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff)); + if (noff % 2) + t = loop_end + loop_start - t; + break; + case OffsetAndRepeat: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff)); + offset = noff * (ekey->v - skey->v); // Broken on custom loop point. + break; + } + } + else if (t > loop_end) + { + switch (loop) + { + case Reset: + *p = 0.f; + return; + + default: + case Constant: + Evaluate(loop_end, p, loop, loop_start, loop_end); + return; + case Repeat: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL)); + break; + case Oscillate: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff)); + if (noff % 2) + t = loop_end + loop_start - t; + break; + case OffsetAndRepeat: + t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff)); + offset = noff * (ekey->v - skey->v); + break; + } + } + + // Seek to current key. + int ikey0; +#if 1 + { + uint lo = 0, hi = points.GetCount() - 1; + + forever + { + uint mid = (lo + hi) / 2; + + if (points[mid]->t > t) + hi = mid; + else + { + if (lo == mid) + { + ikey0 = lo; + break; + } + else + lo = mid; + } + } + } +#else + ikey0 = 0; + while (((ikey0 + 1) < point_count) && (t > points[ikey0 + 1]->t)) + ikey0++; +#endif + + CurvePoint *pkey0 = points[ikey0]; + + if (pkey0 == NULL) + return; + + // Sample curve. + CurvePoint *pkeyp = ikey0 > 0 ? points[ikey0 - 1] : NULL; + + int ikey1 = ikey0 + 1; + CurvePoint *pkey1 = points[ikey1], *pkey2 = ikey1 < (point_count - 1) ? points[ikey1 + 1] : NULL; + + if (t == pkey0->t) + *p = pkey0->v + offset; + + else if (t == pkey1->t) + *p = pkey1->v + offset; + + else + { + const float k_t = (t - pkey0->t).toSec() / (pkey1->t - pkey0->t).toSec(); + + switch (pkey0->shape) + { + case CurvePoint::Shape_TCB: + case CurvePoint::Shape_Bezier: + case CurvePoint::Shape_Hermite: + { + float out = Outgoing(pkey0, pkey1, pkeyp), in = Incoming(pkey0, pkey1, pkey2); + + float h1, h2, h3, h4; + hermite(k_t, &h1, &h2, &h3, &h4); + *p = h1 * pkey0->v + h2 * pkey1->v + h3 * out + h4 * in + offset; + } + break; + + case CurvePoint::Shape_Bezier2: + *p = bez2(pkey0, pkey1, k_t) + offset; + break; + + case CurvePoint::Shape_Linear: + *p = pkey0->v + k_t * (pkey1->v - pkey0->v) + offset; + break; + + case CurvePoint::Shape_Step: + *p = pkey0->v + offset; + break; + + default: + *p = offset; + break; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Curve::Clear() +{ + ArrayListDeleteAllPtr(CurvePoint *, points) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Curve::~Curve() +{ Clear(); } +//------------------------------------------------------------------------------ diff --git a/include/framework/geometry/curve_nml.cpp b/include/framework/geometry/curve_nml.cpp new file mode 100644 index 0000000..a03c894 --- /dev/null +++ b/include/framework/geometry/curve_nml.cpp @@ -0,0 +1,268 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "geometry/curve.h" + #include "math/nmath.h" + #include "sort/sort.h" + #include "alloc/ialloc.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +Reflection::Enum::Dict Curve::loop_mode_dict[] = +{ + { Curve::Reset, "Reset" }, + { Curve::Constant, "Constant" }, + { Curve::Repeat, "Repeat" }, + { Curve::Oscillate, "Oscillate" }, + { Curve::OffsetAndRepeat, "OffsetAndRepeat" }, + { 0, 0 } +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// ARM odd address read/write helper functions. +void ARM_unaligned_read(float &out, const char *addr) +{ + char *p_out = (char *)&out; + for (int n = 0; n < sizeof(float); ++n) + p_out[n] = addr[n]; +} +void ARM_unaligned_write(char *addr, const float &in) +{ + const char *p_in = (const char *)∈ + for (int n = 0; n < sizeof(float); ++n) + addr[n] = p_in[n]; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Curve::FromMetaTag(Tag &tag) +{ + if (tag.name != "Curve") + __ERR__(__LOG_E__ << "Could not parse curve, incorrect root tag (" << tag.name << ").\n", false) + + Clear(); + + // Parse root tags. + NMLTagForeach(pt, tag) + { + if (pt->name == "BinaryKnot") + { + Tag *count_tag = pt->GetTag("Count"), *data_tag = pt->GetTag("Data"); + + if (count_tag && data_tag) + { + char *data = (char *)data_tag->GetValue().GetBinaryBuffer(), *p_data = data; + + if (data && AllocatePoint(count_tag->GetInteger())) + for (uint n = 0; n < points.GetCount(); ++n) + { + CurvePoint *p = points[n]; + + p->shape = CurvePoint::Shape(*p_data++); + + float t; + ARM_unaligned_read(t, p_data + 0); + p->t.setSec(t); + ARM_unaligned_read(p->v, p_data + 4); + + if (p->shape == CurvePoint::Shape_Linear) + p_data += 2 * 4; + + else + { + ARM_unaligned_read(p->tension, p_data + 8); + ARM_unaligned_read(p->continuity, p_data + 12); + ARM_unaligned_read(p->bias, p_data + 16); + + for (int n = 0; n < 4; ++n) + ARM_unaligned_read(p->param[n], p_data + 20 + n * 4); + + p_data += 9 * 4; + } + } + } + } + else if (pt->name == "Knot") + { + Tag *st = pt->GetTags()[0]; + if (!st || (st->name != "Count")) + __ERR__(__LOG_E__ << "First sub-tag in must be the knot tag.\n", false) + + if (!AllocatePoint((uint)st->GetInteger())) + return false; + + static String _count("Count"), _knot("Knot"), _knotex("KnotEx"); + + uint n = 0; + NMLTagForeach(st, *pt) + { + if (st->name == _count) + {} + + // Legacy knot definition. + if (st->name == _knot) + { + if (n == points.GetCount()) + { + __LOG_E__ << "Too many knot in , " << points.GetCount() << " expected.\n"; + break; + } + + if (const char *p = st->GetString()) + { + points[n]->t = Time::fromSec(String::atof(p)); + points[n]->shape = CurvePoint::Shape_Linear; + + p = String::strfindchar(p, ':'); + points[n]->v = p[0] ? String::atof(p + 1) : 0; + + n++; + } + else + __LOG_W__ << "Invalid knot tag while parsing curve.\n"; + } + + /* + Extended knot definition. + */ + else if (st->name == _knotex) + { + if (n == points.GetCount()) + { + __LOG_E__ << "Too many knot in , " << points.GetCount() << " specified.\n"; + break; + } + + if (const char *p = st->GetString()) + { + CurvePoint *_knot = points[n]; + _knot->t = Time::fromSec(String::atof(p)); + + // Read shape. + p = String::strfindchar(p, ':'); + int shape = p[0] ? String::atoi(p + 1) : 0; + p++; + + switch (shape) + { + default: + case 0: _knot->shape = CurvePoint::Shape_None; break; + case 1: _knot->shape = CurvePoint::Shape_Linear; break; + case 2: _knot->shape = CurvePoint::Shape_Bezier; break; + case 3: _knot->shape = CurvePoint::Shape_Bezier2; break; + case 4: _knot->shape = CurvePoint::Shape_Hermite; break; + case 5: _knot->shape = CurvePoint::Shape_TCB; break; + case 6: _knot->shape = CurvePoint::Shape_Step; break; + } + + // Read knot parameters. + //-------------------------------------------- + #define GetInputKnotParamEx(_PARM_)\ + {\ + p = String::strfindchar(p, ':');\ + (_PARM_) = p[0] ? String::atof(p + 1) : -1;\ + p++;\ + } + //-------------------------------------------- + + GetInputKnotParamEx(_knot->v); + GetInputKnotParamEx(_knot->tension); + GetInputKnotParamEx(_knot->continuity); + GetInputKnotParamEx(_knot->bias); + + GetInputKnotParamEx(_knot->param[0]); + GetInputKnotParamEx(_knot->param[1]); + GetInputKnotParamEx(_knot->param[2]); + GetInputKnotParamEx(_knot->param[3]); + n++; + } + else + __LOG_W__ << "Invalid extended knot tag while parsing curve.\n"; + } + else + __LOG_W__ << "Unsupported knot tag '" << st->name << "'.\n"; + } + + // Incomplete/erroneous definition. + if (n != points.GetCount()) + { + Clear(); + __ERR__(__LOG_E__ << " is corrupted, discarding.\n", false) + } + } + else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Curve::AsMetaTag() const +{ + Tag *root = new Tag("Curve"); + if (!root) + __ERR__(__LOG_E__ << "Could not create curve root tag to serialize.\n", NULL) + + // Binary knots. + if (points.GetCount()) + if (Tag *binary_knot_tag = root->AddChild("BinaryKnot")) + { + binary_knot_tag->AddChild("Count", points.GetCount()); + + // Get size. + int size = 0; + for (uint n = 0; n < points.GetCount(); ++n) + { + CurvePoint *_knot = points[n]; + + // Legacy definition. + if (_knot->shape == CurvePoint::Shape_Linear) + size += 2 * 4; // Knot size. + else size += 9 * 4; // Extended knot size. + } + + // Output binary. + Array knot_array(points.GetCount() + size); + char *p_knot = knot_array; + + for (uint n = 0; n < points.GetCount(); ++n) + { + CurvePoint *_knot = points[n]; + + *p_knot++ = uchar(_knot->shape); + + float t = _knot->t.toSec(); + ARM_unaligned_write(p_knot + 0, t); + ARM_unaligned_write(p_knot + 4, _knot->v); + + if (_knot->shape == CurvePoint::Shape_Linear) + p_knot += 2 * 4; + + else + { + ARM_unaligned_write(p_knot + 8, _knot->tension); + ARM_unaligned_write(p_knot + 12, _knot->continuity); + ARM_unaligned_write(p_knot + 16, _knot->bias); + + for (int n = 0; n < 4; ++n) + ARM_unaligned_write(p_knot + 20 + n * 4, _knot->param[n]); + + p_knot += 9 * 4; + } + } + + binary_knot_tag->AddChild("Data", knot_array, points.GetCount() + size); + } + + return root; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/geometry/frustum.cpp b/include/framework/geometry/frustum.cpp new file mode 100644 index 0000000..e4682c6 --- /dev/null +++ b/include/framework/geometry/frustum.cpp @@ -0,0 +1,309 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "geometry/frustum.h" + #include "geometry/bounding_box.h" + #include "geometry/sat.h" + #include "shape/shape.h" + #include "math/matrix4.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Frustum::SetPerspective(float fov, float znear, float zfar, const Matrix4 *matrix, float h_ar, float v_ar) +{ + fov *= 0.5f; + const float hyp = tan(fov); + const float hfov = atan(hyp / h_ar), vfov = atan(hyp / v_ar); + + Vector4 n; + + const float sinv = sin(vfov); + const float cosv = cos(vfov); + n.Set(0, cosv, -sinv); + plane[Top].Set(NULL, n, matrix); + n.Set(0, -cosv, -sinv); + plane[Bottom].Set(NULL, n, matrix); + + const float sinh = sin(hfov); + const float cosh = cos(hfov); + n.Set(-cosh, 0, -sinh); + plane[Left].Set(NULL, n, matrix); + n.Set(cosh, 0, -sinh); + plane[Right].Set(NULL, n, matrix); + + Vector4 s; + s.Set(0, 0, znear); + n.Set(0, 0, -1); + plane[Near].Set(&s, n, matrix); + s.Set(0, 0, zfar); + n.Set(0, 0, 1); + plane[Far].Set(&s, n, matrix); + + // Model vertices. + Vector4 bvtx[8]; + Vector4 *_vtx = matrix ? bvtx : vtx; + + // Compute near plane corners. + float k = znear / -cosv; + _vtx[0].y = -sinv * k; + _vtx[0].z = znear;//-cosv * k; + k = znear / cosh; + _vtx[0].x = -sinh * k; + _vtx[0].w = 1; + + _vtx[1].Set(-_vtx[0].x, _vtx[0].y, _vtx[0].z); + _vtx[2].Set(-_vtx[0].x, -_vtx[0].y, _vtx[0].z); + _vtx[3].Set(_vtx[0].x, -_vtx[0].y, _vtx[0].z); + + // Compute far plane corners. + k = zfar / -cosv; + _vtx[4].y = -sinv * k; + _vtx[4].z = zfar;//-cosv * k; + k = zfar / cosh; + _vtx[4].x = -sinh * k; + _vtx[4].w = 1; + + _vtx[5].Set(-_vtx[4].x, _vtx[4].y, _vtx[4].z); + _vtx[6].Set(-_vtx[4].x, -_vtx[4].y, _vtx[4].z); + _vtx[7].Set(_vtx[4].x, -_vtx[4].y, _vtx[4].z); + + if (matrix) + matrix->Apply(vtx, bvtx, 8); +} +void Frustum::SetOrthographic(float width, float height, float znear, float zfar, const Matrix4 *matrix, float h_ar, float v_ar) +{ + Vector4 s, n; + + width *= h_ar; + height *= v_ar; + + s.Set(0, height * 0.5f, 0); + n.Set(0, 1, 0); + plane[Top].Set(&s, n, matrix); + s.Set(0, -height * 0.5f, 0); + n.Set(0, -1, 0); + plane[Bottom].Set(&s, n, matrix); + s.Set(-width * 0.5f, 0, 0); + n.Set(-1, 0, 0); + plane[Left].Set(&s, n, matrix); + s.Set(width * 0.5f, 0, 0); + n.Set(1, 0, 0); + plane[Right].Set(&s, n, matrix); + s.Set(0, 0, znear); + n.Set(0, 0, -1); + plane[Near].Set(&s, n, matrix); + s.Set(0, 0, zfar); + n.Set(0, 0, 1); + plane[Far].Set(&s, n, matrix); + + // Model vertices. + Vector4 bvtx[8]; + Vector4 *_vtx = matrix ? bvtx : vtx; + + // Compute near plane corners. + _vtx[0].Set(-width * 0.5f, height * 0.5f, znear); + _vtx[1].Set( width * 0.5f, height * 0.5f, znear); + _vtx[2].Set( width * 0.5f, -height * 0.5f, znear); + _vtx[3].Set(-width * 0.5f, -height * 0.5f, znear); + _vtx[4].Set(-width * 0.5f, height * 0.5f, zfar); + _vtx[5].Set( width * 0.5f, height * 0.5f, zfar); + _vtx[6].Set( width * 0.5f, -height * 0.5f, zfar); + _vtx[7].Set(-width * 0.5f, -height * 0.5f, zfar); + + if (matrix) + matrix->Apply(vtx, bvtx, 8); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Frustum::Visibility Frustum::ClassifyShape(const Shape &s, const Matrix4 *m) const +{ + Visibility v = Inside; + + Matrix3 rm; + if (m) + rm = Matrix3::FromMatrix4(*m).Transposed(); + + for (uint n = 0; n < 6; ++n) + { + float d, r; + + if (m) + { + d = plane[n].DistanceToPlane(s.GetCenter() * m[0]); + r = s.GetSupportDistance(plane[n].GetNormal() * rm); + } + else + { + d = plane[n].DistanceToPlane(s.GetCenter()); + r = s.GetSupportDistance(plane[n].GetNormal()); + } + + if (d > r) + return Outside; + if (d > -r) + v = Clipped; + } + return v; +} +Frustum::Visibility Frustum::ClassifySphere(const Vector4 &p, float r) const +{ + Visibility v = Inside; + for (uint n = 0; n < 6; ++n) + { + if (plane[n].DistanceToPlane(p) > r) + return Outside; + if (plane[n].DistanceToPlane(p) > -r) + v = Clipped; + } + return v; +} +Frustum::Visibility Frustum::ClassifySet(uint count, const Vector4 * const GSRESTRICT set, const float offset) const +{ + Visibility v = Inside; + for (uint n = 0; n < 6; ++n) + { + uint out = 0; + for (uint i = 0; i < count; ++i) + if (plane[n].DistanceToPlane(set[i]) > offset) + ++out; + + if (out == count) + return Outside; + if (out > 0) + v = Clipped; + } + return v; +} +//------------------------------------------------------------------------------ + +#if (__PLATFORM_NINTENDO_WII__ == 0) +//#define FRUSTUM_TEST_USE_SAT +#endif + +//-------------------------------------------- +#define SAT_TEST(_N_, _U_, _A_, _V_, _B_)\ +{\ + SAT::Overlap _v = SAT::TestOverlap(_N_, _U_, _A_, _V_, _B_);\ + if (_v == SAT::Outside)\ + return Outside;\ + if (_v == SAT::Clipped)\ + v = Clipped;\ +} +//-------------------------------------------- + +//------------------------------------------------------------------------------ +Frustum::Visibility Frustum::ClassifyMinMax(const MinMax &mm, const Matrix4 *matrix) const +{ + // TODO Please, use AABB half width and implicit interval projection... will you? + Vector4 s[8], d[8], *p; + + s[0].Set(mm.mn.x, mm.mn.y, mm.mn.z); + s[1].Set(mm.mx.x, mm.mn.y, mm.mn.z); + s[2].Set(mm.mx.x, mm.mx.y, mm.mn.z); + s[3].Set(mm.mn.x, mm.mx.y, mm.mn.z); + s[4].Set(mm.mn.x, mm.mn.y, mm.mx.z); + s[5].Set(mm.mx.x, mm.mn.y, mm.mx.z); + s[6].Set(mm.mx.x, mm.mx.y, mm.mx.z); + s[7].Set(mm.mn.x, mm.mx.y, mm.mx.z); + + if (matrix) + { + matrix->Apply(d, s, 8); + p = d; + } + else + p = s; + +#ifndef FRUSTUM_TEST_USE_SAT + // Faster but much coarser test. + return ClassifySet(8, p); +#else + // Frustum/AABB SAT. + Visibility v = Inside; + + // Test face/{face/edge} contact. + SAT_TEST(plane[Top].GetNormal(), 8, vtx, 8, p); + SAT_TEST(plane[Bottom].GetNormal(), 8, vtx, 8, p); + SAT_TEST(plane[Left].GetNormal(), 8, vtx, 8, p); + SAT_TEST(plane[Right].GetNormal(), 8, vtx, 8, p); + SAT_TEST(plane[Near].GetNormal(), 8, vtx, 8, p); + SAT_TEST(plane[Far].GetNormal(), 8, vtx, 8, p); + + Vector4 _edge[3]; + + _edge[0] = matrix ? matrix->GetRow(0) : Vector4(1, 0, 0); + SAT_TEST(_edge[0], 8, vtx, 8, p); + _edge[1] = matrix ? matrix->GetRow(1) : Vector4(0, 1, 0); + SAT_TEST(_edge[1], 8, vtx, 8, p); + _edge[2] = matrix ? matrix->GetRow(2) : Vector4(0, 0, 1); + SAT_TEST(_edge[2], 8, vtx, 8, p); + + // Test edge/edge contact. + Vector4 edge[6]; + for (uint n = 0; n < 4; ++n) + edge[n] = vtx[n + 4] - vtx[n]; + edge[4] = vtx[1] - vtx[0]; + edge[5] = vtx[3] - vtx[0]; + + for (uint n = 0; n < 6; ++n) + for (uint m = 0; m < 3; ++m) + { + Vector4 axis = edge[n].Cross(_edge[m]); + if (Math::EqualZero(axis.Len2())) + continue; + SAT_TEST(axis, 8, vtx, 8, p); + } + return v; +#endif +} +Frustum::Visibility Frustum::ClassifyFrustrum(const Frustum &frustum) const +{ +#ifndef FRUSTUM_TEST_USE_SAT + // Faster but much coarser test. + return ClassifySet(8, frustum.vtx); +#else + // Frustum/frustum SAT. + Visibility v = Inside; + + // Test face/{face/edge} contact. + SAT_TEST(plane[Top].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(plane[Bottom].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(plane[Left].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(plane[Right].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(plane[Far].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(frustum.plane[Top].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(frustum.plane[Bottom].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(frustum.plane[Left].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(frustum.plane[Right].GetNormal(), 8, vtx, 8, frustum.vtx); + SAT_TEST(frustum.plane[Far].GetNormal(), 8, vtx, 8, frustum.vtx); + + // Test edge/edge contact. + Vector4 edge[6], _edge[6]; + for (uint n = 0; n < 4; ++n) + { + edge[n] = vtx[n + 4] - vtx[n]; + _edge[n] = frustum.vtx[n + 4] - frustum.vtx[n]; + } + edge[4] = vtx[1] - vtx[0]; + edge[5] = vtx[3] - vtx[0]; + _edge[4] = frustum.vtx[1] - frustum.vtx[0]; + _edge[5] = frustum.vtx[3] - frustum.vtx[0]; + + for (uint n = 0; n < 6; ++n) + for (uint m = 0; m < 6; ++m) + { + Vector4 axis = edge[n].Cross(_edge[m]); + if (!Math::EqualZero(axis.Len2())) + SAT_TEST(axis, 8, vtx, 8, frustum.vtx); + } + return v; +#endif +} +//------------------------------------------------------------------------------ diff --git a/include/framework/geometry/geometric_tools.cpp b/include/framework/geometry/geometric_tools.cpp new file mode 100644 index 0000000..3e5fb9e --- /dev/null +++ b/include/framework/geometry/geometric_tools.cpp @@ -0,0 +1,122 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "geometry/geometric_tools.h" + + +namespace GS { + namespace Geometric { + +//------------------------------------------------------------------------------ +float TriArea2D(float x0, float y0, float x1, float y1, float x2, float y2) +{ return (x0 - x1) * (y1 - y2) - (x1 - x2) * (y0 - y1); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Barycentric(const Vector4 &a, const Vector4 &b, const Vector4 &c, const Vector4 &p, float &u, float &v, float &w) +{ + Vector4 m = (b - a).Cross(c - a); + + float nu, nv, ood; + float x = fabs(m.x), y = fabs(m.y), z = fabs(m.z); + + if (x >= y && x >= z) + { + nu = TriArea2D(p.y, p.z, b.y, b.z, c.y, c.z); + nv = TriArea2D(p.y, p.z, c.y, c.z, a.y, a.z); + ood = 1.f / m.x; + } + else if (y >= x && y >= z) + { + nu = TriArea2D(p.x, p.z, b.x, b.z, c.x, c.z); + nv = TriArea2D(p.x, p.z, c.x, c.z, a.x, a.z); + ood = 1.f / -m.y; + } + else + { + nu = TriArea2D(p.x, p.y, b.x, b.y, c.x, c.y); + nv = TriArea2D(p.x, p.y, c.x, c.y, a.x, a.y); + ood = 1.f / m.z; + } + u = nu * ood; + v = nv * ood; + w = 1.f - u - v; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool LineIntersectPlane(const Vector4 &a, const Vector4 &v, const Vector4 &n, const Vector4 &p, float &t) +{ + float k = v.Dot(n); + if (Math::EqualZero(k)) + return false; + t = (p.Dot(n) - a.Dot(n)) / k; + return true; +} +bool LineIntersectSphere(const Vector4 &a, const Vector4 &v, const Vector4 &c, float r, float t[2]) +{ + Vector4 e = c - a; + + float k = e.Dot(v); + float d = r * r - (e.Len2() - k * k); + if (d < 0) + return false; + + d = Math::Sqrt(d); + + if (t) + { + t[0] = k - d; + t[1] = k + d; + } + return true; +} +float LineClosestPoint(const Vector4 &a, const Vector4 &b, const Vector4 &u, Vector4 *p) +{ + Vector4 _u = u - a; + Vector4 _v = b - a; + + float t = _u.Dot(_v) / _v.Dot(_v); + + if (p) + p[0] = _v * t + a; + + return t; +} +bool LineClosestPointToLine(const Vector4 &a, const Vector4 &b, const Vector4 &la, const Vector4 &lb, float t[2]) +{ + Vector4 u = b - a, v = lb - la; + float ul2 = u.Len2(), vl2 = v.Len2(); + + float d = u.Dot(v), k = ul2 * vl2 - d * d; + + if (fabs(k) < 0.00000001f) + return false; + + k = 1.f / k; + float uv = d, du = (la - a).Dot(u), dv = (a - la).Dot(v); + + t[0] = (vl2 * du + uv * dv) * k; + t[1] = (uv * du + ul2 * dv) * k; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float SegmentClosestPoint(const Vector4 &a, const Vector4 &b, const Vector4 &u, Vector4 *p) +{ + Vector4 _u = u - a, _v = b - a; + float t = Types::Clamp(_u.Dot(_v) / _v.Dot(_v)); + + if (p) + p[0] = _v * t + a; + return t; +} +//------------------------------------------------------------------------------ + + } // Geometric +} // GS diff --git a/include/framework/geometry/plane.cpp b/include/framework/geometry/plane.cpp new file mode 100644 index 0000000..a2444f1 --- /dev/null +++ b/include/framework/geometry/plane.cpp @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "geometry/plane.h" + #include "math/matrix4.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Plane::Set(const Vector4 *_p, const Vector4 &_n, const Matrix4 *mtx) +{ + if (mtx) + { + if (_p) + mtx->Apply(&p, _p); + else p = mtx->GetRow(3); + mtx->ApplyRotation(&n, &_n); + } + else + { + if (_p) + p = *_p; + else p.Set(0, 0, 0, 1); + n = _n; + } + d = -p.Dot(n); +} +void Plane::Set(const Vector4 _p[3], const Matrix4 *mtx) +{ + Vector4 _n = (_p[1] - _p[0]).Cross(_p[2] - _p[0]); + Set(&_p[0], _n, mtx); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Plane::Plane() +{ + d = 0; + p.Set(); + n.Set(); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/geometry/rect.cpp b/include/framework/geometry/rect.cpp new file mode 100644 index 0000000..ea70c6b --- /dev/null +++ b/include/framework/geometry/rect.cpp @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "geometry/rect.h" + #include "metafile/nml.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +template NML::Tag *Rect::AsMetaTag(const char *id) const +{ + NML::Tag *root = new NML::Tag(id ? id : "Rect"); + + if (root) + { + root->AddChild("SX", sx); + root->AddChild("SY", sy); + root->AddChild("EX", ex); + root->AddChild("EY", ey); + } + return root; +} +template bool Rect::FromMetaTag(NML::Tag &tag) +{ + NML::Tag *t; + List ::Iterator i(tag.GetTags().GetRoot()); + + t = i.ObjectPtr(); + if (!t) return false; + sx = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + sy = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + ex = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + ey = t->GetReal(); + ++i; + + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/math/matrix3.cpp b/include/framework/math/matrix3.cpp new file mode 100644 index 0000000..da1d73d --- /dev/null +++ b/include/framework/math/matrix3.cpp @@ -0,0 +1,319 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "math/matrix3.h" + #include "math/matrix4.h" + #include "metafile/nml.h" + + using namespace GS; + using namespace GS::Math; + + Matrix3 Matrix3::static_identity; + + +//------------------------------------------------------------------------------ +bool Matrix3::Inverse(Matrix3 &i) const +{ + // Covariants. + i.m[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1]; + i.m[0][1] = m[0][2] * m[2][1] - m[0][1] * m[2][2]; + i.m[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1]; + i.m[1][0] = m[1][2] * m[2][0] - m[1][0] * m[2][2]; + i.m[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0]; + i.m[1][2] = m[0][2] * m[1][0] - m[0][0] * m[1][2]; + i.m[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0]; + i.m[2][1] = m[0][1] * m[2][0] - m[0][0] * m[2][1]; + i.m[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0]; + + float k = m[0][0] * i.m[0][0] + m[0][1] * i.m[1][0] + m[0][2] * i.m[2][0]; + if (!k) + return false; + + k = 1.f / k; + i.m[0][0] *= k; i.m[0][1] *= k; i.m[0][2] *= k; + i.m[1][0] *= k; i.m[1][1] *= k; i.m[1][2] *= k; + i.m[2][0] *= k; i.m[2][1] *= k; i.m[2][2] *= k; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix3 Matrix3::VectorMatrix(const Vector4 &v) +{ return Matrix3(v.x, 0, 0, v.y, 0, 0, v.z, 0, 0); } +Matrix3 Matrix3::CrossProductMatrix(const Vector4 &v) +{ return Matrix3(0, -v.z, v.y, v.z, 0, -v.x, -v.y, v.x, 0); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix3 Matrix3::Normalized() const +{ + Vector4 x(GetRow(0)), y(GetRow(1)), z(GetRow(2)); + + Matrix3 m; + m.SetRow(0, x.Normalized()); + m.SetRow(1, y.Normalized()); + m.SetRow(2, z.Normalized()); + return m; +} +Matrix3 Matrix3::AsOrthonormalBase() const +{ + Vector4 x(GetRow(0)), y(GetRow(1)); + + Matrix3 m; + x = x.Normalized(); + m.SetRow(0, x); + Vector4 z(x.Cross(y).Normalized()); + m.SetRow(2, z); + y = z.Cross(x).Normalized(); + m.SetRow(1, y); + return m; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector4 Matrix3::AsEuler(rOrder rorder) const +{ + Vector4 euler(0, 0, 0); + + switch (rorder) + { + case rOrder_ZYX: + euler.y = ASin(-m[2][0]); + euler.z = atan2(m[1][0], m[0][0]); + euler.x = atan2(m[2][1], m[2][2]); + break; + + case rOrder_XZY: + euler.z = ASin(-m[0][1]); + euler.x = atan2(m[2][1], m[1][1]); + euler.y = atan2(m[0][2], m[0][0]); + break; + + case rOrder_XYZ: + euler.y = ASin(m[0][2]); + euler.x = atan2(-m[1][2], m[2][2]); + euler.z = atan2(-m[0][1], m[0][0]); + break; + + case rOrder_YZX: + euler.z = ASin(m[1][0]); + euler.x = atan2(-m[1][2], m[1][1]); + euler.y = atan2(-m[2][0], m[0][0]); + break; + + default: + case rOrder_YXZ: // Engine default. + euler.x = ASin(-m[1][2]); + euler.y = atan2(m[0][2], m[2][2]); + euler.z = atan2(m[1][0], m[1][1]); + break; + + case rOrder_ZXY: // MAX default. + euler.x = ASin(m[2][1]); + euler.y = atan2(-m[2][0], m[2][2]); + euler.z = atan2(-m[0][1], m[1][1]); + break; + + case rOrder_XY: + euler.y = ACos(m[0][0]); + euler.x = ACos(m[1][1]); + euler.z = 0; + break; + } + return euler; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix3 Matrix3::FromEuler(const Vector4 &euler, rOrder rorder) +{ return Matrix3::FromEuler(euler.x, euler.y, euler.z, rorder); } +Matrix3 Matrix3::FromEuler(float x, float y, float z, rOrder rorder) +{ + float cx = Cos(x), cy = Cos(y), cz = Cos(z), + sx = Sin(x), sy = Sin(y), sz = Sin(z); + + switch (rorder) + { + case rOrder_XZY: + return Matrix3 ( cy * cz, sx * sy + cx * cy * sz, -cx * sy + cy * sx * sz, + -sz, cx * cz, cz * sx, + cz * sy, -cy * sx + cx * sy * sz, cx * cy + sx * sy * sz ); + + case rOrder_ZYX: + return Matrix3 ( cy * cz, cy * sz, -sy, + cz * sx * sy - cx * sz, cx * cz + sx * sy * sz, cy * sx, + cx *cz * sy + sx * sz, -cz * sx + cx * sy * sz, cx * cy ); + + case rOrder_XYZ: + return Matrix3 ( cy * cz, cz * sx * sy + cx * sz, -cx * cz * sy + sx * sz, + -cy * sz, cx * cz - sx * sy * sz, cz * sx + cx * sy * sz, + sy, -cy * sx, cx * cy ); + + case rOrder_ZXY: + return Matrix3 ( cy * cz - sx * sy * sz, cz * sx * sy + cy * sz, -cx * sy, + -cx * sz, cx * cz, sx, + cz * sy + cy * sx * sz, -cy * cz * sx + sy * sz, cx * cy ); + + case rOrder_YZX: + return Matrix3 ( cy * cz, sz, -cz * sy, + sx * sy - cx * cy * sz, cx * cz, cy * sx + cx * sy * sz, + cx * sy + cy * sx * sz, -cz * sx, cx * cy - sx * sy * sz ); + + case rOrder_YXZ: + return Matrix3 ( cy * cz + sx * sy * sz, cx * sz, -cz * sy + cy * sx * sz, + cz * sx * sy - cy * sz, cx * cz, cy * cz * sx + sy * sz, + cx * sy, -sx, cx * cy ); + + case rOrder_XY: + return Matrix3 ( cy, sx * sy, -cx * sy, + 0, cx, sx, + sy, -cy * sx, cx * cy ); + } + return Matrix3::IdentityMatrix(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix3 Matrix3::TranslationMatrix(const Vector4 &t) +{ return Matrix3(1, 0, 0, 0, 1, 0, t.x, t.y, 1); } +Matrix3 Matrix3::TranslationMatrix(const Vector2 &t) +{ return Matrix3(1, 0, 0, 0, 1, 0, t.x, t.y, 1); } +Matrix3 Matrix3::ScaleMatrix(const Vector4 &s) +{ return Matrix3(s.x, 0, 0, 0, s.y, 0, 0, 0, s.z); } +Matrix3 Matrix3::ScaleMatrix(const Vector2 &s) +{ return Matrix3(s.x, 0, 0, 0, s.y, 0, 0, 0, 1); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix3 Matrix3::RotationMatrixXAxis(float a) +{ return Matrix3(1, 0, 0, 0, Cos(a), Sin(a), 0, -Sin(a), Cos(a)); } +Matrix3 Matrix3::RotationMatrixYAxis(float a) +{ return Matrix3(Cos(a), 0, -Sin(a), 0, 1, 0, Sin(a), 0, Cos(a)); } +Matrix3 Matrix3::RotationMatrixZAxis(float a) +{ return Matrix3(Cos(a), Sin(a), 0, -Sin(a), Cos(a), 0, 0, 0, 1); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Matrix3::SetRow(uint n, const Vector4 &row) +{ m[0][n] = row.x; m[1][n] = row.y; m[2][n] = row.z; } +void Matrix3::SetColumn(uint n, const Vector4 &col) +{ m[n][0] = col.x; m[n][1] = col.y; m[n][2] = col.z; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix3 Matrix3::FromOrthonormalBasis(const Vector4 &w, const Vector4 *v) +{ + Matrix3 mtx; + + float l = w.Len(); + if (!l) + return Matrix3::IdentityMatrix(); + + Vector4 wn = w / l, u; + + if (!v) + { + if (!EqualZero(wn.x) || !EqualZero(wn.z)) + { + u.Set(wn.z, 0, -wn.x); // Cross with up = {0,1,0}. + u = u.Normalized(); + } + else + u.Set(-1, 0, 0); + + Vector4 c(wn.Cross(u)); + mtx.SetRow(1, c); + } + else + { + Vector4 vn(v->Normalized()); + mtx.SetRow(1, vn); + u = vn.Cross(wn); + } + + mtx.SetRow(0, u); + mtx.SetRow(2, wn); + return mtx; +} +Matrix3 Matrix3::FromMatrix4(const Matrix4 &mtx) +{ + return Matrix3( + mtx.m[0][0], mtx.m[1][0], mtx.m[2][0], + mtx.m[0][1], mtx.m[1][1], mtx.m[2][1], + mtx.m[0][2], mtx.m[1][2], mtx.m[2][2] + ); +} +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------- +void Matrix3::Apply(Vector4 *o, const Vector4 *v, uint n) const +//----------------------------------------------------------------------------- +{ + for (uint c = 0; c < n; c++) + { + float x = v->x, y = v->y, z = v->z; + o->x = x * m[0][0] + y * m[0][1] + z * m[0][2]; + o->y = x * m[1][0] + y * m[1][1] + z * m[1][2]; + o->z = x * m[2][0] + y * m[2][1] + z * m[2][2]; + o->w = 1; + o++; v++; + } +} + +//------------------------------------------------------------------------------ +void Matrix3::Set + ( + float m00, float m10, float m20, + float m01, float m11, float m21, + float m02, float m12, float m22 + ) +{ + m[0][0] = m00; m[1][0] = m10; m[2][0] = m20; + m[0][1] = m01; m[1][1] = m11; m[2][1] = m21; + m[0][2] = m02; m[1][2] = m12; m[2][2] = m22; +} +void Matrix3::Set(const Vector4 &u, const Vector4 &v, const Vector4 &w) +{ + m[0][0] = u.x; m[1][0] = u.y; m[2][0] = u.z; + m[0][1] = v.x; m[1][1] = v.y; m[2][1] = v.z; + m[0][2] = w.x; m[1][2] = w.y; m[2][2] = w.z; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NML::Tag *Matrix3::AsMetaTag(const char *id) const +{ + NML::Tag *root = new NML::Tag(id ? id : "Mtx3"); + root->AddChild(GetRow(0).AsMetaTag("R0")); + root->AddChild(GetRow(1).AsMetaTag("R1")); + root->AddChild(GetRow(2).AsMetaTag("R2")); + return root; +} +bool Matrix3::FromMetaTag(NML::Tag &tag) +{ + NML::Tag *t; + Vector4 R; + + List ::Iterator i(tag.GetTags().GetRoot()); + + t = i.ObjectPtr(); + if (!t) return false; + R.FromMetaTag(*t); SetRow(0, R); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + R.FromMetaTag(*t); SetRow(1, R); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + R.FromMetaTag(*t); SetRow(2, R); + + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/math/matrix4.cpp b/include/framework/math/matrix4.cpp new file mode 100644 index 0000000..900369e --- /dev/null +++ b/include/framework/math/matrix4.cpp @@ -0,0 +1,277 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "math/matrix4.h" + #include "math/matrix3.h" + #include "math/quaternion.h" + #include "metafile/nml.h" + + using namespace GS; + + Matrix4 Matrix4::static_identity(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + + +//------------------------------------------------------------------------------ +Matrix4 Matrix4::FromMatrix3(const Matrix3 &m) +{ + return Matrix4( + m.m[0][0], m.m[1][0], m.m[2][0], 0, + m.m[0][1], m.m[1][1], m.m[2][1], 0, + m.m[0][2], m.m[1][2], m.m[2][2], 0, + 0, 0, 0, 1 + ); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +const Matrix4 &Matrix4WithInverse::Get() const +{ return matrix; } +const Matrix4 &Matrix4WithInverse::GetInverse() const +{ return imatrix; } +void Matrix4WithInverse::Commit() +{ imatrix = matrix.InversedFast(); } +void Matrix4WithInverse::Set(const Matrix4 &m) +{ + matrix = m; + Commit(); +} +Vector4 Matrix4WithInverse::GetRow(uint n, bool w_1) const +{ return matrix.GetRow(n, w_1); } +Vector4 Matrix4WithInverse::GetColumn(uint n, bool w_1) const +{ return matrix.GetColumn(n, w_1); } +void Matrix4WithInverse::SetRow(uint n, const Vector4 &row, bool w_1) +{ + matrix.SetRow(n, row, w_1); + Commit(); +} +void Matrix4WithInverse::SetColumn(uint n, const Vector4 &col, bool w_1) +{ + matrix.SetColumn(n, col, w_1); + Commit(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NML::Tag *Matrix4WithInverse::AsMetaTag(const char *id) const +{ return matrix.AsMetaTag(id); } +bool Matrix4WithInverse::FromMetaTag(NML::Tag &tag) +{ + if (!matrix.FromMetaTag(tag)) + return false; + Commit(); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix4 Matrix4::TransformationMatrix(const Vector4 &p, const Matrix3 &r, const Vector4 &s, const Vector4 *o) +{ + Matrix4 m = + Matrix4::TranslationMatrix(p) * + Matrix4::FromMatrix3(r) * + Matrix4::ScaleMatrix(s); + return o ? m * Matrix4::TranslationMatrix(*o) : m; +} +Matrix4 Matrix4::TransformationMatrix(const Vector4 &p, const Vector4 &r, const Vector4 &s, const Vector4 *o) +{ + Matrix4 m = + Matrix4::TranslationMatrix(p) * + Matrix4::FromMatrix3(Matrix3::FromEuler(r.x, r.y, r.z)) * + Matrix4::ScaleMatrix(s); + return o ? m * Matrix4::TranslationMatrix(*o) : m; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix4 Matrix4::LerpAsOrthonormalBase(const Matrix4 &a, const Matrix4 &b, float k, bool fast) +{ + if (fast) + { + Matrix4 o; + for (int m = 0; m < 4; ++m) + for (int n = 0; n < 4; ++n) + o.m[m][n] = (b.m[m][n] - a.m[m][n]) * k + a.m[m][n]; + return o; + } + + Matrix3 a_matrix3, b_matrix3; + Vector4 a_position, b_position, a_scale, b_scale; + + a.Decompose(&a_position, &a_scale, &a_matrix3); + b.Decompose(&b_position, &b_scale, &b_matrix3); + + Quaternion a_orientation(Quaternion::FromMatrix3(a_matrix3)); + Quaternion b_orientation(Quaternion::FromMatrix3(b_matrix3)); + + return Matrix4::TranslationMatrix((b_position - a_position) * k + a_position) * + Matrix4::FromMatrix3(Quaternion::Slerp(k, a_orientation, b_orientation).AsMatrix3()) * + Matrix4::ScaleMatrix((b_scale - a_scale) * k + a_scale); +} +void Matrix4::Decompose(Vector4 *position, Vector4 *scale, Vector4 *rotation, Math::rOrder order) const +{ + Matrix3 m3; + Decompose(position, scale, &m3); + if (rotation) + *rotation = m3.AsEuler(order); +} +void Matrix4::Decompose(Vector4 *position, Vector4 *scale, Matrix3 *rotation) const +{ + // Extract position. + if (position) + *position = GetRow(3); + + // Extract scale. + Vector4 scl; + scl.Set(GetRow(0).Len(), GetRow(1).Len(), GetRow(2).Len()); + + // Handle negative scale (permute X to preserve left-handedness). + Vector4 left = GetRow(1).Cross(GetRow(2)); + if (left.Dot(GetRow(0)) < 0) + scl.x = -scl.x; + if (scale) + *scale = scl; + + // Rotation 3x3 (renormalized). + if (rotation) + { + if (scl.x) + { + scl.x = 1 / scl.x; + rotation->SetRow(0, Vector4(m[0][0] * scl.x, m[1][0] * scl.x, m[2][0] * scl.x)); + } + else rotation->SetRow(0, Vector4(1, 0, 0)); + + if (scl.y) + { + scl.y = 1 / scl.y; + rotation->SetRow(1, Vector4(m[0][1] * scl.y, m[1][1] * scl.y, m[2][1] * scl.y)); + } + else rotation->SetRow(1, Vector4(0, 1, 0)); + + if (scl.z) + { + scl.z = 1 / scl.z; + rotation->SetRow(2, Vector4(m[0][2] * scl.z, m[1][2] * scl.z, m[2][2] * scl.z)); + } + else rotation->SetRow(2, Vector4(0, 0, 1)); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix4 Matrix4::InversedFast() const +{ + // Extract inverse scale. + Vector4 scl(1.f / GetRow(0).Len(), 1.f / GetRow(1).Len(), 1.f / GetRow(2).Len()); + + // Inverse rotation 3x3 (renormalized). + Matrix3 irt ( + m[0][0] * scl.x, m[0][1] * scl.y, m[0][2] * scl.z, + m[1][0] * scl.x, m[1][1] * scl.y, m[1][2] * scl.z, + m[2][0] * scl.x, m[2][1] * scl.y, m[2][2] * scl.z + ); + + // Recompose as inverse matrix. + return Matrix4::ScaleMatrix(scl) * (Matrix4::FromMatrix3(irt) * Matrix4::TranslationMatrix(GetRow(3).Reversed())); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix4 Matrix4::AsOrthonormalBase() const +{ + Matrix3 rcp ( + m[0][0], m[1][0], m[2][0], + m[0][1], m[1][1], m[2][1], + m[0][2], m[1][2], m[2][2] + ); + rcp = rcp.AsOrthonormalBase(); + + Matrix4 otb(*this); + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + otb.m[i][j] = rcp.m[i][j]; + return otb; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix4 Matrix4::TranslationMatrix(const Vector4 &t) +{ return Matrix4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1); } +Matrix4 Matrix4::ScaleMatrix(const Vector4 &s) +{ return Matrix4(s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0, 0, 0, 0, 1); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NML::Tag *Matrix4::AsMetaTag(const char *id) const +{ + NML::Tag *root = new NML::Tag(id ? id : "Mtx4"); + root->AddChild(GetRow(0, false).AsMetaTag("R0", true)); + root->AddChild(GetRow(1, false).AsMetaTag("R1", true)); + root->AddChild(GetRow(2, false).AsMetaTag("R2", true)); + root->AddChild(GetRow(3, false).AsMetaTag("R3", true)); + return root; +} +bool Matrix4::FromMetaTag(NML::Tag &tag) +{ + NML::Tag *t; + Vector4 R; + + List ::Iterator i(tag.GetTags().GetRoot()); + + t = i.ObjectPtr(); + if (!t) return false; + R.FromMetaTag(*t); SetRow(0, R, false); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + R.FromMetaTag(*t); SetRow(1, R, false); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + R.FromMetaTag(*t); SetRow(2, R, false); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + R.FromMetaTag(*t); SetRow(3, R, false); + return true; +} +//------------------------------------------------------------------------------ + +bool Matrix4::Inverse(Matrix4 &out) const +{ + float inv[16], det; + + inv[0] = m[1][1] * m[2][2] * m[3][3] - m[1][1] * m[2][3] * m[3][2] - m[2][1] * m[1][2] * m[3][3] + m[2][1] * m[1][3] * m[3][2] + m[3][1] * m[1][2] * m[2][3] - m[3][1] * m[1][3] * m[2][2]; + inv[4] = -m[1][0] * m[2][2] * m[3][3] + m[1][0] * m[2][3] * m[3][2] + m[2][0] * m[1][2] * m[3][3] - m[2][0] * m[1][3] * m[3][2] - m[3][0] * m[1][2] * m[2][3] + m[3][0] * m[1][3] * m[2][2]; + inv[8] = m[1][0] * m[2][1] * m[3][3] - m[1][0] * m[2][3] * m[3][1] - m[2][0] * m[1][1] * m[3][3] + m[2][0] * m[1][3] * m[3][1] + m[3][0] * m[1][1] * m[2][3] - m[3][0] * m[1][3] * m[2][1]; + inv[12] = -m[1][0] * m[2][1] * m[3][2] + m[1][0] * m[2][2] * m[3][1] + m[2][0] * m[1][1] * m[3][2] - m[2][0] * m[1][2] * m[3][1] - m[3][0] * m[1][1] * m[2][2] + m[3][0] * m[1][2] * m[2][1]; + inv[1] = -m[0][1] * m[2][2] * m[3][3] + m[0][1] * m[2][3] * m[3][2] + m[2][1] * m[0][2] * m[3][3] - m[2][1] * m[0][3] * m[3][2] - m[3][1] * m[0][2] * m[2][3] + m[3][1] * m[0][3] * m[2][2]; + inv[5] = m[0][0] * m[2][2] * m[3][3] - m[0][0] * m[2][3] * m[3][2] - m[2][0] * m[0][2] * m[3][3] + m[2][0] * m[0][3] * m[3][2] + m[3][0] * m[0][2] * m[2][3] - m[3][0] * m[0][3] * m[2][2]; + inv[9] = -m[0][0] * m[2][1] * m[3][3] + m[0][0] * m[2][3] * m[3][1] + m[2][0] * m[0][1] * m[3][3] - m[2][0] * m[0][3] * m[3][1] - m[3][0] * m[0][1] * m[2][3] + m[3][0] * m[0][3] * m[2][1]; + inv[13] = m[0][0] * m[2][1] * m[3][2] - m[0][0] * m[2][2] * m[3][1] - m[2][0] * m[0][1] * m[3][2] + m[2][0] * m[0][2] * m[3][1] + m[3][0] * m[0][1] * m[2][2] - m[3][0] * m[0][2] * m[2][1]; + inv[2] = m[0][1] * m[1][2] * m[3][3] - m[0][1] * m[1][3] * m[3][2] - m[1][1] * m[0][2] * m[3][3] + m[1][1] * m[0][3] * m[3][2] + m[3][1] * m[0][2] * m[1][3] - m[3][1] * m[0][3] * m[1][2]; + inv[6] = -m[0][0] * m[1][2] * m[3][3] + m[0][0] * m[1][3] * m[3][2] + m[1][0] * m[0][2] * m[3][3] - m[1][0] * m[0][3] * m[3][2] - m[3][0] * m[0][2] * m[1][3] + m[3][0] * m[0][3] * m[1][2]; + inv[10] = m[0][0] * m[1][1] * m[3][3] - m[0][0] * m[1][3] * m[3][1] - m[1][0] * m[0][1] * m[3][3] + m[1][0] * m[0][3] * m[3][1] + m[3][0] * m[0][1] * m[1][3] - m[3][0] * m[0][3] * m[1][1]; + inv[14] = -m[0][0] * m[1][1] * m[3][2] + m[0][0] * m[1][2] * m[3][1] + m[1][0] * m[0][1] * m[3][2] - m[1][0] * m[0][2] * m[3][1] - m[3][0] * m[0][1] * m[1][2] + m[3][0] * m[0][2] * m[1][1]; + inv[3] = -m[0][1] * m[1][2] * m[2][3] + m[0][1] * m[1][3] * m[2][2] + m[1][1] * m[0][2] * m[2][3] - m[1][1] * m[0][3] * m[2][2] - m[2][1] * m[0][2] * m[1][3] + m[2][1] * m[0][3] * m[1][2]; + inv[7] = m[0][0] * m[1][2] * m[2][3] - m[0][0] * m[1][3] * m[2][2] - m[1][0] * m[0][2] * m[2][3] + m[1][0] * m[0][3] * m[2][2] + m[2][0] * m[0][2] * m[1][3] - m[2][0] * m[0][3] * m[1][2]; + inv[11] = -m[0][0] * m[1][1] * m[2][3] + m[0][0] * m[1][3] * m[2][1] + m[1][0] * m[0][1] * m[2][3] - m[1][0] * m[0][3] * m[2][1] - m[2][0] * m[0][1] * m[1][3] + m[2][0] * m[0][3] * m[1][1]; + inv[15] = m[0][0] * m[1][1] * m[2][2] - m[0][0] * m[1][2] * m[2][1] - m[1][0] * m[0][1] * m[2][2] + m[1][0] * m[0][2] * m[2][1] + m[2][0] * m[0][1] * m[1][2] - m[2][0] * m[0][2] * m[1][1]; + det = m[0][0] * inv[0] + m[0][1] * inv[4] + m[0][2] * inv[8] + m[0][3] * inv[12]; + + if (det == 0) + return false; + + det = 1.f / det; + + for (int i = 0; i < 16; i++) + ((float *)out.m)[i] = inv[i] * det; + + return true; +} diff --git a/include/framework/math/quaternion.cpp b/include/framework/math/quaternion.cpp new file mode 100644 index 0000000..a4b7542 --- /dev/null +++ b/include/framework/math/quaternion.cpp @@ -0,0 +1,218 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "math/quaternion.h" + #include "math/matrix3.h" + #include "metafile/nml.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +Quaternion Quaternion::Slerp(float t, const Quaternion &a, const Quaternion &b) +{ + float norm = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; + + bool bFlip = false; + + if (norm < 0.0f) + { + norm = -norm; + bFlip = true; + } + + float inv_d; + if (1.0f - norm < 0.000001f) + inv_d = 1.0f - t; + + else + { + float theta = Math::ACos(norm); + float s = 1.f / Math::Sin(theta); + + inv_d = Math::Sin((1.0f - t) * theta) * s; + t = Math::Sin(t * theta) * s; + } + + if (bFlip) + t = -t; + + return Quaternion(inv_d * a.x + t * b.x, inv_d * a.y + t * b.y, inv_d * a.z + t * b.z, inv_d * a.w + t * b.w); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Quaternion::Distance(const Quaternion &a, const Quaternion &b) +{ + const float dx = a.x - b.x, dy = a.y - b.y, dz = a.z - b.z, dw = a.w - b.w; + return Math::Sqrt((dx * dx) + (dy * dy) + (dz * dz) + (dw * dw)); +} +Quaternion Quaternion::Inverse() const +{ + const float norm = w * w + x * x + y * y + z * z; + if (norm > 0) + { + const float inorm = 1.f / norm; + return Quaternion(x * -inorm, y * -inorm, z * -inorm, w * inorm); + } + return *this; +} +Quaternion Quaternion::Normalize() const +{ + float d = Math::Sqrt(x * x + y * y + z * z + w * w); + if (!d) + return Quaternion(1, 1, 1, 1); + + float k = 1.f / d; + return Quaternion(x * k, y * k, z * k, w * k); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Quaternion Quaternion::LookAt(const Vector4 &at) +{ return Quaternion::FromMatrix3(Matrix3::FromOrthonormalBasis(at)); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Quaternion Quaternion::FromMatrix3(const Matrix3 &m) +{ + // From "Quaternion Calculus and Fast Animation". + float x, y, z, w; + float trace = m.m[0][0] + m.m[1][1] + m.m[2][2]; + + if (trace > 0.0) + { + // |w| > 1/2, may as well choose w > 1/2 + float root = Math::Sqrt(trace + 1.0f); // 2w + w = 0.5f * root; + root = 0.5f / root; // 1/(4w) + x = (m.m[2][1] - m.m[1][2]) * root; + y = (m.m[0][2] - m.m[2][0]) * root; + z = (m.m[1][0] - m.m[0][1]) * root; + } + else + { + // |w| <= 1/2 + static size_t inext[3] = { 1, 2, 0 }; + size_t i = 0; + if (m.m[1][1] > m.m[0][0]) + i = 1; + if (m.m[2][2] > m.m[i][i]) + i = 2; + size_t j = inext[i]; + size_t k = inext[j]; + + float root = Math::Sqrt(m.m[i][i] - m.m[j][j] - m.m[k][k] + 1.0f); + float *quat[3] = { &x, &y, &z }; + *quat[i] = 0.5f * root; + root = 0.5f / root; + w = (m.m[k][j] - m.m[j][k]) * root; + *quat[j] = (m.m[j][i] + m.m[i][j]) * root; + *quat[k] = (m.m[k][i] + m.m[i][k]) * root; + } + return Quaternion(x, y, z, w); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Quaternion Quaternion::FromAxisAngle(float a, float _x, float _y, float _z) +{ + float sn = Math::Sin(a * 0.5f), cs = Math::Cos(a * 0.5f); + return Quaternion(_x * sn, _y * sn, _z * sn, cs).Normalize(); +} +Quaternion Quaternion::FromEuler(float _x, float _y, float _z, Math::rOrder rorder) +{ + Quaternion qx(Quaternion::FromAxisAngle(_x, 1, 0, 0)), + qy(Quaternion::FromAxisAngle(_y, 0, 1, 0)), + qz(Quaternion::FromAxisAngle(_z, 0, 0, 1)), + q; + + switch (rorder) + { + case Math::rOrder_ZYX: q = qz * qy * qx; break; + case Math::rOrder_YZX: q = qy * qz * qx; break; + case Math::rOrder_ZXY: q = qz * qx * qy; break; + case Math::rOrder_XZY: q = qx * qz * qy; break; + default: + case Math::rOrder_YXZ: q = qy * qx * qz; break; + case Math::rOrder_XYZ: q = qx * qy * qz; break; + case Math::rOrder_XY: q = qx * qy; break; + } + return q.Normalize(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Matrix3 Quaternion::AsMatrix3() const +{ + float sqw = w * w, sqx = x * x, sqy = y * y, sqz = z * z; + + Matrix3 m; + + float invs = 1.f / (sqx + sqy + sqz + sqw); + m.m[0][0] = ( sqx - sqy - sqz + sqw) * invs; // Since sqw + sqx + sqy + sqz = 1 / invs * invs. + m.m[1][1] = (-sqx + sqy - sqz + sqw) * invs; + m.m[2][2] = (-sqx - sqy + sqz + sqw) * invs; + + float tmp1 = x * y; + float tmp2 = z * w; + m.m[1][0] = 2.f * (tmp1 + tmp2) * invs; + m.m[0][1] = 2.f * (tmp1 - tmp2) * invs; + + tmp1 = x * z; + tmp2 = y * w; + m.m[2][0] = 2.f * (tmp1 - tmp2) * invs; + m.m[0][2] = 2.f * (tmp1 + tmp2) * invs; + tmp1 = y * z; + tmp2 = x * w; + m.m[2][1] = 2.f * (tmp1 + tmp2) * invs; + m.m[1][2] = 2.f * (tmp1 - tmp2) * invs; + + return m; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NML::Tag *Quaternion::AsMetaTag(const char *id) const +{ + NML::Tag *root = new NML::Tag(id ? id : "Quaternion"); + + if (root) + { + root->AddChild("X", x); + root->AddChild("Y", y); + root->AddChild("Z", z); + root->AddChild("W", w); + } + return root; +} +bool Quaternion::FromMetaTag(NML::Tag &tag) +{ + NML::Tag *t; + List ::Iterator i(tag.GetTags().GetRoot()); + + t = i.ObjectPtr(); + if (!t) return false; + x = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + y = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + z = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + w = t->GetReal(); + + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/math/vector.cpp b/include/framework/math/vector.cpp new file mode 100644 index 0000000..9249608 --- /dev/null +++ b/include/framework/math/vector.cpp @@ -0,0 +1,207 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "metafile/nml.h" + #include "math/matrix3.h" + #include "math/matrix4.h" + #include "rand/rand.h" + + using namespace GS; + + +namespace GS { + +//------------------------------------------------------------------------------ +template <> tVector2 tVector2 ::operator * (const Matrix3 &m) const +{ + return tVector2 ( (float(x) * m.m[0][0] + float(y) * m.m[0][1] + m.m[0][2]), + int(float(x) * m.m[1][0] + float(y) * m.m[1][1] + m.m[1][2]) ); +} +template <> tVector2 tVector2 ::operator * (const Matrix3 &m) const +{ + return tVector2 ( x * m.m[0][0] + y * m.m[0][1] + m.m[0][2], + x * m.m[1][0] + y * m.m[1][1] + m.m[1][2] ); +} +//------------------------------------------------------------------------------ + +} + +//------------------------------------------------------------------------------ +Vector4 Vector4::Floor() const +{ return Vector4(Math::Floor(x), Math::Floor(y), Math::Floor(z), Math::Floor(w)); } +Vector4 Vector4::Ceil() const +{ return Vector4(Math::Ceil(x), Math::Ceil(y), Math::Ceil(z), Math::Ceil(w)); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector4 Vector4::Abs() const +{ return Vector4(Types::Abs(x), Types::Abs(y), Types::Abs(z)); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector4 Vector4::Clamped(float min, float max) const +{ + float _x, _y, _z; + if (x < min) _x = min; else if (x > max) _x = max; else _x = x; + if (y < min) _y = min; else if (y > max) _y = max; else _y = y; + if (z < min) _z = min; else if (z > max) _z = max; else _z = z; + return Vector4(_x, _y, _z); +} +Vector4 Vector4::Clamped(const Vector4 &min, const Vector4 &max) const +{ + float _x, _y, _z; + if (x < min.x) _x = min.x; else if (x > max.x) _x = max.x; else _x = x; + if (y < min.y) _y = min.y; else if (y > max.y) _y = max.y; else _y = y; + if (z < min.z) _z = min.z; else if (z > max.z) _z = max.z; else _z = z; + return Vector4(_x, _y, _z); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector4 Vector4::ClampedMagnitude(float min, float max) const +{ + float l2 = Len2(); + if ((l2 >= (min * min)) && (l2 <= (max * max))) + return Vector4(*this); + if (l2 < 0.000001) + return Vector4(*this); + float l = Math::Sqrt((float)l2); + return (*this) * Types::Clamp(l, min, max) / l; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Vector4::operator *= (const Matrix4 &m) +{ + float _x = x, _y = y, _z = z; + x = _x * m.m[0][0] + _y * m.m[0][1] + _z * m.m[0][2] + m.m[0][3]; + y = _x * m.m[1][0] + _y * m.m[1][1] + _z * m.m[1][2] + m.m[1][3]; + z = _x * m.m[2][0] + _y * m.m[2][1] + _z * m.m[2][2] + m.m[2][3]; +} +Vector4 Vector4::operator * (const Matrix4 &m) const +{ + return Vector4( x * m.m[0][0] + y * m.m[0][1] + z * m.m[0][2] + m.m[0][3], + x * m.m[1][0] + y * m.m[1][1] + z * m.m[1][2] + m.m[1][3], + x * m.m[2][0] + y * m.m[2][1] + z * m.m[2][2] + m.m[2][3] ); +} +void Vector4::operator *= (const Matrix3 &m) +{ + float _x = x, _y = y, _z = z; + x = _x * m.m[0][0] + _y * m.m[0][1] + _z * m.m[0][2]; + y = _x * m.m[1][0] + _y * m.m[1][1] + _z * m.m[1][2]; + z = _x * m.m[2][0] + _y * m.m[2][1] + _z * m.m[2][2]; +} +Vector4 Vector4::operator * (const Matrix3 &m) const +{ + return Vector4( x * m.m[0][0] + y * m.m[0][1] + z * m.m[0][2], + x * m.m[1][0] + y * m.m[1][1] + z * m.m[1][2], + x * m.m[2][0] + y * m.m[2][1] + z * m.m[2][2] ); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector4 Vector4::FaceForward(Vector4 &dir) +{ + if (Dot(dir) >= 0) + return Reversed(); + return *this; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int Vector4::Hash() const +{ + int a = (int)(x * 10.f), b = (int)(y * 10.f), c = (int)(z * 10.f); + // From Christer Ericson's Realtime Collision Detection. + return a * 0x8da6b343 + b * 0xd8163841 + c * 0xcb1ab31f; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Vector4::BaseToEuler(Vector4 &euler, Vector4 &u, Vector4 *v) +{ + float _v = Math::Sqrt(u.x * u.x + u.y * u.y + u.z * u.z); + euler.x = -Math::ASin(u.y / _v); + + _v = Math::Sqrt(u.x * u.x + u.z * u.z); + if (_v > 0.00001f) + euler.y = Math::ASin(u.x / _v); + else euler.y = 0; + + if (u.z < 0.f) + { + if (euler.y < 0.f) + euler.y = - (Math::Pi + euler.y); + else euler.y = Math::Pi - euler.y; + } + euler.z = 0; + + if (v) + { + Matrix3 mx(Matrix3::RotationMatrixXAxis(Units::Rad(euler.x))); + Matrix3 my(Matrix3::RotationMatrixYAxis(Units::Rad(euler.y))); + Vector4 bv(Vector4(1,0,0) * my * mx), vn(v->Normalized()); + const float vc = vn.Dot(bv); + + if (vc >= 1.f) + euler.z = 0.f; + else if (vc <= -1.f) + euler.z = Math::Pi; + else euler.z = Math::ACos(vc); + + if ((bv.Cross(vn)).Dot(u) <= 0.f) + euler.z = (Math::Pi + Math::Pi) - euler.z; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Vector4 Vector4::Random(float min, float max) +{ return Vector4(Random::FRRand(min, max), Random::FRRand(min, max), Random::FRRand(min, max)); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NML::Tag *Vector4::AsMetaTag(const char *id, bool fulldump) const +{ + NML::Tag *root = new NML::Tag(id ? id : "Vector"); + + if (root) + { + root->AddChild("X", x); + root->AddChild("Y", y); + root->AddChild("Z", z); + if (fulldump) + root->AddChild("W", w); + } + return root; +} +bool Vector4::FromMetaTag(NML::Tag &tag) +{ + NML::Tag *t; + List ::Iterator i(tag.GetTags().GetRoot()); + + t = i.ObjectPtr(); + if (!t) return false; + x = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + y = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (!t) return false; + z = t->GetReal(); + ++i; + + t = i.ObjectPtr(); + if (t) + w = t->GetReal(); + + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/metafile/nml_binary_load.cpp b/include/framework/metafile/nml_binary_load.cpp new file mode 100644 index 0000000..e69de29 diff --git a/include/framework/metafile/nml_binary_save.cpp b/include/framework/metafile/nml_binary_save.cpp new file mode 100644 index 0000000..2ac33fa --- /dev/null +++ b/include/framework/metafile/nml_binary_save.cpp @@ -0,0 +1,111 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "metafile/nml.h" + #include "filesystem/io_handle.h" + #include "filesystem/filesystem.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool Parser::SaveBinaryTag(IO::Handle &out, const Tag &tag, File::Binary method) +{ + const Variant &v = tag.GetValue(); + + if (v.GetType() != Variant::VariantNone) + { + out.Write ((ushort)tag.name.Len()); + out.Write((void *)tag.name.c_str(), tag.name.Len()); + } + else + __ERR__(__LOG_W__ << "Ignoring invalid metatag '" << tag.name << "'.\n", true) + + // Store tag start size/type. + out.Write ((uchar)v.GetType()); + + size_t tag_length_pos = out.Tell(); + switch (v.GetType()) + { + case Variant::VariantNone: + case Variant::VariantBinary: + case Variant::VariantString: + out.Write (-1); + break; + + default: break; + } + + switch (v.GetType()) + { + case Variant::VariantNone: + NMLTagForeach(child, tag) + if (!SaveBinaryTag(out, *child, method)) + return false; + break; + + case Variant::VariantBinary: + out.Write(tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize()); + break; + + case Variant::VariantInteger: + out.Write (tag.GetInteger()); + break; + + case Variant::VariantFloat: + out.Write (tag.GetReal()); + break; + + case Variant::VariantString: + out.Write(tag.GetString(), std::strlen(tag.GetString())); + break; + + default: + __ERR__(__LOG_E__ << "No method to output tag '" << tag.name << "' type.\n", false) + } + + switch (v.GetType()) + { + case Variant::VariantNone: + case Variant::VariantBinary: + case Variant::VariantString: + { + size_t tag_end_pos = out.Tell(); + out.Seek(tag_length_pos, IO::Base::SeekStart); + out.Write (tag_end_pos - tag_length_pos); + out.Seek(tag_end_pos, IO::Base::SeekStart); + } + break; + + default: break; + } + return true; +} +bool Parser::SaveBinary(IO::Handle &h, const File &file) +{ + h.Write((const void *)"\n", 10); + NMLFileForeach(tag, file) + if (!SaveBinaryTag(h, *tag, file.GetBinaryMethod())) + return false; + + return true; +} +bool Parser::SaveBinary(const char *uri, const File &file) +{ + if (!uri) + return false; + + AutoPtr handle; + if (!(handle = Platform::Get().io->Open(uri, IO::ModeWrite))) + __ERR__(__LOG_E__ << "Failed to open metafile output '" << uri << "'.\n", false) + + return SaveBinary(*handle, file); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/metafile/nml_file.cpp b/include/framework/metafile/nml_file.cpp new file mode 100644 index 0000000..2e1a8a4 --- /dev/null +++ b/include/framework/metafile/nml_file.cpp @@ -0,0 +1,83 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + +#include "metafile/nml.h" +#include "alloc/ialloc.h" + +using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool File::GetBool(const char *path, bool dflt, bool verbose) const { + Tag *t = GetTypedTag(path, Variant::VariantBool, verbose); + return t ? t->GetBool() : dflt; +} + +int File::GetInteger(const char *path, int dflt, bool verbose) const { + Tag *t = GetTypedTag(path, Variant::VariantInteger, verbose); + return t ? t->GetInteger() : dflt; +} + +float File::GetReal(const char *path, float dflt, bool verbose) const { + Tag *t = GetTypedTag(path, Variant::VariantFloat, verbose); + return t ? t->GetReal() : dflt; +} + +const char *File::GetString(const char *path, const char *dflt, bool verbose) const { + Tag *t = GetTypedTag(path, Variant::VariantString, verbose); + return t ? t->GetString() : dflt; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void File::Import(const File &src, bool clear_before_import) { + if (clear_before_import) + Clear(); + ListForeachPtr(Tag *, tag, src.GetTags()) + AddRoot(tag->Clone()); +} + +File *File::Clone() const { + File *clone = new File; + if (!clone) + return NULL; + + if (!name.IsEmpty()) + clone->name = name.c_str(); + + clone->Import(*this); + return clone; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *File::AddRoot(Tag *t) { + if (!t) + return NULL; + if (!tags.Add(t)) + return NULL; + return t; +} + +Tag *File::AddRoot(const char *name) { return AddRoot(new Tag(name)); } +Tag *File::AddRoot(const char *name, bool v) { return AddRoot(new Tag(name, v)); } +Tag *File::AddRoot(const char *name, int v) { return AddRoot(new Tag(name, v)); } +Tag *File::AddRoot(const char *name, float v) { return AddRoot(new Tag(name, v)); } +Tag *File::AddRoot(const char *name, const char *s) { return AddRoot(new Tag(name, s)); } +Tag *File::AddRoot(const char *name, void *d, size_t s) { return AddRoot(new Tag(name, d, s)); } +bool File::UnlinkRoot(Tag *t) { return tags.Remove(t); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void File::Free() { + ListDeleteAllPtr(Tag *, tags); + name.Clear(); +} + +File::~File() { Free(); } +//------------------------------------------------------------------------------ diff --git a/include/framework/metafile/nml_generic.cpp b/include/framework/metafile/nml_generic.cpp new file mode 100644 index 0000000..41fcb27 --- /dev/null +++ b/include/framework/metafile/nml_generic.cpp @@ -0,0 +1,122 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "metafile/nml.h" + #include "reflection/c_refl.h" + #include "memory/nauto_ptr.h" + #include "assert/nassert.h" + + +namespace GS { + namespace NML { + using namespace Reflection; + +//------------------------------------------------------------------------------ +bool GenericObjectFromMetaTag(Tag &t, void *o, Property *o_prop) +{ + NMLTagForeach(pt, t) + for (int n = 0; o_prop[n].name; ++n) + if (pt->name == o_prop[n].name) + { + size_t p_prop = (size_t)o + o_prop[n].offset_of; + + switch (o_prop[n].type) + { + case Property::BoolProp: + *(bool *)p_prop = pt->GetBool(); + break; + case Property::CharProp: + *(char *)p_prop = (char)pt->GetInteger(); + break; + case Property::ShortProp: + *(short *)p_prop = (short)pt->GetInteger(); + break; + case Property::IntProp: + *(int *)p_prop = pt->GetInteger(); + break; + case Property::FloatProp: + *(float *)p_prop = pt->GetReal(); + break; + case Property::StringProp: + *(GS::String *)p_prop = pt->GetString(); + break; + case Property::EnumProp: + __ASSERT__(o_prop[n].enum_dict); + *(int *)p_prop = Enum::fromString(pt->GetString(), o_prop[n].enum_dict); + break; + + default: + __ASSERT_ALWAYS__; + break; + } + } + + return true; +} +Tag *GenericObjectToMetaTag(Tag *t, const void *o, Property *o_prop) +{ + if (t) + for (int n = 0; o_prop[n].name; ++n) + { + size_t p_prop = (size_t)o + o_prop[n].offset_of; + + switch (o_prop[n].type) + { + case Property::BoolProp: + t->AddChild(o_prop[n].name, *(bool *)p_prop); + break; + case Property::CharProp: + t->AddChild(o_prop[n].name, (int)*(char *)p_prop); + break; + case Property::ShortProp: + t->AddChild(o_prop[n].name, (int)*(short *)p_prop); + break; + case Property::IntProp: + t->AddChild(o_prop[n].name, *(int *)p_prop); + break; + case Property::FloatProp: + t->AddChild(o_prop[n].name, *(float *)p_prop); + break; + case Property::StringProp: + t->AddChild(o_prop[n].name, ((GS::String *)p_prop)->c_str()); + break; + case Property::EnumProp: + __ASSERT__(o_prop[n].enum_dict); + t->AddChild(o_prop[n].name, Enum::toString(*(int *)p_prop, o_prop[n].enum_dict)); + break; + + default: + __ASSERT_ALWAYS__; + break; + } + } + return t; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool GenericObjectFromMetaFile(const char *uri, void *obj, Property *obj_prop, const char *root_name) +{ + File file; + if (!Parser::Load(uri, file)) + return false; + + if (Tag *root = file.GetTag(root_name)) + if (!GenericObjectFromMetaTag(*root, obj, obj_prop)) + return false; + + return true; +} +bool GenericObjectToMetaFile(const char *uri, const void *obj, Property *obj_prop, const char *root_name) +{ + File file; + file.AddRoot(GenericObjectToMetaTag(new Tag(root_name), obj, obj_prop)); + return Parser::Save(uri, file); +} +//------------------------------------------------------------------------------ + + } //NML +} // GS diff --git a/include/framework/metafile/nml_load.cpp b/include/framework/metafile/nml_load.cpp new file mode 100644 index 0000000..cdd3799 --- /dev/null +++ b/include/framework/metafile/nml_load.cpp @@ -0,0 +1,380 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "metafile/nml.h" + #include "ascii/parser.h" + #include "ascii/ascii_encoder.h" + #include "filesystem/io_handle.h" + #include "filesystem/filesystem.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::NML; + using namespace GS::AsciiParser; + + +//------------------------------------------------------------------------------ +bool Parser::IsMetafile(const char *name) +{ + AutoPtr h(Platform::Get().io->Open(name)); + if (h.IsNull()) + return false; + + char header[9]; + h->Read(header, 9); + if (Memory::Compare(header, "': + s++; + break; + + // Node/real/integer/string. + case '=': + { + s++; + forever + { + s += SkipSpace(s, e) - s; + if (s == e) + MLTAG_ERROR("Mangled definition, metatag '" << tag.name << "'.\n") + + // End of tag. + if (s[0] == '>') + { + s++; + break; + } + + // Preprocessor directive. + if (s[0] == '#') + s = ParseTagPreprocessorDirective(tag, s + 1, e); + + // Node. + else if (s[0] == '<') + { + if (tag.GetValue().GetType() != Variant::VariantNone) + MLTAG_ERROR("Incoherent type in tag '" << tag.name << "' declaration.\n") + + Tag *stag = tag.tags.Add(new Tag)->Object(); + if (!ParseTag(*stag, s, e, &s)) + MLTAG_ERROR("") + s += SkipSpace(s, e) - s; + } + + // Constant. + else + { + if (tag.GetValue().GetType() != Variant::VariantNone) + MLTAG_ERROR("Incoherent type in tag '" << tag.name << "' declaration.\n") + + // Binary. + if (s[0] == '=') + { + s++; + if (!(s[0] >= '0' && s[0] <= '9')) + MLTAG_ERROR("Expected encoded size in binary tag '" << tag.name << "' declaration.\n") + + const char *ye = s; + while (ye[0] >= '0' && ye[0] <= '9') + ye++; + if (ye[0] != ':') + MLTAG_ERROR("Expected size delimiter in binary tag '" << tag.name << "' declaration.\n") + uint asize = String(s, ye).Integer(); + + s = ye + 1; + if (!(s[0] >= '0' && s[0] <= '9')) + MLTAG_ERROR("Expected binary size in binary tag '" << tag.name << "' declaration.\n") + ye = s; + while (ye[0] >= '0' && ye[0] <= '9') + ye++; + + // Trailing @ means yEnc binary. + File::Binary encoding = File::Binary_UU; + if (ye[0] == '@') + { + encoding = File::Binary_yEnc; + ye++; + } + + // Detect EOL + if ((ye[0] != 0x0a) && ((ye[0] != 0x0d) && (ye[1] != 0x0a))) + MLTAG_ERROR("Expected EOL following binary size in binary tag '" << tag.name << "' declaration.\n") + + size_t eol_size = (ye[0] == 0x0a) ? 1 : 2; + uint bsize = String(s, ye).Integer(); + + uchar *astart = (uchar *)(ye + eol_size); + + // [EJ] Adjust asize to account for Windows EOL (historically NML only specifies Unix ascii size). + if (eol_size > 1) + { + __LOG_V__ << "CRLF reduces NML binary load performance.\n"; + + size_t a_size_in = asize; + asize = 0; + + for (; a_size_in > 0; --a_size_in) + if ((astart[asize] == 0x0d) && (astart[asize + 1] == 0x0a)) + asize += 2; + else + ++asize; + } + // Load ASCII encoded data. + Array aenc(asize, Alloc::Metatag); + if (!aenc) + MLTAG_ERROR("Failed to allocate binary buffer in binary tag '" << tag.name << "'.\n") + + memcpy(&aenc[0], astart, asize); + + s = ye + eol_size + asize; + if (s[0] != '>') + MLTAG_ERROR("Expected closing tag in tag '" << tag.name << "'.\n") + + Array data(bsize, Alloc::Metatag); + if (data) + { + switch (encoding) + { + case File::Binary_UU: nAsciiEncoder::UUDecode(&aenc[0], asize, &data[0], bsize); break; + case File::Binary_yEnc: nAsciiEncoder::yDecode(&aenc[0], asize, &data[0], bsize); break; + } + tag.GetValue().SetBinary(&data[0], bsize); + } + } + // Real/Integer. + else if ((s[0] >= '0' && s[0] <= '9') || (s[0] == '.') || (s[0] == '-')) + { + if (IsConstantFloat(s, e)) + tag.GetValue() = String::atof(s, e, true); + else tag.GetValue() = String::atoi(s); + + if (s[0] == '-') + s++; + s += SkipEntry(s, e) - s; + + if (s[0] != '>') + MLTAG_ERROR("Unexpected trailing expression following value, metatag '" << tag.name << "'.\n") + } + // String. + else if (s[0] == '\"') + { + s++; + ptrdiff_t len = RunToEOS(s, e) - s; + if ((s + len) == e) + MLTAG_ERROR("Mangled string declaration, metatag '" << tag.name << "'.\n") + + // Copy string. + tag.GetValue() = String(s, s + len); + + s += SkipSpace(s + len + 1, e) - s; // Jump over string. + if (s == e) + MLTAG_ERROR("Unexpected EOF after string declaration, metatag '" << tag.name << "'.\n") + if (s[0] != '>') + MLTAG_ERROR("Unexpected trailing expression following string object, metatag '" << tag.name << "'.\n") + + tag.GetValue().s_value.ReplaceAll("\\n", "\n"); // convert CF + } + // Boolean. + else if (!strncmp(s, "True", 4)) + { + tag.GetValue() = true; + s += SkipSpace(s + 4, e) - s; + if (s[0] != '>') + MLTAG_ERROR("Unexpected trailing expression following value, metatag '" << tag.name << "'.\n") + } + else if (!strncmp(s, "False", 5)) + { + tag.GetValue() = false; + s += SkipSpace(s + 5, e) - s; + if (s[0] != '>') + MLTAG_ERROR("Unexpected trailing expression following value, metatag '" << tag.name << "'.\n") + } + else + MLTAG_ERROR("Unexpected '" << s[0] << "' in assignation, metatag '" << tag.name << "'.\n") + } + } + } + break; + + default: + MLTAG_ERROR("Unexpected trailing expression after metatag '" << tag.name << "' name declaration.\n") + } + if (es) + es[0] = s; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Parser::LoadFromMemory(const char *data, size_t size, File &mfl) +{ + mfl.Free(); + if (!data) + return false; + + // Read header tag, expected to be NML version. + const char *pof = data, *eof = data + size; + + #define MEM_MLP_ERROR(c) { (c); return false; } + + Tag header_tag; + if (!ParseTag(header_tag, pof, eof, &pof)) + MEM_MLP_ERROR(__LOG_E__ << "Invalid metafile.\n") + if ((header_tag.name != "Version") && (header_tag.name != "NML")) + MEM_MLP_ERROR(__LOG_E__ << "Unknown metafile variant.\n") + + switch (header_tag.GetValue().GetType()) + { + case Variant::VariantInteger: + if (header_tag.GetInteger() > version) + __LOG_W__ << "Newer version NML header found (" << header_tag.GetInteger() << ">" << version << ").\n"; + break; + + case Variant::VariantFloat: + if (header_tag.GetReal() > version) + __LOG_W__ << "Newer version NML header found (" << header_tag.GetReal() << ">" << version << ").\n"; + break; + + default: + __LOG_W__ << "Unknown NML header version identification method.\n"; + break; + } + + // Read all root tags. + while (pof < eof) + { + Tag *tag = mfl.tags.Add(new Tag)->Object(); + if (!ParseTag(*tag, pof, eof, &pof)) + return false; + pof += SkipSpace(pof, eof) - pof; + } + return true; +} +bool Parser::Load(const char *path, File &file, bool verbose) +{ + if (!path) + return false; + + Array data; + if (!Platform::Get().io->FileLoad(path, data, verbose)) + return false; + + try + { + if (!LoadFromMemory(data.c_ptr(), data.GetSize(), file)) + return false; + } + catch (char *e) + { + __LOG_E__ << "Failed to load file LoadFromMemory. " << path << "\n"; + return false; + } + file.name = path; + return true; +} +File *Parser::Load(const char *metafile, bool verbose) +{ + AutoPtr mfl(new File); + if (mfl.IsNull()) + __ERR__(__LOG_E__ << "Failed to allocate file.\n", NULL) + return Load(metafile, *mfl, verbose) ? mfl.Detach() : NULL; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/metafile/nml_query.cpp b/include/framework/metafile/nml_query.cpp new file mode 100644 index 0000000..1749fee --- /dev/null +++ b/include/framework/metafile/nml_query.cpp @@ -0,0 +1,97 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::NML; + + +static bool MetatagNameCompare(const Tag *o, const String &name) { return o->name == name; } + +//------------------------------------------------------------------------------ +Tag *Tag::GetTagEx(const List &tg, const char *s, const File *, bool verbose) +{ + if (!s) + return NULL; + + const char *path = s; + const List *list = &tg; + + Tag *tag = NULL; + + while (s[0]) + { + while (s[0] == ':') + s++; + if (s[0] == ';') + break; + + const char *t = s; + while ((t[0] != ';') && (t[0] != ':') && t[0]) + t++; + if (!t[0] && verbose) + { + if (t > s) + __LOG_W__ << "incomplete path '" << path << "' (missing ';').\n"; + else __LOG_E__ << "unexpected end of path'" << path << "'.\n"; + } + + // No more node to search. + if (!list) + { + if (verbose) + __LOG_W__ << "'" << path << "' is deeper than lowest tree node.\n"; + return NULL; + } + + String node_name(s, t); + s = t; + tag = ListFindEx(*list, MetatagNameCompare, node_name); + + if (tag == NULL) + { + if (verbose) + __LOG__ << "!! Error '" << node_name << "' in '" << path << "' not found.\n"; + return NULL; + } + + switch (tag->GetValue().GetType()) + { + case Variant::VariantNone: + list = &tag->tags; + break; + + default: + list = NULL; + break; + } + } + return tag; +} +Tag *Tag::GetTag(const char *path, const File *root, bool verbose) const +{ + return GetTagEx(tags, path, root, verbose); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Tag::GetTypedTag(const char *path, Variant::Type type, const File *root, bool verbose) const +{ + Tag *t = Tag::GetTagEx(tags, path, root, verbose); + if ((!t) || (t->GetValue().GetType() != type)) + return NULL; + return t; +} +Tag *File::GetTypedTag(const char *path, Variant::Type type, bool verbose) const +{ + Tag *t = Tag::GetTagEx(tags, path, this, verbose); + if ((!t) || (t->GetValue().GetType() != type)) + return NULL; + return t; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/metafile/nml_save.cpp b/include/framework/metafile/nml_save.cpp new file mode 100644 index 0000000..d40355a --- /dev/null +++ b/include/framework/metafile/nml_save.cpp @@ -0,0 +1,152 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include "metafile/nml.h" + #include "ascii/ascii_encoder.h" + #include "filesystem/filesystem.h" + #include "filesystem/io_handle.h" + #include "memory/nauto_ptr.h" + #include "platform_config.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +bool Parser::SaveTag(IO::Handle &out, const Tag &tag, File::Binary method, uint idt) +{ + //--------------------------------------------------------------------------- + #define OUTPUT_INDENT { for (uint n = 0; n < idt; n++) out << "\t"; } + //--------------------------------------------------------------------------- + + if (tag.name.IsEmpty() && !tag.GetChildCount()) + return true; // silently skip this tag + + OUTPUT_INDENT; + out << "<" << tag.name.c_str(); + + switch (tag.GetValue().GetType()) + { + case Variant::VariantNone: + if (tag.GetChildCount()) + { + out << "=\n"; + + NMLTagForeach(child, tag) + if (!SaveTag(out, *child, method, idt + 1)) + return false; + + OUTPUT_INDENT; + } + break; + + case Variant::VariantBinary: + { + uint olen = (uint)~0; + + switch (method) + { + case File::Binary_UU: + olen = nAsciiEncoder::UUEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize()); + break; + + case File::Binary_yEnc: + olen = nAsciiEncoder::yEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize()); + break; + } + + if (olen) + { + Array aenc(olen, Alloc::Metatag); + + if (aenc.IsValid()) + { + uint asize = 0; + switch (method) + { + case File::Binary_UU: + asize = nAsciiEncoder::UUEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize(), &aenc[0], olen); + break; + + case File::Binary_yEnc: + asize = nAsciiEncoder::yEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize(), &aenc[0], olen); + break; + } + if (asize != olen) + __LOG_W__ << "Internal ASCII encoding inconsistency detected while processing tag '" << tag.name << "'.\n"; + + char str[256]; + _snprintf(str, 255, "==%d:%d", asize, tag.GetValue().GetBinarySize()); // ==[encoded size:decoded size] is encoded binary. + out << str; + + if (method == File::Binary_yEnc) // @ marker select yEncoding. + out << "@"; + out << "\n"; + + out.Write(aenc, asize); + } + else + __LOG_E__ << "Tag '" << tag.name << "' failed to allocate internal binary buffer.\n"; + } +// else __LOG_W__ << "NULL size ASCII encoded binary tag '" << tag.id << "'.\n"; + } + break; + + case Variant::VariantInteger: + { + char str[256]; + _snprintf(str, 255, "=%d", tag.GetInteger()); + out << str; + } + break; + + case Variant::VariantFloat: + { + char str[256]; + _snprintf(str, 255, "=%f", tag.GetReal()); + out << str; + } + break; + + case Variant::VariantString: + out << "=\"" << tag.GetString() << "\""; + break; + + case Variant::VariantBool: + out << "=" << (tag.GetBool() ? "True" : "False"); + break; + + default: + __ERR__(__LOG_E__ << "No method to output tag '" << tag.name << "' type.\n", false) + } + + out << ">\n"; + return true; +} +bool Parser::Save(IO::Handle &h, const File &file) +{ + h << "\n"; + NMLFileForeach(tag, file) + if (!SaveTag(h, *tag, file.GetBinaryMethod(), 0)) + return false; + return true; +} +bool Parser::Save(const char *uri, const File &file) +{ + if (!uri) + return false; + + AutoPtr h(Platform::Get().io->Open(uri, IO::ModeWrite)); + if (h.IsNull()) + __ERR__(__LOG_E__ << "Failed to open nml output '" << uri << "'.\n", false) + + return Save(*h, file); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/metafile/nml_string.cpp b/include/framework/metafile/nml_string.cpp new file mode 100644 index 0000000..671ba4a --- /dev/null +++ b/include/framework/metafile/nml_string.cpp @@ -0,0 +1,65 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "metafile/nml_string.h" + #include "metafile/nml.h" + #include "filesystem/io_memory.h" + #include "memory/nauto_ptr.h" + #include "nstring/nstring.h" + #include "log/log.h" + + +namespace GS { + namespace NML { + +//----------------------------------------------------------------------------- +bool TagToString(const Tag &tag, String &str) +{ + IO::Memory memory_fs; + + AutoPtr h(memory_fs.Open("file", IO::ModeWrite)); + if (h.IsNull() || !Parser::SaveTag(*h, tag)) + return false; + h = NULL; + + Array data; + if (!memory_fs.FileLoad("file", data)) + return false; + + str.Set(data.Start(), data.End()); + return true; +} +bool TagFromString(const String &str, Tag &tag) +{ + return Parser::ParseTag(tag, str.c_str(), &str.c_str()[str.Len()]); +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +bool FileToString(const File &file, String &str) +{ + IO::Memory memory_fs; + + AutoPtr h(memory_fs.Open("file", IO::ModeWrite)); + if (h.IsNull() || !Parser::Save(*h, file)) + return false; + h = NULL; + + Array data; + if (!memory_fs.FileLoad("file", data)) + return false; + + str.Set(data.Start(), data.End()); + return true; +} +bool FileFromString(const String &str, File &file) +{ + return Parser::LoadFromMemory(str.c_str(), str.Len(), file); +} +//----------------------------------------------------------------------------- + + } // NML +} // GS diff --git a/include/framework/metafile/nml_tag.cpp b/include/framework/metafile/nml_tag.cpp new file mode 100644 index 0000000..5040121 --- /dev/null +++ b/include/framework/metafile/nml_tag.cpp @@ -0,0 +1,121 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "metafile/nml.h" + #include "filesystem/io_handle.h" + #include "alloc/ialloc.h" + #include "log/log.h" + + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +Tag *Tag::GetParent(Tag *root) const +{ + ListForeachPtr(Tag *, child, root->GetTags()) + if (child == this) + return root; + + Tag *parent = NULL; + ListForeachPtr(Tag *, child, root->GetTags()) + if ((parent = GetParent(child)) != NULL) + break; + + return parent; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag *Tag::AddChild(Tag *t) +{ + if (!t) + return NULL; + if (value.type != Variant::VariantNone) + __ERR__(__LOG_E__ << "Cannot add child to tag '" << name << "' as it is neither a pure tag or a node.\n", NULL) + if (!tags.Add(t)) + return NULL; + return t; +} +Tag *Tag::AddChild(const char *name) +{ return AddChild(new Tag(name)); } +Tag *Tag::AddChild(const char *name, bool v) +{ return AddChild(new Tag(name, v)); } +Tag *Tag::AddChild(const char *name, int v) +{ return AddChild(new Tag(name, v)); } +Tag *Tag::AddChild(const char *name, uint v) +{ return AddChild(new Tag(name, v)); } +Tag *Tag::AddChild(const char *name, float v) +{ return AddChild(new Tag(name, v)); } +Tag *Tag::AddChild(const char *name, const char *s) +{ return AddChild(new Tag(name, s)); } +Tag *Tag::AddChild(const char *name, void *buffer, size_t size) +{ return AddChild(new Tag(name, buffer, size)); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Tag::Clone(const Tag &src, bool recursive) +{ + Free(); + + value = src.GetValue(); + + if (recursive) + ListForeachPtr(Tag *, ct, src.GetTags()) + AddChild(ct->Clone(true)); + + return true; +} +Tag *Tag::Clone(bool recursive) const +{ + Tag *clone = new Tag(name); + if (!clone) + return NULL; + + // Copy tag content. + clone->GetValue() = value; + + // Clone children. + if (recursive) + ListForeachPtr(Tag *, ct, tags) + clone->AddChild(ct->Clone(true)); + + return clone; +} +uint Tag::DeleteChildren(const char *filter) +{ + uint count = 0; + + if (filter) + { + String _filter(filter); + + ListForeachPtr(Tag *, t, tags) + if (t->name == _filter) + { + tags.Remove(t); + _safe_delete(t); + count++; + } + } + else + ListDeleteAllPtr(Tag *, tags) + + return count; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Tag::Free() +{ + value.Free(); + DeleteChildren(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Tag::~Tag() +{ Free(); } +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict.cpp b/include/framework/picture/pict.cpp new file mode 100644 index 0000000..1d448d8 --- /dev/null +++ b/include/framework/picture/pict.cpp @@ -0,0 +1,205 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include "picture/pict.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool Picture::HasAlpha() const +{ + uchar *pdata = GetData(); + if (!pdata || !width || !height) + return false; + + for (uint y = 0; y < height; y++) + for (uint x = 0; x < width; x++) + { + union + { + uint packed; + uchar ppack[4]; + }; + + switch (pxformat.GetBpp()) + { + case 8: ppack[0] = pdata[0]; pdata++; break; + case 16: ppack[0] = pdata[0]; ppack[1] = pdata[1]; pdata += 2; break; + case 24: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; pdata += 3; break; + case 32: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; ppack[3] = pdata[3]; pdata += 4; break; + } + + int a = (int)(((packed & pxformat.desc.amask) >> pxformat.ashift) << (8 - pxformat.acount)); + if (a < ((1 << pxformat.acount) - 1)) + return true; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Picture::ColorBlend(uint u, uint v, float opacity) +{ + int fk = (int)(opacity * 65536), + ik = 65536 - fk; + + uint ta = ((u >> 24) & 0xff) * ik + ((v >> 24) & 0xff) * fk, + tr = ((u >> 16) & 0xff) * ik + ((v >> 16) & 0xff) * fk, + tg = ((u >> 8) & 0xff) * ik + ((v >> 8) & 0xff) * fk, + tb = (u & 0xff) * ik + (v & 0xff) * fk; + + return ((ta << 8) & 0xff000000) + (tr & 0xff0000) + ((tg >> 8) & 0xff00) + (tb >> 16); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::Compare(const Picture &picture) const +{ + if (pxformat != picture.GetPixelFormat().GetDesc()) + return false; + // Binary comparison. + return !Memory::Compare(data, picture.GetData(), width * height * (pxformat.GetBpp() >> 3)); +} +bool Picture::ComputeHash() +{ + uchar *pdata = GetData(); + if (!pdata || !width || !height) + return false; + + hash = 0; + for (uint y = 0; y < height; y++) + for (uint x = 0; x < width; x++) + { + union + { + uint packed; + uchar ppack[4]; + }; + + switch (pxformat.GetBpp()) + { + case 8: ppack[0] = pdata[0]; pdata++; break; + case 16: ppack[0] = pdata[0]; ppack[1] = pdata[1]; pdata += 2; break; + case 24: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; pdata += 3; break; + case 32: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; ppack[3] = pdata[3]; pdata += 4; break; + } + + int a = (int)(((packed & pxformat.desc.amask) >> pxformat.ashift) << (8 - pxformat.acount)); + int r = (int)(((packed & pxformat.desc.rmask) >> pxformat.rshift) << (8 - pxformat.rcount)); + int g = (int)(((packed & pxformat.desc.gmask) >> pxformat.gshift) << (8 - pxformat.gcount)); + int b = (int)(((packed & pxformat.desc.bmask) >> pxformat.bshift) << (8 - pxformat.bcount)); + + hash += (a << 24) + (r << 16) + (g << 8) + b; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::SetData(void *ud, uint w, uint h, const PixelFormatDescription &fmt, bool take_ownership) +{ + if (!ud) + return; + + FreeData(); + hash = 0; + + data = (uchar *)ud; + if (!take_ownership) + pic_flag.Set(HasForeignData); + + width = w; + height = h; + pxformat.Set(fmt); +} +bool Picture::AllocAs(uint w, uint h, const PixelFormatDescription &fmt) +{ + if (!pic_flag.IsSet(HasForeignData) && data && (width == w) && (height == h) && (pxformat.GetBpp() == fmt.bpp)) + { + pxformat.Set(fmt); + return true; + } + + FreeData(); + + if (w && h && fmt.bpp) + { + size_t count = w * h * (fmt.bpp / 8); + + data = AllocMemory(count); + if (data) + memset(data, 0, sizeof(uchar) * count); + else + __ERR__(__LOG_E__ << "Failed to allocate picture buffer (" << w << "x" << h << "@" << fmt.bpp << "bpp).\n", false); + + width = w; + height = h; + pxformat.Set(fmt); + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::Clone(const Picture &src, bool clone_data) +{ + Free(); + + if (src.IsStub()) + Stub(src.GetWidth(), src.GetHeight()); + else + { + if (clone_data) + { + if (AllocAs(src.GetWidth(), src.GetHeight(), src.pxformat.GetDesc())) + Memory::Copy((char *)data, (char *)src.GetData(), width * height * (pxformat.GetBpp() / 8)); + } + else + SetData(src.GetData(), src.GetWidth(), src.GetHeight(), src.pxformat.GetDesc(), false); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::Stub(uint w, uint h) +{ + Free(); + protected_flag.Set(PictureIsStub); + width = w; + height = h; +} +void Picture::Zeroify() +{ + data = NULL; + hash = 0; + width = height = 0; + pxformat.Set(PixelFormat::NONE); + pic_flag = 0; + protected_flag = 0; +} +void Picture::FreeData() +{ + if (!pic_flag.IsSet(HasForeignData)) + FreeMemory(data); + data = NULL; + pic_flag.Remove(HasForeignData); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uchar *Picture::AllocMemory(size_t size) +{ return (uchar *)Alloc::DefaultAllocator::Alloc(size, Alloc::Picture); } +void Picture::FreeMemory(uchar *data) +{ Alloc::DefaultAllocator::Delete(data, Alloc::Picture); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Picture::~Picture() { Free(); } +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_blit.cpp b/include/framework/picture/pict_blit.cpp new file mode 100644 index 0000000..18963c0 --- /dev/null +++ b/include/framework/picture/pict_blit.cpp @@ -0,0 +1,420 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include + #include "picture/pict.h" + #include "color/color.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool Picture::Reframe(int offset_sx, int offset_sy, int offset_ex, int offset_ey, const Color *fill) +{ + if (!GetData() || (GetPixelFormat().GetBpp() != 32)) + return false; + + int _width = GetWidth() - offset_sx + offset_ex, + _height = GetHeight() - offset_sy + offset_ey; + + uint *new_data = (uint *)AllocMemory(sizeof(uint) * _width * _height), *_d = new_data; + + if (!new_data) + __ERR__(__LOG_E__ << "Failed to allocate destination buffer.\n", false) + + // Fill color. + uint _fill = fill ? GetPixelFormat().Format(fill->x, fill->y, fill->z, fill->w) : GetPixelFormat().Format(0, 0, 0); + + // Top framing. + for (int y = offset_sy; y < 0; ++y) + for (int x = 0; x < _width; ++x) + *_d++ = _fill; + + // Blit + left/right framing. + int blit_ex = offset_ex > 0 ? GetWidth() : GetWidth() + offset_ex, + blit_ey = offset_ey > 0 ? GetHeight() : GetHeight() + offset_ey; + + uint *s = (uint *)GetData(); + if (offset_sy > 0) + s += GetWidth() * offset_sy; + + for (int y = offset_sy > 0 ? offset_sy : 0; y < blit_ey; ++y) + { + uint *_s = s; + + for (int x = offset_sx; x < 0; ++x) + *_d++ = _fill; // Left framing + for (int x = offset_sx > 0 ? offset_sx : 0; x < blit_ex; ++x) + *_d++ = _s[x]; // Blit + for (int x = 0; x < offset_ex; ++x) + *_d++ = _fill; // Right framing + + s += GetWidth(); + } + + // Bottom framing. + for (int y = 0; y < offset_ey; ++y) + for (int x = 0; x < _width; ++x) + *_d++ = _fill; + + SetData(new_data, _width, _height, GetPixelFormat().GetDesc(), true); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::Flip(bool flip_h, bool flip_v) +{ + if (!GetData() || (GetPixelFormat().GetBpp() != 32)) + return false; + + uint *s = (uint *)GetData(), + *d = s, t; + + if (flip_h) + { + if (flip_v) + { + d += GetWidth() * GetHeight() - 1; + + while (d > s) + { + t = *s; + *s++ = *d; + *d-- = t; + } + } + else + { + for (uint n = 0; n < GetHeight(); ++n) + { + uint *_s = s, *_d = d + GetWidth() - 1; + + while (_d > _s) + { + t = *_s; + *_s++ = *_d; + *_d-- = t; + } + s += GetWidth(); + d += GetWidth(); + } + } + } + else + if (flip_v) + { + d += GetWidth() * (GetHeight() - 1); + while (d > s) + { + for (uint n = 0; n < GetWidth(); ++n) + { + t = s[n]; + s[n] = d[n]; + d[n] = t; + } + s += GetWidth(); + d -= GetWidth(); + } + } + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static void WindowClip(const Rect *a, Rect *fa, const Rect *b, Rect *fb) +{ + Rect _b(*b); + _b.ex = _b.sx + a->GetWidth(); + _b.ey = _b.sy + a->GetHeight(); + + // Clip source rectangle and correct destination rectangle. + *fa = fa->Intersection(*a); + _b.sx += fa->sx - a->sx; + _b.sy += fa->sy - a->sy; + _b.ex += fa->ex - a->ex; + _b.ey += fa->ey - a->ey; + + // Clip destination rectangle and correct source rectangle. + *fb = fb->Intersection(_b); + fa->sx += fb->sx - _b.sx; + fa->sy += fb->sy - _b.sy; + fa->ex += fb->ex - _b.ex; + fa->ey += fb->ey - _b.ey; +} +static void WindowStretch(Rect *a, Rect *fa, Rect *b, Rect *fb) +{ + float ku = (float)b->GetWidth() / (float)a->GetWidth(), + kv = (float)b->GetHeight() / (float)a->GetHeight(); + + // Clip source rectangle and correct destination rectangle. + fa[0] = fa->Intersection(a[0]); + b->sx += (fa->sx - a->sx) * ku; + b->sy += (fa->sy - a->sy) * kv; + b->ex += (fa->ex - a->ex) * ku; + b->ey += (fa->ey - a->ey) * kv; + + // Clip destination rectangle and correct source rectangle. + fb[0] = fb->Intersection(b[0]); + ku = 1 / ku; + kv = 1 / kv; + fa->sx += (fb->sx - b->sx) * ku; + fa->sy += (fb->sy - b->sy) * kv; + fa->ex += (fb->ex - b->ex) * ku; + fa->ey += (fb->ey - b->ey) * kv; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::BlitMask(const Picture &src, Picture &dst, Picture &msk, const Rect *src_rect, const Rect *dst_rect) +{ + if (!src.GetData() || !dst.GetData()) + return false; + + // Default blit rectangles. + Rect default_a(src.GetRect()), default_b(dst.GetRect()); + if (!src_rect) + src_rect = &default_a; + if (!dst_rect) + dst_rect = &default_b; + + // Compute blit window. + Rect frame_a(src.GetRect()), frame_b(dst.GetRect()); + WindowClip(src_rect, &frame_a, dst_rect, &frame_b); + + // Limit to mask dimensions. + if (frame_b.GetWidth() > (int)msk.GetWidth()) + frame_b.SetWidth(msk.GetWidth()); + if (frame_b.GetHeight() > (int)msk.GetHeight()) + frame_b.SetHeight(msk.GetHeight()); + + if ((frame_b.GetWidth() <= 0) || (frame_b.GetHeight() <= 0)) + return false; + + PixelFormatDescription initial = dst.GetPixelFormat().GetDesc(); + dst.Convert(src.GetPixelFormat().GetDesc()); + + // Perform blit. + uchar *psrc = src.GetDataOffset(frame_a.sx, frame_a.sy), + *pdst = dst.GetDataOffset(frame_b.sx, frame_b.sy), + *pmsk = msk.GetData(); + + for (int n = 0; n < frame_b.GetHeight(); n++) + { + uchar *_pdst = pdst, *_psrc = psrc, *_pmsk = pmsk; + + for (int x = frame_b.GetWidth(); x--; ) + { + uchar alpha = _pmsk[3]; + + uchar a_blend = AlphaCompositeAlpha(_pdst[3], alpha); + _pdst[0] = AlphaCompositeColor(_pdst[0], _psrc[0], _pdst[3], alpha, a_blend); + _pdst[1] = AlphaCompositeColor(_pdst[1], _psrc[1], _pdst[3], alpha, a_blend); + _pdst[2] = AlphaCompositeColor(_pdst[2], _psrc[2], _pdst[3], alpha, a_blend); + _pdst[3] = a_blend; + + _psrc += 4; + _pdst += 4; + _pmsk += 4; + } + + psrc += src.GetPitch(); + pdst += dst.GetPitch(); + pmsk += msk.GetPitch(); + } + dst.Convert(initial); + return true; +} +bool Picture::Blit(const Picture &src, Picture &dst, const Rect *src_rect, const Rect *dst_rect, BlendMode mode) +{ + if (!src.GetData() || !dst.GetData()) + return false; + + // Default blit rectangles. + Rect default_a(src.GetRect()), default_b(dst.GetRect()); + if (!src_rect) + src_rect = &default_a; + if (!dst_rect) + dst_rect = &default_b; + + // Compute blit window. + Rect frame_a(src.GetRect()), frame_b(dst.GetRect()); + WindowClip(src_rect, &frame_a, dst_rect, &frame_b); + + if ((frame_b.GetWidth() <= 0) || (frame_b.GetHeight() <= 0)) + return false; + + PixelFormatDescription initial = dst.GetPixelFormat().GetDesc(); + dst.Convert(src.GetPixelFormat().GetDesc()); + + // Perform blit. + uchar *psrc = src.GetDataOffset(frame_a.sx, frame_a.sy), + *pdst = dst.GetDataOffset(frame_b.sx, frame_b.sy); + + for (int n = 0; n < frame_b.GetHeight(); n++) + { + uchar *_pdst = pdst, *_psrc = psrc; + + switch (mode) + { + case RgbToAlpha: + for (int x = frame_b.GetWidth(); x--; ) + { + _pdst[3] = (_psrc[0] + _psrc[1] + _psrc[2]) / 3; + _psrc += 4; + _pdst += 4; + } + break; + + case BlendReplace: + memmove(pdst, psrc, frame_b.GetWidth() * dst.GetBpp() / 8); + break; + + case BlendComposeFast: + for (int x = frame_b.GetWidth(); x--; ) + { + int a = _psrc[3], ia = 255 - a; + _pdst[0] = uchar((_psrc[0] * a + _pdst[0] * ia) >> 8); + _pdst[1] = uchar((_psrc[1] * a + _pdst[1] * ia) >> 8); + _pdst[2] = uchar((_psrc[2] * a + _pdst[2] * ia) >> 8); + _pdst[3] = uchar(Types::Max (_pdst[3], a)); + + _psrc += 4; + _pdst += 4; + } + break; + + case BlendCompose: + for (int x = frame_b.GetWidth(); x--; ) + { + uchar a_blend = AlphaCompositeAlpha(_pdst[3], _psrc[3]); + _pdst[0] = AlphaCompositeColor(_pdst[0], _psrc[0], _pdst[3], _psrc[3], a_blend); + _pdst[1] = AlphaCompositeColor(_pdst[1], _psrc[1], _pdst[3], _psrc[3], a_blend); + _pdst[2] = AlphaCompositeColor(_pdst[2], _psrc[2], _pdst[3], _psrc[3], a_blend); + _pdst[3] = a_blend; + + _psrc += 4; + _pdst += 4; + } + break; + + default: break; + } + psrc += src.GetPitch(); + pdst += dst.GetPitch(); + } + dst.Convert(initial); + return true; +} +bool Picture::ScaleBlit(Picture &src, Picture &dst, Rect *src_rect, Rect *dst_rect) +{ + if (!src.GetData() || !dst.GetData()) + return false; + + // Default blitting rectangles. + Rect default_a(src.GetRect().AsFloat()), default_b(dst.GetRect().AsFloat()); + if (!src_rect) + src_rect = &default_a; + if (!dst_rect) + dst_rect = &default_b; + + Rect frame_a(src.GetRect().AsFloat()), frame_b(dst.GetRect().AsFloat()); + WindowStretch(src_rect, &frame_a, dst_rect, &frame_b); + + if ((frame_b.GetWidth() <= 0) || (frame_b.GetHeight() <= 0)) + return false; + + // Apply sub-pixel/sub-texel correction. + float ku = frame_a.GetWidth() / frame_b.GetWidth(), + kv = frame_a.GetHeight() / frame_b.GetHeight(); + + float fb_isx = Math::Floor(frame_b.sx), + fb_isy = Math::Floor(frame_b.sy), + fb_iex = Math::Floor(frame_b.ex), + fb_iey = Math::Floor(frame_b.ey); + + float dt_su = (frame_b.sx - fb_isx), + dt_sv = (frame_b.sy - fb_isy), + dt_eu = (frame_b.ex - fb_iex), + dt_ev = (frame_b.ey - fb_iey); + + frame_a.sx -= dt_su * ku; + frame_a.sy -= dt_sv * kv; + frame_a.ex -= dt_eu * ku; + frame_a.ey -= dt_ev * kv; + + frame_b.sx = fb_isx; + frame_b.sy = fb_isy; + frame_b.ex = fb_iex; + frame_b.ey = fb_iey; + + // Convert sub pixel deltas to blending coefficients. + dt_su = 1 - dt_su; + dt_sv = 1 - dt_sv; + + uint *pdst = (uint *)dst.GetDataOffset((uint)frame_b.sx, (uint)frame_b.sy); + + int src_width = (int)frame_b.GetWidth(), + src_height = (int)frame_b.GetHeight(); + + float v = frame_a.sy; + for (int y = 0; y < src_height; y++) + { + float u = frame_a.sx; + + // Blended or opaque scanline. + if ((!y) || (y == (src_height - 1))) + { + float kfrst, kscan, klast; + + // Set blend coefficients. + if (!y) + { + kfrst = dt_su * dt_sv; // top-left + kscan = dt_sv; // top + klast = dt_eu * dt_sv; // top-right + } + else + { + kfrst = dt_su * dt_ev; // bottom-left + kscan = dt_ev; // bottom + klast = dt_eu * dt_ev; // bottom-right + } + + // 1st pixel, scanline, last pixel. + pdst[0] = ColorBlend(pdst[0], src.SampleInteger(u, v), kfrst); + u += ku; + + int x; + for (x = 1; x < (src_width - 1); x++) + { + pdst[x] = ColorBlend(pdst[x], src.SampleInteger(u, v), kscan); + u += ku; + } + pdst[x] = ColorBlend(pdst[x], src.SampleInteger(u, v), klast); + } + else + { + pdst[0] = ColorBlend(pdst[0], src.SampleInteger(u, v), dt_su); + u += ku; + + int x; + for (x = 1; x < (src_width - 1); x++) + { + pdst[x] = src.SampleInteger(u, v); + u += ku; + } + pdst[x] = ColorBlend(pdst[x], src.SampleInteger(u, v), dt_eu); + } + + pdst += dst.GetWidth(); + v += kv; + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_bmp.cpp b/include/framework/picture/pict_bmp.cpp new file mode 100644 index 0000000..cc0b17e --- /dev/null +++ b/include/framework/picture/pict_bmp.cpp @@ -0,0 +1,137 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "picture/pict.h" + #include "picture/pict_io.h" + #include "log/log.h" + + using namespace GS; + + #define IMGBMP_BI_RGB 0 + #define IMGBMP_BI_RLE8 1 + #define IMGBMP_BI_RLE4 2 + + +//----------------------------------------------------------------------------- +bool PictureIO::BmpLoad(Picture &picture, IO::Handle &handle) +{ + handle.Rewind(); + size_t size = handle.GetSize(); + if (size < 10) + return false; + + // Magic number + if ((handle.Read () != 'B') || (handle.Read () != 'M')) + return false; + + handle.Seek(8); + uint OffBits = handle.Read (), width, height; + ushort bpp; + + if (handle.Read () == 40) // we met a BITMAPCOREHEADER + { + width = handle.Read (); + height = handle.Read (); + } + else // we met a BITMAPINFOHEADER + { + width = handle.Read (); + height = handle.Read (); + } + handle.Seek(2); + bpp = handle.Read (); + + if ((bpp != 8) && (bpp != 24) && (bpp != 32)) + __ERR__(__LOG_E__ << "BMP format unhandled (neither RGB8, RGB24 or BGR8).\n", false) + + // Decode bitmap data. + if (!picture.AllocAs(width, height, PixelFormat::BGR8)) + __ERR__(__LOG_E__ << "Failed to allocate output buffer.\n", false) + + uint *rgb = (uint *)picture.GetData(); + Array bmp(size - OffBits); + if (!bmp) + __ERR__(__LOG_E__ << "Failed to allocate input framebuffer.\n", false) + + uchar *_bmp = &bmp[0]; + handle.Seek(OffBits, GS::IO::Base::SeekStart); + handle.Read((void *)_bmp, OffBits); + + rgb += (picture.GetHeight() - 1) * picture.GetWidth(); + + // Load palette + Array palette; + + if (bpp < 16) + { + __LOG__ << "Picture is palletized.\n"; + if (palette.Allocate(1 << bpp)) + { + char cbuf[4]; + handle.Seek(54, GS::IO::Base::SeekStart); + for (int n = 0; n < (1 << bpp); ++n) + { + handle.Read(cbuf, 4); + palette[n] = (cbuf[3] << 24) + (cbuf[2] << 16) + (cbuf[1] << 8) + cbuf[0]; + } + } + else + __ERR__(__LOG_E__ << "Failed to allocate palette.\n", false) + } + + // Even width + switch (bpp) + { + case 8: + { + // 32 bit 0 padding. + uint pad = 0; + if (picture.GetWidth() & 3) + pad = 4 - (picture.GetWidth() & 3); + + for (uint c2 = 0; c2 < picture.GetHeight(); c2++) + { + for (uint c = 0; c < picture.GetWidth(); c++) + rgb[c] = palette[*_bmp++]; + _bmp += pad; + rgb -= picture.GetWidth(); + } + } + break; + + case 16: + break; + + case 24: + for (uint c2 = 0; c2 < picture.GetHeight(); c2++) + { + for (uint c = 0; c < picture.GetWidth(); c++) + { + rgb[c] = (_bmp[2] << 16) + (_bmp[1] << 8) + _bmp[0]; + _bmp += 3; + } + uint dt = 3 * picture.GetWidth(); + if (dt & 3) + _bmp += (4 - (dt & 3)); + rgb -= picture.GetWidth(); + } + break; + + case 32: + for (uint c2 = 0; c2 < picture.GetHeight(); c2++) + { + for (uint c = 0; c < picture.GetWidth(); c++) + { + rgb[c] = (_bmp[2] << 16) + (_bmp[1] << 8) + _bmp[0]; + _bmp += 4; + } + rgb -= picture.GetWidth(); + } + break; + } + return true; +} +//----------------------------------------------------------------------------- diff --git a/include/framework/picture/pict_color_format.cpp b/include/framework/picture/pict_color_format.cpp new file mode 100644 index 0000000..50e03dc --- /dev/null +++ b/include/framework/picture/pict_color_format.cpp @@ -0,0 +1,333 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict_color_format.h" + #include "picture/pict.h" + #include "math/nmath.h" + #include "sort/sort.h" + #include "memory/endian.h" + #include "log/log.h" + + using namespace GS; + + +PixelFormatDescription PixelFormat::NONE + = {PixelColorSpace_NULL, 0, 0, 0, 0, 0, false}; +PixelFormatDescription PixelFormat::BGRA8 + = {PixelColorSpace_RGB, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 32, false}; +PixelFormatDescription PixelFormat::RGBA8 + = {PixelColorSpace_RGB, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 32, false}; +PixelFormatDescription PixelFormat::ARGB8 + = {PixelColorSpace_RGB, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, 32, false}; +PixelFormatDescription PixelFormat::BGR8 + = {PixelColorSpace_RGB, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 24, false}; +PixelFormatDescription PixelFormat::RGB8 + = {PixelColorSpace_RGB, 0, 0x000000ff, 0x0000ff00,0x00ff0000, 24, false}; +PixelFormatDescription PixelFormat::RGB555 + = {PixelColorSpace_RGB, 0, 0x0000001f, 0x000003e0, 0x00007c00, 16, false}; +PixelFormatDescription PixelFormat::RGB565 + = {PixelColorSpace_RGB, 0, 0x0000001f, 0x000007e0, 0x0000f800, 16, false}; +PixelFormatDescription PixelFormat::RGBA4444 + = {PixelColorSpace_RGB, 0x0000f000, 0x0000000f, 0x000000f0, 0x00000f00, 16, false}; +PixelFormatDescription PixelFormat::RGBF += { PixelColorSpace_RGB, 0, 0, 1, 2, sizeof(float) * 3 * 8, true }; +PixelFormatDescription PixelFormat::RGBAF += { PixelColorSpace_RGB, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 4 * 16, true }; + +//------------------------------------------------------------------------------ +String PixelFormat::GetName() const +{ + // Sort components. + uint count[4] = { Memory::GetBitCount(desc.rmask), Memory::GetBitCount(desc.gmask), Memory::GetBitCount(desc.bmask), Memory::GetBitCount(desc.amask) }, + shift[4] = { Memory::GetShiftCount(desc.rmask), Memory::GetShiftCount(desc.gmask), Memory::GetShiftCount(desc.bmask), Memory::GetShiftCount(desc.amask) }; + + Sort::Entry comp_sort[4]; + for (uint n = 0; n < 4; ++n) + { + comp_sort[n].v = shift[n]; + comp_sort[n].o = n; + } + Sort::QuickSort(4, comp_sort); + + // Build name. + static const char *comp_name[4] = {"R", "G", "B", "A"}; + + String name; + switch (desc.space) + { + case PixelColorSpace_RGB: + { + for (uint n = 0; n < 4; ++n) + { + int i = comp_sort[n].o; + if (count[i] != 0) + { + name += String::Format("%s%d", comp_name[i], count[i]); + if (desc.real) + name += "F"; + } + } + } + break; + + default: + name = "NONE"; + break; + } + return name; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint PixelFormat::Format(float r, float g, float b, float a) const +{ + switch (GetBpp()) + { + case 32: + return Endian::ToHost((int(r * 255) << rshift) + (int(g * 255) << gshift) + (int(b * 255) << bshift) + (int(a * 255) << ashift), Endian::Intel); + + default: + __LOG_W__ << "Unimplemented formatting.\n"; + } + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::Negative(bool r, bool g, bool b, bool a) +{ + if ((GetBpp() != 32) || (!r && !g && !b && !a) || !GetData()) + return; + + int iia = pxformat.ashift >> 3, + iir = pxformat.rshift >> 3, + iig = pxformat.gshift >> 3, + iib = pxformat.bshift >> 3; + + unsigned char *p = GetData(); + for (uint v = 0; v < height; ++v) + for (uint u = 0; u < width; ++u) + { + if (r) p[iir] = 255 - p[iir]; + if (g) p[iig] = 255 - p[iig]; + if (b) p[iib] = 255 - p[iib]; + if (a) p[iia] = 255 - p[iia]; + p += 4; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::Fast8888Conversion(const PixelFormat &dsformat) +{ + int iia = pxformat.ashift >> 3, + iir = pxformat.rshift >> 3, + iig = pxformat.gshift >> 3, + iib = pxformat.bshift >> 3, + dia = dsformat.ashift >> 3, + dir = dsformat.rshift >> 3, + dig = dsformat.gshift >> 3, + dib = dsformat.bshift >> 3; + + unsigned char *p = GetData(); + if (!p) + return false; + + // Optimized for the most common reorganizing done on 8888 ARGB data. + unsigned char r, g, b, a; + if (iia == dia) + { + if (iig == dig) // Fixed green & alpha. + for (uint v = 0; v < GetHeight(); ++v) + for (uint u = 0; u < GetWidth(); ++u) + { + r = p[iir]; b = p[iib]; + p[dir] = r; p[dib] = b; + p += 4; + } + else // Fixed alpha. + for (uint v = 0; v < GetHeight(); ++v) + for (uint u = 0; u < GetWidth(); ++u) + { + r = p[iir]; g = p[iig]; b = p[iib]; + p[dir] = r; p[dig] = g; p[dib] = b; + p += 4; + } + } + else // Fully generic. + for (uint v = 0; v < GetHeight(); ++v) + for (uint u = 0; u < GetWidth(); ++u) + { + a = p[iia]; r = p[iir]; g = p[iig]; b = p[iib]; + p[dia] = a; p[dir] = r; p[dig] = g; p[dib] = b; + p += 4; + } + + pxformat = dsformat; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::RealToIntegerConversion(const PixelFormat &dstfmt) +{ + uchar *new_data = new uchar[width * height * (dstfmt.GetBpp() / 8)]; + if (!new_data) + return false; + + uchar *out = new_data; + float *pdata = (float *)GetData(); + + // Convert. + for (uint y = 0; y < GetHeight(); ++y) + for (uint x = 0; x < GetWidth(); ++x) + { + uchar r = (uchar)Types::Min(pdata[2] * 255.f, 255.f), g = (uchar)Types::Min(pdata[1] * 255.f, 255.f), b = (uchar)Types::Min(pdata[0] * 255.f, 255.f), a = 255; + pdata += 3; + + // Convert components. + a >>= (8 - dstfmt.acount); + r >>= (8 - dstfmt.rcount); + g >>= (8 - dstfmt.gcount); + b >>= (8 - dstfmt.bcount); + + // Repack components and output. + uint packed; + uchar *ppack = (uchar *)&packed; + + packed = (a << dstfmt.ashift) + (r << dstfmt.rshift) + (g << dstfmt.gshift) + (b << dstfmt.bshift); + + switch (dstfmt.GetBpp()) + { + case 8: out[0] = ppack[0]; out++; break; + case 16: out[0] = ppack[0]; out[1] = ppack[1]; out += 2; break; + case 24: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out += 3; break; + case 32: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out[3] = ppack[3]; out += 4; break; + } + } + + // Replace data. + SetData(new_data, width, height, dstfmt.GetDesc()); + return true; +} +bool Picture::IntegerToIntegerConversion(const PixelFormat &dsformat) +{ + switch (pxformat.GetBpp()) + { + case 8: case 16: case 24: case 32: break; + default: return false; // Unsupported source mode. + } + + // Allocate destination buffer. + uchar *new_data = new uchar[width * height * (dsformat.GetBpp() / 8)]; + if (!new_data) + return false; + + uchar *out = new_data; + uchar *pdata = GetData(); + + // Convert. + for (uint y = 0; y < GetHeight(); ++y) + { + uint packed; + uchar *ppack = (uchar *)&packed; + + for (uint x = 0; x < GetWidth(); ++x) + { + // Extract packed color. + switch (pxformat.GetBpp()) + { + case 8: ppack[0] = pdata[0]; pdata++; break; + case 16: ppack[0] = pdata[0]; ppack[1] = pdata[1]; pdata += 2; break; + case 24: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; pdata += 3; break; + case 32: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; ppack[3] = pdata[3]; pdata += 4; break; + } + + // Extract components. + uint a = (uchar)(((packed & pxformat.desc.amask) >> pxformat.ashift) << (8 - pxformat.acount)), + r = (uchar)(((packed & pxformat.desc.rmask) >> pxformat.rshift) << (8 - pxformat.rcount)), + g = (uchar)(((packed & pxformat.desc.gmask) >> pxformat.gshift) << (8 - pxformat.gcount)), + b = (uchar)(((packed & pxformat.desc.bmask) >> pxformat.bshift) << (8 - pxformat.bcount)); + + // Convert components. + a >>= (8 - dsformat.acount); + r >>= (8 - dsformat.rcount); + g >>= (8 - dsformat.gcount); + b >>= (8 - dsformat.bcount); + + // Repack components and output. + packed = Endian::ToHost((a << dsformat.ashift) + (r << dsformat.rshift) + (g << dsformat.gshift) + (b << dsformat.bshift), Endian::Intel); + + switch (dsformat.GetBpp()) + { + case 8: out[0] = ppack[0]; out++; break; + case 16: out[0] = ppack[0]; out[1] = ppack[1]; out += 2; break; + case 24: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out += 3; break; + case 32: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out[3] = ppack[3]; out += 4; break; + } + } + } + + // Replace data. + SetData(new_data, width, height, dsformat.GetDesc(), true); + return true; +} +bool Picture::Convert(const PixelFormatDescription &dsc) +{ + if (pxformat == dsc) + return true; + + if (!dsc.bpp) + { + Free(); + return true; + } + + PixelFormat dsformat(dsc); + + // Real to integer. + if (pxformat.IsReal()) + return RealToIntegerConversion(dsformat); + + // Fast 8888 conversion. + if ( + (pxformat.acount == 8) && (pxformat.rcount == 8) && (pxformat.gcount == 8) && (pxformat.bcount == 8) && + (dsformat.acount == 8) && (dsformat.rcount == 8) && (dsformat.gcount == 8) && (dsformat.bcount == 8) + ) + return Fast8888Conversion(dsformat); + + // Slower generic integer->integer conversion. + return IntegerToIntegerConversion(dsformat); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::Swizzle(uchar r, uchar g, uchar b, uchar a) +{ + // Swizzle output format... + PixelFormatDescription out_format = GetPixelFormat().GetDesc(); + + const uint in_mask[4] = { out_format.rmask, out_format.gmask, out_format.bmask, out_format.amask }; + out_format.rmask = in_mask[r]; + out_format.gmask = in_mask[g]; + out_format.bmask = in_mask[b]; + out_format.amask = in_mask[a]; + + // ...and convert picture. + return Convert(out_format); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::SetFormat(const PixelFormatDescription &dsc) +{ + if (dsc.bpp != pxformat.GetDesc().bpp) + __ERR__(__LOG_E__ << "Target format requires a data conversion, see Convert().\n", false) + + pxformat.Set(dsc); + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_convolution.cpp b/include/framework/picture/pict_convolution.cpp new file mode 100644 index 0000000..b0eab72 --- /dev/null +++ b/include/framework/picture/pict_convolution.cpp @@ -0,0 +1,94 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + #include "color/color.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool Picture::ApplyConvolution(uint k_width, uint k_height, const int *p_w, int weight, int pass, const Rect *clip_rect) +{ + if (GetBpp() != 32) + __ERR__(__LOG_E__ << "Convolution filter only supported on 32bpp picture.\n", false); + if (!k_width || !k_height) + __ERR__(__LOG_E__ << "Invalid kernel size (" << k_width << "x" << k_height << ").\n", false); + + if (pass <= 0) + return true; + + // Clipping rect. + Rect rect = GetRect(); + if (!clip_rect) + clip_rect = ▭ + + // Setup flip chain. + Picture tmp(*this), *src, *dst; + + if (pass & 1) + { src = &tmp; dst = this; } + else { src = this; dst = &tmp; } + + // Perform convolution. + for (int p = 0; p < pass; ++p) + { + uchar *pdata = dst->GetDataOffset(clip_rect->sx, clip_rect->sy); + + for (int y = 0; y < clip_rect->GetHeight(); ++y) + { + uchar *pscan = pdata; + + for (int x = 0; x < rect.GetWidth(); ++x) + { + int sx = x - k_width / 2, + sy = y - k_height / 2; + + int k_sx = Types::Max (sx, clip_rect->sx), + k_sy = Types::Max (sy, clip_rect->sy); + int k_ex = Types::Min (k_width + x - k_width / 2, clip_rect->ex), + k_ey = Types::Min (k_height + y - k_height / 2, clip_rect->ey); + + const int *w = p_w + Types::Max(0, clip_rect->sx - sx) + + Types::Max(0, clip_rect->sy - sy) * k_width; + + int k = 0; + int accu[4] = { 0, 0, 0, 0 }; + for (int ky = k_sy; ky < k_ey; ++ky) + { + const int *sw = w; + + for (int kx = k_sx; kx < k_ex; ++kx) + { + uchar *psrc = src->GetDataOffset(kx, ky); + + accu[0] += psrc[0] * *sw; + accu[1] += psrc[1] * *sw; + accu[2] += psrc[2] * *sw; + accu[3] += psrc[3] * *sw; + + k += *sw++; + } + w += k_width; + } + + k = k ? (weight << 6) / k : (weight << 6); + pscan[0] = (uchar)Types::Clamp((accu[0] * k) >> 14, 0, 255); + pscan[1] = (uchar)Types::Clamp((accu[1] * k) >> 14, 0, 255); + pscan[2] = (uchar)Types::Clamp((accu[2] * k) >> 14, 0, 255); + pscan[3] = (uchar)Types::Clamp((accu[3] * k) >> 14, 0, 255); + + pscan += 4; + } + pdata += dst->GetPitch(); + } + + Picture *swp = dst; dst = src; src = swp; + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_draw.cpp b/include/framework/picture/pict_draw.cpp new file mode 100644 index 0000000..4226bc1 --- /dev/null +++ b/include/framework/picture/pict_draw.cpp @@ -0,0 +1,25 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +uchar Picture::AlphaCompositeAlpha(uchar a, uchar b) +{ return (uchar)Types::Clamp (a + b - ((a * b) >> 8), 0, 255); } +uchar Picture::AlphaCompositeColor(uchar u, uchar v, uchar a, uchar b, uchar k) +{ return (uchar)Types::Clamp (k ? (u * a + v * b - ((u * b * a) >> 8)) / k : 0, 0, 255); } +void Picture::AlphaCompositePixel(uchar *data, uchar r, uchar g, uchar b, uchar a) +{ + uchar a_blend = AlphaCompositeAlpha(data[3], a); + data[0] = AlphaCompositeColor(data[0], r, data[3], a, a_blend); + data[1] = AlphaCompositeColor(data[1], g, data[3], a, a_blend); + data[2] = AlphaCompositeColor(data[2], b, data[3], a, a_blend); + data[3] = a_blend; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_draw_line.cpp b/include/framework/picture/pict_draw_line.cpp new file mode 100644 index 0000000..a882d9a --- /dev/null +++ b/include/framework/picture/pict_draw_line.cpp @@ -0,0 +1,166 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + #include "math/nmath.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Picture::LowLevelDrawLine(bool hq, float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect *clip_rect) +{ + // Output validity. + if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal()) + return; + + // Clip primitive. + float dx = ex - sx, dy = ey - sy; + + // Sub pixel correction. + if (Types::Abs(dy) > Types::Abs(dx)) + { + float fsy = Math::Floor(sy); + if (dy) + sx -= dx * (sy - fsy) / dy; // Sub-pixel correction. + sy = fsy; + } + else + { + float fsx = Math::Floor(sx); + if (dx) + sy -= dy * (sx - fsx) / dx; // Sub-pixel correction. + sx = fsx; + } + + // Clipping. + if (clip_rect) + { + //--------------------------------------------------------------- + #define __SwapFloat(A, B) { float swp = A; A = B; B = swp; } + //--------------------------------------------------------------- + + if (dx) + { + // Flip line if it is going backward. + if (dx < 0) + { + __SwapFloat(sx, ex) + __SwapFloat(sy, ey) + dx = ex - sx; dy = ey - sy; + } + float idx = 1 / dx; + + // Clip on X axis. + if (ex < clip_rect->sx) + return; + + float kee = (clip_rect->ex - sx) * idx; + if (kee < 1) + { + ex = clip_rect->ex; + ey = dy * kee + sy; + } + + if (sx > clip_rect->ex) + return; + + float kss = (clip_rect->sx - sx) * idx; + if (kss > 0) + { + sx = clip_rect->sx; + sy += dy * kss; + } + dx = ex - sx; dy = ey - sy; + } + else + if ((sx < clip_rect->sx) || (sx > clip_rect->ex)) + return; + + if (dy) + { + // Flip line if it is going backward. + if (dy < 0) + { + __SwapFloat(sx, ex) + __SwapFloat(sy, ey) + dx = ex - sx; dy = ey - sy; + } + float idy = 1 / dy; + + // Clip on Y axis. + if (ey < clip_rect->sy) + return; + + float kee = (clip_rect->ey - sy) * idy; + if (kee < 1) + { + ey = clip_rect->ey; + ex = dx * kee + sx; + } + + if (sy > clip_rect->ey) + return; + + float kss = (clip_rect->sy - sy) * idy; + if (kss > 0) + { + sy = clip_rect->sy; + sx += dx * kss; + } + dx = ex - sx; dy = ey - sy; + } + else + if ((sy < clip_rect->sy) || (sy > clip_rect->ey)) + return; + } + + // Draw line. + if (Types::Abs(dy) > Types::Abs(dx)) + { + if (dy < 0) + { + dy = -dy; dx = -dx; + float swp = ey; + ey = sy; sy = swp; sx = ex; + } + + float slope = dy ? dx / dy : 0.f; + for (; sy < ey; sy += 1.f) + { + if (hq) + DrawPlotHQ(sx, sy, r, g, b, a); + else DrawPlot(sx, sy, r, g, b, a); + sx += slope; + } + } + else + { + if (dx < 0) + { + dx = -dx; dy = -dy; + float swp = ex; + ex = sx; sx = swp; sy = ey; + } + + float slope = dx ? dy / dx : 0.f; + for (; sx < ex; sx += 1.f) + { + if (hq) + DrawPlotHQ(sx, sy, r, g, b, a); + else DrawPlot(sx, sy, r, g, b, a); + sy += slope; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::DrawLine(float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect *clip_rect) +{ LowLevelDrawLine(false, sx, sy, ex, ey, r, g, b, a, clip_rect); } +void Picture::DrawLineHQ(float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect *clip_rect) +{ LowLevelDrawLine(true, sx, sy, ex, ey, r, g, b, a, clip_rect); } +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_draw_plot.cpp b/include/framework/picture/pict_draw_plot.cpp new file mode 100644 index 0000000..ec77850 --- /dev/null +++ b/include/framework/picture/pict_draw_plot.cpp @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + #include "math/nmath.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Picture::DrawPlot(float x, float y, float r, float g, float b, float a, const Rect *clip_rect) +{ + // Output validity. + if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal()) + return; + + // Clip primitive. + if (clip_rect && ((x < clip_rect->sx) || (x >= clip_rect->ex) || (y < clip_rect->sy) || (y >= clip_rect->ey))) + return; + + // Draw. + AlphaCompositePixel(GetDataOffset((uint)x, (uint)y), uchar(r * 255.f), uchar(g * 255.f), uchar(b * 255.f), uchar(a * 255.f)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::DrawPlotHQ(float x, float y, float r, float g, float b, float a, const Rect *clip_rect) +{ + // Output validity. + if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal()) + return; + + // Clip primitive. + if (clip_rect && ((x < clip_rect->sx) || (x >= (clip_rect->ex - 1)) || (y < clip_rect->sy) || (y >= (clip_rect->ey - 1)))) + return; + + // Draw. + uchar ir = uchar(r * 255.f), + ig = uchar(g * 255.f), + ib = uchar(b * 255.f), + ia = uchar(a * 255.f); + + float xm = Math::Floor(x), + ym = Math::Floor(y); + + float a0 = (xm + 1 - x) * (ym + 1 - y), + a1 = (x - xm) * (ym + 1 - y), + a2 = (xm + 1 - x) * (y - ym), + a3 = (x - xm) * (y - ym); + + uchar *output = GetDataOffset((uint)x, (uint)y); + AlphaCompositePixel(output, ir, ig, ib, uchar(ia * a0)); + AlphaCompositePixel(output + 4, ir, ig, ib, uchar(ia * a1)); + AlphaCompositePixel(output + width * 4, ir, ig, ib, uchar(ia * a2)); + AlphaCompositePixel(output + (width + 1) * 4, ir, ig, ib, uchar(ia * a3)); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_draw_polygon.cpp b/include/framework/picture/pict_draw_polygon.cpp new file mode 100644 index 0000000..131e979 --- /dev/null +++ b/include/framework/picture/pict_draw_polygon.cpp @@ -0,0 +1,159 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + #include "math/nmath.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------- +static bool ClipValueTestLess(float v, float c) +{ return v < c; } +static bool ClipValueTestGreater(float v, float c) +{ return v >= c; } +//------------------------------------------------- + +//------------------------------------------------------------------------------ +static uint ClipPolygonAxis(float clip, uint axis, bool (*ClipValueTest)(float v, float c), uint count_in, Point *p_in, Point *p_out) +{ + uint p_current = 0, count_out = 0; + + //-------------------------------------------------------------------------------------------------------- + #define __ClipSegment\ + {\ + float k = (clip - p_in[p_current][axis]) / (p_in[p_next][axis] - p_in[p_current][axis]);\ + if (!axis)\ + p_out[count_out++].Set (clip, (p_in[p_next].y - p_in[p_current].y) * k + p_in[p_current].y);\ + else p_out[count_out++].Set ((p_in[p_next].x - p_in[p_current].x) * k + p_in[p_current].x, clip);\ + } + //-------------------------------------------------------------------------------------------------------- + + while (p_current < count_in) + { + uint p_next = p_current + 1; + if (p_next == count_in) + p_next = 0; + + if (ClipValueTest(p_in[p_current][axis], clip)) // Inside. + { + p_out[count_out++] = p_in[p_current]; + if (!ClipValueTest(p_in[p_next][axis], clip)) + __ClipSegment + } + else // Outside. + { + if (ClipValueTest(p_in[p_next][axis], clip)) + __ClipSegment + } + p_current++; + } + return count_out; +} +void Picture::DrawPolygon(uint point_count, Point *point, float r, float g, float b, float a, const Rect *clip_rect) +{ + // Output validity. + if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal()) + return; + + // Clip primitive. + Point *_point = point; + + if (clip_rect) + { + _point = new Point [128]; + if (!_point) + __ERRRAW__(__LOG_E__ << "failed to allocate polygon clipping array.\n") + + // Old boring clipping code... + Point *_point_ = _point + 64; + point_count = ClipPolygonAxis(clip_rect->sx, 0, ClipValueTestGreater, point_count, point, _point_); + point_count = ClipPolygonAxis(clip_rect->ex, 0, ClipValueTestLess, point_count, _point_, _point); + point_count = ClipPolygonAxis(clip_rect->sy, 1, ClipValueTestGreater, point_count, _point, _point_); + point_count = ClipPolygonAxis(clip_rect->ey, 1, ClipValueTestLess, point_count, _point_, _point); + + if (point_count < 3) + { + _safe_delete_array(_point); + return; + } + } + + // Determine entry vertex. + float y_scan = _point[0].y, + y_max = _point[0].y; + int p_int = 0, + p_ext = 0; + + for (uint n = 1; n < point_count; ++n) + { + if (_point[n].y < y_scan) + { + y_scan = _point[n].y; + p_int = p_ext = n; + } + if (_point[n].y > y_max) + y_max = _point[n].y; + } + + // Render scanline. + float d_int = 0, + d_ext = 0; + float x_int = _point[p_int].x, + x_ext = _point[p_int].x; + + y_scan = Math::Ceil(y_scan); + while (y_scan < y_max) + { + // Update interior pointer. + while (y_scan >= _point[p_int].y) + { + uint p_next = p_int - 1; + if (p_next == -1) + p_next = point_count - 1; + + // Update delta. + d_int = (_point[p_next].x - _point[p_int].x) / (_point[p_next].y - _point[p_int].y); + x_int = d_int * (y_scan - _point[p_int].y) + _point[p_int].x; + p_int = p_next; + } + + // Update exterior pointer. + while (y_scan >= _point[p_ext].y) + { + uint p_next = p_ext + 1; + if (p_next == point_count) + p_next = 0; + + // Update delta. + d_ext = (_point[p_next].x - _point[p_ext].x) / (_point[p_next].y - _point[p_ext].y); + x_ext = d_ext * (y_scan - _point[p_ext].y) + _point[p_ext].x; + p_ext = p_next; + } + + // Draw scanline. + { + float sx, ex; + if (x_int > x_ext) + { sx = x_ext; ex = x_int; } + else { sx = x_int; ex = x_ext; } + + for (int x = int(sx); x < int(ex); ++x) + DrawPlot((float)x, y_scan, r, g, b, a); + } + + // Step scanline boundaries. + y_scan += 1; + x_int += d_int; + x_ext += d_ext; + } + + // Release clipping point array. + if (clip_rect) + _safe_delete_array(_point); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_fft.cpp b/include/framework/picture/pict_fft.cpp new file mode 100644 index 0000000..3a6ec9e --- /dev/null +++ b/include/framework/picture/pict_fft.cpp @@ -0,0 +1,105 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "picture/pict.h" + + +//------------------------------------------------------------------------------ +void FFT(int size, bool inverse, float *inReal, float *inIm, float *outReal, float *outIm) +{ + // Calculate m = log_2(n). + int m = 0, p = 1; + for (; p < size; ++m) + p *= 2; + + // Bit reversal. + outReal[size - 1] = inReal[size - 1]; + outIm[size - 1] = inIm[size - 1]; + + int j = 0; + for (int i = 0; i < size - 1; ++i) + { + outReal[i] = inReal[j]; + outIm[i] = inIm[j]; + + int k = size / 2; + while (k <= j) + { + j -= k; + k /= 2; + } + + j += k; + } + + // Calculate the FFT. + float ca = -1.0, sa = 0.0; + int l1 = 1, l2 = 1; + + for (int l = 0; l < m; ++l) + { + l1 = l2; + l2 *= 2; + + float u1 = 1.0, u2 = 0.0; + + for(int j = 0; j < l1; j++) + { + for(int i = j; i < size; i += l2) + { + int i1 = i + l1; + + float t1 = u1 * outReal[i1] - u2 * outIm[i1], + t2 = u1 * outIm[i1] + u2 * outReal[i1]; + + outReal[i1] = outReal[i] - t1; + outIm[i1] = outIm[i] - t2; + outReal[i] += t1; + outIm[i] += t2; + } + + double z = u1 * ca - u2 * sa; + u2 = u1 * sa + u2 * ca; + u1 = (float)z; + } + + sa = (float)sqrt((1.f - ca) / 2.f); + if (!inverse) + sa = -sa; + ca = (float)sqrt((1.f + ca) / 2.f); + } + + // Divide through n if it isn't the IDFT. + if (!inverse) + for (int i = 0; i < size; ++i) + { + outReal[i] /= size; + outIm[i] /= size; + } +} + +void testFFT() +{ + float inR[8], inI[8], outR[8], outI[8]; + + for (int n = 0; n < 8; ++n) + { + inR[n] = 5; + inI[n] = 2; + } + + FFT(8, false, inR, inI, outR, outI); + + for (int n = 0; n < 8; ++n) + { + inR[n] = 0; + inI[n] = 0; + } + + FFT(8, true, outR, outI, inR, inI); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_gradient.cpp b/include/framework/picture/pict_gradient.cpp new file mode 100644 index 0000000..532a603 --- /dev/null +++ b/include/framework/picture/pict_gradient.cpp @@ -0,0 +1,184 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict_gradient.h" + #include "picture/pict.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +static uchar ClampChannel(int v) +{ + if (v < 0) + return 0; + if (v > 255) + return 255; + return (uchar)v; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::DrawGradient(const Gradient &gradient, const Rect *clip_rect) +{ + if (!gradient.GetControlPointCount()) + return; + + Rect rect = GetRect(); + if (!clip_rect) + clip_rect = ▭ + + uint current_control_point = 0, + next_control_point = 1; + if (next_control_point == gradient.GetControlPointCount()) + next_control_point = current_control_point; + uchar *pdata = GetDataOffset(clip_rect->sx, clip_rect->sy); + + for (int y = 0; y < clip_rect->GetHeight(); ++y) + { + float c_k = (float)y / clip_rect->GetHeight(); + + // Check gradient interval change. + if ((c_k > gradient.k[next_control_point]) && (current_control_point + 1 < gradient.GetControlPointCount())) + { + current_control_point++; + next_control_point++; + if (next_control_point == gradient.GetControlPointCount()) + next_control_point = current_control_point; + } + + // Blend. + Color blend_color = gradient.color[current_control_point]; + + if (current_control_point != next_control_point) + blend_color = (gradient.color[next_control_point] - gradient.color[current_control_point]) * + (c_k - gradient.k[current_control_point]) / (gradient.k[next_control_point] - gradient.k[current_control_point]) + + gradient.color[current_control_point]; + + uchar *pscan = pdata, + r = (uchar)(blend_color.x * 255), + g = (uchar)(blend_color.y * 255), + b = (uchar)(blend_color.z * 255), + a = (uchar)(blend_color.w * 255); + + switch (gradient.GetOperator()) + { + case Picture::BlendReplace: + for (int x = 0; x < rect.GetWidth(); ++x) + { + pscan[0] = r; + pscan[1] = g; + pscan[2] = b; + pscan[3] = a; + pscan += 4; + } + break; + + case Picture::BlendCompose: + for (int x = 0; x < rect.GetWidth(); ++x) + { + uchar a_blend = AlphaCompositeAlpha(pscan[3], a); + pscan[0] = AlphaCompositeColor(pscan[0], r, pscan[3], a, a_blend); + pscan[1] = AlphaCompositeColor(pscan[1], g, pscan[3], a, a_blend); + pscan[2] = AlphaCompositeColor(pscan[2], b, pscan[3], a, a_blend); + pscan[3] = a_blend; + pscan += 4; + } + break; + + case Picture::BlendMultiply: + for (int x = 0; x < rect.GetWidth(); ++x) + { + pscan[0] = (pscan[0] * r) >> 8; + pscan[1] = (pscan[1] * g) >> 8; + pscan[2] = (pscan[2] * b) >> 8; + pscan[3] = (pscan[3] * a) >> 8; + pscan += 4; + } + break; + + case Picture::BlendMultiply2x: + for (int x = 0; x < rect.GetWidth(); ++x) + { + pscan[0] = ClampChannel((pscan[0] * r) >> 7); + pscan[1] = ClampChannel((pscan[1] * g) >> 7); + pscan[2] = ClampChannel((pscan[2] * b) >> 7); + pscan[3] = (pscan[3] * a) >> 8; + pscan += 4; + } + break; + + case Picture::BlendAdd: + for (int x = 0; x < rect.GetWidth(); ++x) + { + pscan[0] = ClampChannel(pscan[0] + r); + pscan[1] = ClampChannel(pscan[1] + g); + pscan[2] = ClampChannel(pscan[2] + b); + pscan[3] = (pscan[3] * a) >> 8; + pscan += 4; + } + break; + + default: break; + } + pdata += GetPitch(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Gradient::FromMetaTag(NML::Tag *tag) +{ + control_point_count = 0; + op = Picture::BlendMultiply; + + NMLTagForeach(ctag, *tag) + { + if (ctag->name == "Operator") + { + String op_string(ctag->GetString()); + + if (op_string == "Replace") + op = Picture::BlendReplace; + else if (op_string == "Multiply") + op = Picture::BlendMultiply; + else if (op_string == "Multiply2x") + op = Picture::BlendMultiply2x; + else if (op_string == "Add") + op = Picture::BlendAdd; + else if (op_string == "Compose") + op = Picture::BlendCompose; + else __LOG_W__ << "Unknown gradient operator.\n"; + } + else if (ctag->name == "Control") + { + // Control point count safety. + if (control_point_count == 8) + __ERR__(__LOG_E__ << "Too many control points in gradient definition.\n", false); + + // Coordinate. + NML::Tag *attr_tag = ctag->GetTypedTag("K", Variant::VariantFloat); + if (!attr_tag) + __ERR__(__LOG_E__ << "Missing tag (control point coordinate) in gradient definition.\n", false); + k[control_point_count] = attr_tag->GetReal(); + + // Color. + attr_tag = ctag->GetTypedTag("Color", Variant::VariantNone); + if (!attr_tag) + __ERR__(__LOG_E__ << "Missing tag (control point color) in gradient definition.\n", false); + color[control_point_count].Set(); + if (!color[control_point_count].FromMetaTag(*attr_tag)) + __ERR__(__LOG_E__ << "Erroneous control point color in gradient definition.\n", false); + + control_point_count++; + } + else __ERR__(__LOG_E__ << "Unexpected tag in gradient definition.\n", false); + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_io.cpp b/include/framework/picture/pict_io.cpp new file mode 100644 index 0000000..3ef8866 --- /dev/null +++ b/include/framework/picture/pict_io.cpp @@ -0,0 +1,70 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict_io.h" + #include "picture/pict.h" + #include "filesystem/io_handle.h" + #include "filesystem/filesystem.h" + #include "memory/nauto_ptr.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::IO; + + template<> PictureIO *Singleton ::i = NULL; + + +//------------------------------------------------------------------------------ +PictureCodec *PictureIO::Codec(const char *codec_name) +{ + ListForeachPtr(PictureCodec *, codec, codec_list) + if (GS::String(codec->GetName()) == GS::String(codec_name)) + return codec; + return NULL; +} +bool PictureIO::RegisterCodec(PictureCodec *codec, bool verbose) +{ + if (Codec(codec->GetName())) + return false; + codec_list.Add(codec); + if (verbose) + __LOG__ << "Codec '" << codec->GetName() << "' registered successfully.\n"; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool PictureIO::Save(const Picture &picture, const char *uri, const char *codec_name) +{ + if (PictureCodec *c = Codec(codec_name)) + { + AutoPtr h(Platform::Get().io->Open(uri, ModeWrite)); + if (h.IsNull()) + return false; + + if (!c->Save(*h, picture)) + return false; + } + else + return false; + + return true; +} +bool PictureIO::Load(Picture &picture, const char *uri) +{ + AutoPtr h(Platform::Get().io->Open(uri)); + if (h.IsNull()) + return false; + + picture.name = uri; + ListForeachPtr(PictureCodec *, codec, codec_list) + if (codec->Load(*h, picture)) + return true; + + return false; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_sampling.cpp b/include/framework/picture/pict_sampling.cpp new file mode 100644 index 0000000..f357eab --- /dev/null +++ b/include/framework/picture/pict_sampling.cpp @@ -0,0 +1,183 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + #include "color/color.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Picture::Sample(float u, float v, Color &out, uint _w, uint _h) const +{ + if (!GetData()) + { + out.Set(1, 0, 1); + return; + } + + if (!GetPixelFormat().IsReal()) + { + uint _out; + Sample(u, v, _out, _w, _h); + out.FromInteger(_out); + } + else + { + if (!_w) _w = GetWidth(); + if (!_h) _h = GetHeight(); + u *= _w; v *= _h; + + if (u < 0) u = 0; + if (v < 0) v = 0; + if (u >= _w) u = (float)(_w - 1); + if (v >= _h) v = (float)(_h - 1); + + uint iu = (uint)u, iv = (uint)v; + + Color sample[4]; + + float *pdata = (float *)GetData(); + pdata += (iu + iv * _w) * 3; + + //--------------------------------------- + #define EXTRACT_FSAMPLE(_S_, _P_) \ + { \ + (_S_).z = (_P_)[2]; \ + (_S_).y = (_P_)[1]; \ + (_S_).x = (_P_)[0]; \ + } + //--------------------------------------- + + EXTRACT_FSAMPLE(sample[0], pdata + 0); + if (iu < (_w - 1)) + EXTRACT_FSAMPLE(sample[1], pdata + 3) + else sample[1] = sample[0]; + if (iv < (_h - 1)) + EXTRACT_FSAMPLE(sample[2], pdata + _w * 3) + else sample[2] = sample[0]; + if ((iu < (_w - 1)) && (iv < (_h - 1))) + EXTRACT_FSAMPLE(sample[3], pdata + (_w + 1) * 3) + else sample[3] = sample[0]; + + // Bilinear sample. + float k[4], uf = u - (float)iu, vf = v - (float)iv; + + k[0] = (1.f - uf) * (1.f - vf); + k[1] = uf * (1.f - vf); + k[2] = (1.f - uf) * vf; + k[3] = uf * vf; + + out = sample[0] * k[0] + sample[1] * k[1] + sample[2] * k[2] + sample[3] * k[3]; + out.w = sample[0].w * k[0] + sample[1].w * k[1] + sample[2].w * k[2] + sample[3].w * k[3]; + } +} +void Picture::Sample(float u, float v, uint &out, uint _w, uint _h) const +{ + if (!GetData()) + { + out = 0xffff00ff; + return; + } + + if (GetPixelFormat().IsReal()) + { + Color _out; + Sample(u, v, _out, _w, _h); + out = _out.AsInteger(); + } + else + { + if (!_w) _w = GetWidth(); + if (!_h) _h = GetHeight(); + u *= _w; v *= _h; + + if (u < 0) u = 0; + if (v < 0) v = 0; + if (u >= _w) u = (float)(_w - 1); + if (v >= _h) v = (float)(_h - 1); + + uint iu = (uint)u, iv = (uint)v; + + struct iVector + { + int x, y, z, w; + + iVector operator + (const iVector &b) const + { return iVector(x + b.x, y + b.y, z + b.z, w + b.w); } + iVector operator * (const int v) const + { return iVector(x * v, y * v, z * v, w * v); } + iVector operator >> (const int v) const + { return iVector(x >> v, y >> v, z >> v, w >> v); } + + iVector(int _x, int _y, int _z, int _w = 255) + { x = _x; y = _y; z = _z; w = _w; } + iVector() + {} + }; + iVector sample[4]; + + uint *pdata = (uint *)GetData(); + pdata += iu + iv * _w; + + //---------------------------------------------------------------------- + #define EXTRACT_SAMPLE(_S_, _P_) \ + { \ + const uchar *_t_p = (const uchar *)&(_P_); \ + (_S_).x = _t_p[0]; \ + (_S_).y = _t_p[1]; \ + (_S_).z = _t_p[2]; \ + (_S_).w = _t_p[3]; \ + } + //---------------------------------------------------------------------- + + EXTRACT_SAMPLE(sample[0], pdata[0]); + if (iu < (_w - 1)) + EXTRACT_SAMPLE(sample[1], pdata[1]) + else sample[1] = sample[0]; + if (iv < (_h - 1)) + EXTRACT_SAMPLE(sample[2], pdata[_w]) + else sample[2] = sample[0]; + if ((iu < (_w - 1)) && (iv < (_h - 1))) + EXTRACT_SAMPLE(sample[3], pdata[_w + 1]) + else sample[3] = sample[0]; + + int k[4], uf = int((u - (float)iu) * 256), vf = int((v - (float)iv) * 256); + + k[0] = (256 - uf) * (256 - vf); // 16bit fixed point. + k[1] = uf * (256 - vf); + k[2] = (256 - uf) * vf; + k[3] = uf * vf; + + iVector r = (sample[0] * k[0] + sample[1] * k[1] + sample[2] * k[2] + sample[3] * k[3]) >> 16; + + uchar *_out = (uchar *)&out; + _out[0] = (uchar)r.x; + _out[1] = (uchar)r.y; + _out[2] = (uchar)r.z; + _out[3] = (uchar)r.w; + } +} +void Picture::SampleRGBA(float u, float v, Color &o, uint _w, uint _h) const +{ + Color s; + Sample(u, v, s, _w, _h); + + o[0] = s[pxformat.rshift >> 3]; + o[1] = s[pxformat.gshift >> 3]; + o[2] = s[pxformat.bshift >> 3]; + o[3] = s[pxformat.ashift >> 3]; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Picture::SampleInteger(float u, float v, uint _w, uint _h) const +{ uint s; Sample(u, v, s, _w, _h); return s; } +Color Picture::SampleColor(float u, float v, uint _w, uint _h) const +{ Color s; Sample(u, v, s, _w, _h); return s; } +Color Picture::SampleRGBAColor(float u, float v, uint _w, uint _h) const +{ Color s; SampleRGBA(u, v, s, _w, _h); return s; } +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_scaler.cpp b/include/framework/picture/pict_scaler.cpp new file mode 100644 index 0000000..83db0e3 --- /dev/null +++ b/include/framework/picture/pict_scaler.cpp @@ -0,0 +1,206 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + #include "color/color.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool Picture::Resize(uint nwidth, uint nheight) +{ + if (!nwidth && !nheight) + return false; + + if (!nwidth) + nwidth = (GetWidth() * nheight) / GetHeight(); + if (!nheight) + nheight = (GetHeight() * nwidth) / GetWidth(); + + if ((nwidth == GetWidth()) && (nheight == GetHeight())) + return true; + + if (pxformat.IsReal()) + { + float *new_data = (float *)AllocMemory(sizeof(float) * nwidth * nheight * 3); + if (!new_data) + return false; + + float *pdst = (float *)new_data; + float ku = 1.f / (float)nwidth, + kv = 1.f / (float)nheight; + + Color out; + + float v = kv * 0.5f - 0.5f / height; + if (data) + for (uint y = 0; y < nheight; ++y) + { + float u = ku * 0.5f - 0.5f / width; + for (uint x = 0; x < nwidth; ++x) + { + Sample(u, v, out); + pdst[0] = out.x; + pdst[1] = out.y; + pdst[2] = out.z; + pdst += 3; + u += ku; + } + v += kv; + } + + SetData(new_data, nwidth, nheight, PixelFormat::RGBAF, true); + //SetData(new_data, nwidth, nheight, PixelFormat::RGBF, true); + } + else if (GetBpp() == 32) + { + uchar *new_data = (uchar *)AllocMemory(sizeof(uchar) * nwidth * nheight * 4); + if (!new_data) + return false; + + uint *pdst = (uint*)new_data; + float ku = 1.f / (float)nwidth, + kv = 1.f / (float)nheight; + + float v = kv * 0.5f - 0.5f / height; + if (data) + for (uint y = 0; y < nheight; ++y) + { + float u = ku * 0.5f - 0.5f / width; + for (uint x = 0; x < nwidth; ++x) + { + Sample(u, v, *pdst++); + u += ku; + } + v += kv; + } + + SetData(new_data, nwidth, nheight, GetPixelFormat().GetDesc(), true); + } + else + return false; + + return true; +} +bool Picture::Downscale(uint nwidth, uint nheight) +{ + if (!nwidth && !nheight) + return false; + + if (!nwidth) + nwidth = (GetWidth() * nheight) / GetHeight(); + if (!nheight) + nheight = (GetHeight() * nwidth) / GetWidth(); + + if ((nwidth > GetWidth()) || (nheight > GetHeight())) + return Resize(nwidth, nheight); + + if (GetBpp() == 32) + { + uchar *new_data = (uchar *)AllocMemory(sizeof(uchar) * nwidth * nheight * 4); + if (!new_data) + return false; + + uchar *pdst = new_data; + Array accu(nwidth * 4); + + if (accu) + { + float ku = (float)GetWidth() / (float)nwidth, + kv = (float)GetHeight() / (float)nheight; + float u, v; + + // + v = 0.f; + + // Accumulate scan lines. + uchar *psrc = GetData(); + + for (uint y = 0; y < nheight; y++) + { + uint n; + for (n = 0; n < (nwidth * 4); n++) + accu[n] = 0.f; + + float tv = kv, nv = kv; + + for (;;) + { + float k = GS::Math::Ceil(v) - v; + tv -= k; + if (tv < 0.f) + k += tv; // readjust + v += k; + + if (v >= GetHeight()) + { + nv -= k; + break; + } + + // + u = 0.f; + + // Accumulate texels. + uchar *lsrc = psrc; + float *paccu = accu; + float texel[4]; + + for (uint x = 0; x < nwidth; x++) + { + for (n = 0; n < 4; n++) + texel[n] = 0.f; + + float tu = ku, nu = ku; + + for (;;) + { + float k = GS::Math::Ceil(u) - u; + tu -= k; + if (tu < 0.f) + k += tu; // readjust + u += k; + + if (u >= GetWidth()) + { + nu -= k; + break; + } + + for (n = 0; n < 4; n++) + texel[n] += (float)(lsrc[n]) * k; + + if (tu < 0.f) + break; + + lsrc += 4; + } + + tu = k / nu; + for (n = 0; n < 4; n++) + paccu[n] += texel[n] * tu; + paccu += 4; + } + if (tv < 0.f) + break; + + psrc += GetWidth() * 4; + } + + tv = 1.f / nv; + for (n = 0; n < (nwidth * 4); n++) + pdst[n] = (uchar)(accu[n] * tv); + pdst += nwidth * 4; + } + + SetData(new_data, nwidth, nheight, GetPixelFormat().GetDesc(), true); + return true; + } + } + return false; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_tga.cpp b/include/framework/picture/pict_tga.cpp new file mode 100644 index 0000000..f4e0255 --- /dev/null +++ b/include/framework/picture/pict_tga.cpp @@ -0,0 +1,2644 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include + #include + #include "picture/pict.h" + #include "picture/pict_io.h" + #include "filesystem/filesystem.h" + #include "memory/endian.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Endian; + + // + template + destType bitCast(const sourceType &source) + { + size_t copySize = Types::Min(sizeof(destType), sizeof(sourceType)); + destType output; + memcpy(&output, &source, copySize); + return output; + } + + const static unsigned g_mantissa[2048] = { + 0x00000000, + 0x33800000, + 0x34000000, + 0x34400000, + 0x34800000, + 0x34a00000, + 0x34c00000, + 0x34e00000, + 0x35000000, + 0x35100000, + 0x35200000, + 0x35300000, + 0x35400000, + 0x35500000, + 0x35600000, + 0x35700000, + 0x35800000, + 0x35880000, + 0x35900000, + 0x35980000, + 0x35a00000, + 0x35a80000, + 0x35b00000, + 0x35b80000, + 0x35c00000, + 0x35c80000, + 0x35d00000, + 0x35d80000, + 0x35e00000, + 0x35e80000, + 0x35f00000, + 0x35f80000, + 0x36000000, + 0x36040000, + 0x36080000, + 0x360c0000, + 0x36100000, + 0x36140000, + 0x36180000, + 0x361c0000, + 0x36200000, + 0x36240000, + 0x36280000, + 0x362c0000, + 0x36300000, + 0x36340000, + 0x36380000, + 0x363c0000, + 0x36400000, + 0x36440000, + 0x36480000, + 0x364c0000, + 0x36500000, + 0x36540000, + 0x36580000, + 0x365c0000, + 0x36600000, + 0x36640000, + 0x36680000, + 0x366c0000, + 0x36700000, + 0x36740000, + 0x36780000, + 0x367c0000, + 0x36800000, + 0x36820000, + 0x36840000, + 0x36860000, + 0x36880000, + 0x368a0000, + 0x368c0000, + 0x368e0000, + 0x36900000, + 0x36920000, + 0x36940000, + 0x36960000, + 0x36980000, + 0x369a0000, + 0x369c0000, + 0x369e0000, + 0x36a00000, + 0x36a20000, + 0x36a40000, + 0x36a60000, + 0x36a80000, + 0x36aa0000, + 0x36ac0000, + 0x36ae0000, + 0x36b00000, + 0x36b20000, + 0x36b40000, + 0x36b60000, + 0x36b80000, + 0x36ba0000, + 0x36bc0000, + 0x36be0000, + 0x36c00000, + 0x36c20000, + 0x36c40000, + 0x36c60000, + 0x36c80000, + 0x36ca0000, + 0x36cc0000, + 0x36ce0000, + 0x36d00000, + 0x36d20000, + 0x36d40000, + 0x36d60000, + 0x36d80000, + 0x36da0000, + 0x36dc0000, + 0x36de0000, + 0x36e00000, + 0x36e20000, + 0x36e40000, + 0x36e60000, + 0x36e80000, + 0x36ea0000, + 0x36ec0000, + 0x36ee0000, + 0x36f00000, + 0x36f20000, + 0x36f40000, + 0x36f60000, + 0x36f80000, + 0x36fa0000, + 0x36fc0000, + 0x36fe0000, + 0x37000000, + 0x37010000, + 0x37020000, + 0x37030000, + 0x37040000, + 0x37050000, + 0x37060000, + 0x37070000, + 0x37080000, + 0x37090000, + 0x370a0000, + 0x370b0000, + 0x370c0000, + 0x370d0000, + 0x370e0000, + 0x370f0000, + 0x37100000, + 0x37110000, + 0x37120000, + 0x37130000, + 0x37140000, + 0x37150000, + 0x37160000, + 0x37170000, + 0x37180000, + 0x37190000, + 0x371a0000, + 0x371b0000, + 0x371c0000, + 0x371d0000, + 0x371e0000, + 0x371f0000, + 0x37200000, + 0x37210000, + 0x37220000, + 0x37230000, + 0x37240000, + 0x37250000, + 0x37260000, + 0x37270000, + 0x37280000, + 0x37290000, + 0x372a0000, + 0x372b0000, + 0x372c0000, + 0x372d0000, + 0x372e0000, + 0x372f0000, + 0x37300000, + 0x37310000, + 0x37320000, + 0x37330000, + 0x37340000, + 0x37350000, + 0x37360000, + 0x37370000, + 0x37380000, + 0x37390000, + 0x373a0000, + 0x373b0000, + 0x373c0000, + 0x373d0000, + 0x373e0000, + 0x373f0000, + 0x37400000, + 0x37410000, + 0x37420000, + 0x37430000, + 0x37440000, + 0x37450000, + 0x37460000, + 0x37470000, + 0x37480000, + 0x37490000, + 0x374a0000, + 0x374b0000, + 0x374c0000, + 0x374d0000, + 0x374e0000, + 0x374f0000, + 0x37500000, + 0x37510000, + 0x37520000, + 0x37530000, + 0x37540000, + 0x37550000, + 0x37560000, + 0x37570000, + 0x37580000, + 0x37590000, + 0x375a0000, + 0x375b0000, + 0x375c0000, + 0x375d0000, + 0x375e0000, + 0x375f0000, + 0x37600000, + 0x37610000, + 0x37620000, + 0x37630000, + 0x37640000, + 0x37650000, + 0x37660000, + 0x37670000, + 0x37680000, + 0x37690000, + 0x376a0000, + 0x376b0000, + 0x376c0000, + 0x376d0000, + 0x376e0000, + 0x376f0000, + 0x37700000, + 0x37710000, + 0x37720000, + 0x37730000, + 0x37740000, + 0x37750000, + 0x37760000, + 0x37770000, + 0x37780000, + 0x37790000, + 0x377a0000, + 0x377b0000, + 0x377c0000, + 0x377d0000, + 0x377e0000, + 0x377f0000, + 0x37800000, + 0x37808000, + 0x37810000, + 0x37818000, + 0x37820000, + 0x37828000, + 0x37830000, + 0x37838000, + 0x37840000, + 0x37848000, + 0x37850000, + 0x37858000, + 0x37860000, + 0x37868000, + 0x37870000, + 0x37878000, + 0x37880000, + 0x37888000, + 0x37890000, + 0x37898000, + 0x378a0000, + 0x378a8000, + 0x378b0000, + 0x378b8000, + 0x378c0000, + 0x378c8000, + 0x378d0000, + 0x378d8000, + 0x378e0000, + 0x378e8000, + 0x378f0000, + 0x378f8000, + 0x37900000, + 0x37908000, + 0x37910000, + 0x37918000, + 0x37920000, + 0x37928000, + 0x37930000, + 0x37938000, + 0x37940000, + 0x37948000, + 0x37950000, + 0x37958000, + 0x37960000, + 0x37968000, + 0x37970000, + 0x37978000, + 0x37980000, + 0x37988000, + 0x37990000, + 0x37998000, + 0x379a0000, + 0x379a8000, + 0x379b0000, + 0x379b8000, + 0x379c0000, + 0x379c8000, + 0x379d0000, + 0x379d8000, + 0x379e0000, + 0x379e8000, + 0x379f0000, + 0x379f8000, + 0x37a00000, + 0x37a08000, + 0x37a10000, + 0x37a18000, + 0x37a20000, + 0x37a28000, + 0x37a30000, + 0x37a38000, + 0x37a40000, + 0x37a48000, + 0x37a50000, + 0x37a58000, + 0x37a60000, + 0x37a68000, + 0x37a70000, + 0x37a78000, + 0x37a80000, + 0x37a88000, + 0x37a90000, + 0x37a98000, + 0x37aa0000, + 0x37aa8000, + 0x37ab0000, + 0x37ab8000, + 0x37ac0000, + 0x37ac8000, + 0x37ad0000, + 0x37ad8000, + 0x37ae0000, + 0x37ae8000, + 0x37af0000, + 0x37af8000, + 0x37b00000, + 0x37b08000, + 0x37b10000, + 0x37b18000, + 0x37b20000, + 0x37b28000, + 0x37b30000, + 0x37b38000, + 0x37b40000, + 0x37b48000, + 0x37b50000, + 0x37b58000, + 0x37b60000, + 0x37b68000, + 0x37b70000, + 0x37b78000, + 0x37b80000, + 0x37b88000, + 0x37b90000, + 0x37b98000, + 0x37ba0000, + 0x37ba8000, + 0x37bb0000, + 0x37bb8000, + 0x37bc0000, + 0x37bc8000, + 0x37bd0000, + 0x37bd8000, + 0x37be0000, + 0x37be8000, + 0x37bf0000, + 0x37bf8000, + 0x37c00000, + 0x37c08000, + 0x37c10000, + 0x37c18000, + 0x37c20000, + 0x37c28000, + 0x37c30000, + 0x37c38000, + 0x37c40000, + 0x37c48000, + 0x37c50000, + 0x37c58000, + 0x37c60000, + 0x37c68000, + 0x37c70000, + 0x37c78000, + 0x37c80000, + 0x37c88000, + 0x37c90000, + 0x37c98000, + 0x37ca0000, + 0x37ca8000, + 0x37cb0000, + 0x37cb8000, + 0x37cc0000, + 0x37cc8000, + 0x37cd0000, + 0x37cd8000, + 0x37ce0000, + 0x37ce8000, + 0x37cf0000, + 0x37cf8000, + 0x37d00000, + 0x37d08000, + 0x37d10000, + 0x37d18000, + 0x37d20000, + 0x37d28000, + 0x37d30000, + 0x37d38000, + 0x37d40000, + 0x37d48000, + 0x37d50000, + 0x37d58000, + 0x37d60000, + 0x37d68000, + 0x37d70000, + 0x37d78000, + 0x37d80000, + 0x37d88000, + 0x37d90000, + 0x37d98000, + 0x37da0000, + 0x37da8000, + 0x37db0000, + 0x37db8000, + 0x37dc0000, + 0x37dc8000, + 0x37dd0000, + 0x37dd8000, + 0x37de0000, + 0x37de8000, + 0x37df0000, + 0x37df8000, + 0x37e00000, + 0x37e08000, + 0x37e10000, + 0x37e18000, + 0x37e20000, + 0x37e28000, + 0x37e30000, + 0x37e38000, + 0x37e40000, + 0x37e48000, + 0x37e50000, + 0x37e58000, + 0x37e60000, + 0x37e68000, + 0x37e70000, + 0x37e78000, + 0x37e80000, + 0x37e88000, + 0x37e90000, + 0x37e98000, + 0x37ea0000, + 0x37ea8000, + 0x37eb0000, + 0x37eb8000, + 0x37ec0000, + 0x37ec8000, + 0x37ed0000, + 0x37ed8000, + 0x37ee0000, + 0x37ee8000, + 0x37ef0000, + 0x37ef8000, + 0x37f00000, + 0x37f08000, + 0x37f10000, + 0x37f18000, + 0x37f20000, + 0x37f28000, + 0x37f30000, + 0x37f38000, + 0x37f40000, + 0x37f48000, + 0x37f50000, + 0x37f58000, + 0x37f60000, + 0x37f68000, + 0x37f70000, + 0x37f78000, + 0x37f80000, + 0x37f88000, + 0x37f90000, + 0x37f98000, + 0x37fa0000, + 0x37fa8000, + 0x37fb0000, + 0x37fb8000, + 0x37fc0000, + 0x37fc8000, + 0x37fd0000, + 0x37fd8000, + 0x37fe0000, + 0x37fe8000, + 0x37ff0000, + 0x37ff8000, + 0x38000000, + 0x38004000, + 0x38008000, + 0x3800c000, + 0x38010000, + 0x38014000, + 0x38018000, + 0x3801c000, + 0x38020000, + 0x38024000, + 0x38028000, + 0x3802c000, + 0x38030000, + 0x38034000, + 0x38038000, + 0x3803c000, + 0x38040000, + 0x38044000, + 0x38048000, + 0x3804c000, + 0x38050000, + 0x38054000, + 0x38058000, + 0x3805c000, + 0x38060000, + 0x38064000, + 0x38068000, + 0x3806c000, + 0x38070000, + 0x38074000, + 0x38078000, + 0x3807c000, + 0x38080000, + 0x38084000, + 0x38088000, + 0x3808c000, + 0x38090000, + 0x38094000, + 0x38098000, + 0x3809c000, + 0x380a0000, + 0x380a4000, + 0x380a8000, + 0x380ac000, + 0x380b0000, + 0x380b4000, + 0x380b8000, + 0x380bc000, + 0x380c0000, + 0x380c4000, + 0x380c8000, + 0x380cc000, + 0x380d0000, + 0x380d4000, + 0x380d8000, + 0x380dc000, + 0x380e0000, + 0x380e4000, + 0x380e8000, + 0x380ec000, + 0x380f0000, + 0x380f4000, + 0x380f8000, + 0x380fc000, + 0x38100000, + 0x38104000, + 0x38108000, + 0x3810c000, + 0x38110000, + 0x38114000, + 0x38118000, + 0x3811c000, + 0x38120000, + 0x38124000, + 0x38128000, + 0x3812c000, + 0x38130000, + 0x38134000, + 0x38138000, + 0x3813c000, + 0x38140000, + 0x38144000, + 0x38148000, + 0x3814c000, + 0x38150000, + 0x38154000, + 0x38158000, + 0x3815c000, + 0x38160000, + 0x38164000, + 0x38168000, + 0x3816c000, + 0x38170000, + 0x38174000, + 0x38178000, + 0x3817c000, + 0x38180000, + 0x38184000, + 0x38188000, + 0x3818c000, + 0x38190000, + 0x38194000, + 0x38198000, + 0x3819c000, + 0x381a0000, + 0x381a4000, + 0x381a8000, + 0x381ac000, + 0x381b0000, + 0x381b4000, + 0x381b8000, + 0x381bc000, + 0x381c0000, + 0x381c4000, + 0x381c8000, + 0x381cc000, + 0x381d0000, + 0x381d4000, + 0x381d8000, + 0x381dc000, + 0x381e0000, + 0x381e4000, + 0x381e8000, + 0x381ec000, + 0x381f0000, + 0x381f4000, + 0x381f8000, + 0x381fc000, + 0x38200000, + 0x38204000, + 0x38208000, + 0x3820c000, + 0x38210000, + 0x38214000, + 0x38218000, + 0x3821c000, + 0x38220000, + 0x38224000, + 0x38228000, + 0x3822c000, + 0x38230000, + 0x38234000, + 0x38238000, + 0x3823c000, + 0x38240000, + 0x38244000, + 0x38248000, + 0x3824c000, + 0x38250000, + 0x38254000, + 0x38258000, + 0x3825c000, + 0x38260000, + 0x38264000, + 0x38268000, + 0x3826c000, + 0x38270000, + 0x38274000, + 0x38278000, + 0x3827c000, + 0x38280000, + 0x38284000, + 0x38288000, + 0x3828c000, + 0x38290000, + 0x38294000, + 0x38298000, + 0x3829c000, + 0x382a0000, + 0x382a4000, + 0x382a8000, + 0x382ac000, + 0x382b0000, + 0x382b4000, + 0x382b8000, + 0x382bc000, + 0x382c0000, + 0x382c4000, + 0x382c8000, + 0x382cc000, + 0x382d0000, + 0x382d4000, + 0x382d8000, + 0x382dc000, + 0x382e0000, + 0x382e4000, + 0x382e8000, + 0x382ec000, + 0x382f0000, + 0x382f4000, + 0x382f8000, + 0x382fc000, + 0x38300000, + 0x38304000, + 0x38308000, + 0x3830c000, + 0x38310000, + 0x38314000, + 0x38318000, + 0x3831c000, + 0x38320000, + 0x38324000, + 0x38328000, + 0x3832c000, + 0x38330000, + 0x38334000, + 0x38338000, + 0x3833c000, + 0x38340000, + 0x38344000, + 0x38348000, + 0x3834c000, + 0x38350000, + 0x38354000, + 0x38358000, + 0x3835c000, + 0x38360000, + 0x38364000, + 0x38368000, + 0x3836c000, + 0x38370000, + 0x38374000, + 0x38378000, + 0x3837c000, + 0x38380000, + 0x38384000, + 0x38388000, + 0x3838c000, + 0x38390000, + 0x38394000, + 0x38398000, + 0x3839c000, + 0x383a0000, + 0x383a4000, + 0x383a8000, + 0x383ac000, + 0x383b0000, + 0x383b4000, + 0x383b8000, + 0x383bc000, + 0x383c0000, + 0x383c4000, + 0x383c8000, + 0x383cc000, + 0x383d0000, + 0x383d4000, + 0x383d8000, + 0x383dc000, + 0x383e0000, + 0x383e4000, + 0x383e8000, + 0x383ec000, + 0x383f0000, + 0x383f4000, + 0x383f8000, + 0x383fc000, + 0x38400000, + 0x38404000, + 0x38408000, + 0x3840c000, + 0x38410000, + 0x38414000, + 0x38418000, + 0x3841c000, + 0x38420000, + 0x38424000, + 0x38428000, + 0x3842c000, + 0x38430000, + 0x38434000, + 0x38438000, + 0x3843c000, + 0x38440000, + 0x38444000, + 0x38448000, + 0x3844c000, + 0x38450000, + 0x38454000, + 0x38458000, + 0x3845c000, + 0x38460000, + 0x38464000, + 0x38468000, + 0x3846c000, + 0x38470000, + 0x38474000, + 0x38478000, + 0x3847c000, + 0x38480000, + 0x38484000, + 0x38488000, + 0x3848c000, + 0x38490000, + 0x38494000, + 0x38498000, + 0x3849c000, + 0x384a0000, + 0x384a4000, + 0x384a8000, + 0x384ac000, + 0x384b0000, + 0x384b4000, + 0x384b8000, + 0x384bc000, + 0x384c0000, + 0x384c4000, + 0x384c8000, + 0x384cc000, + 0x384d0000, + 0x384d4000, + 0x384d8000, + 0x384dc000, + 0x384e0000, + 0x384e4000, + 0x384e8000, + 0x384ec000, + 0x384f0000, + 0x384f4000, + 0x384f8000, + 0x384fc000, + 0x38500000, + 0x38504000, + 0x38508000, + 0x3850c000, + 0x38510000, + 0x38514000, + 0x38518000, + 0x3851c000, + 0x38520000, + 0x38524000, + 0x38528000, + 0x3852c000, + 0x38530000, + 0x38534000, + 0x38538000, + 0x3853c000, + 0x38540000, + 0x38544000, + 0x38548000, + 0x3854c000, + 0x38550000, + 0x38554000, + 0x38558000, + 0x3855c000, + 0x38560000, + 0x38564000, + 0x38568000, + 0x3856c000, + 0x38570000, + 0x38574000, + 0x38578000, + 0x3857c000, + 0x38580000, + 0x38584000, + 0x38588000, + 0x3858c000, + 0x38590000, + 0x38594000, + 0x38598000, + 0x3859c000, + 0x385a0000, + 0x385a4000, + 0x385a8000, + 0x385ac000, + 0x385b0000, + 0x385b4000, + 0x385b8000, + 0x385bc000, + 0x385c0000, + 0x385c4000, + 0x385c8000, + 0x385cc000, + 0x385d0000, + 0x385d4000, + 0x385d8000, + 0x385dc000, + 0x385e0000, + 0x385e4000, + 0x385e8000, + 0x385ec000, + 0x385f0000, + 0x385f4000, + 0x385f8000, + 0x385fc000, + 0x38600000, + 0x38604000, + 0x38608000, + 0x3860c000, + 0x38610000, + 0x38614000, + 0x38618000, + 0x3861c000, + 0x38620000, + 0x38624000, + 0x38628000, + 0x3862c000, + 0x38630000, + 0x38634000, + 0x38638000, + 0x3863c000, + 0x38640000, + 0x38644000, + 0x38648000, + 0x3864c000, + 0x38650000, + 0x38654000, + 0x38658000, + 0x3865c000, + 0x38660000, + 0x38664000, + 0x38668000, + 0x3866c000, + 0x38670000, + 0x38674000, + 0x38678000, + 0x3867c000, + 0x38680000, + 0x38684000, + 0x38688000, + 0x3868c000, + 0x38690000, + 0x38694000, + 0x38698000, + 0x3869c000, + 0x386a0000, + 0x386a4000, + 0x386a8000, + 0x386ac000, + 0x386b0000, + 0x386b4000, + 0x386b8000, + 0x386bc000, + 0x386c0000, + 0x386c4000, + 0x386c8000, + 0x386cc000, + 0x386d0000, + 0x386d4000, + 0x386d8000, + 0x386dc000, + 0x386e0000, + 0x386e4000, + 0x386e8000, + 0x386ec000, + 0x386f0000, + 0x386f4000, + 0x386f8000, + 0x386fc000, + 0x38700000, + 0x38704000, + 0x38708000, + 0x3870c000, + 0x38710000, + 0x38714000, + 0x38718000, + 0x3871c000, + 0x38720000, + 0x38724000, + 0x38728000, + 0x3872c000, + 0x38730000, + 0x38734000, + 0x38738000, + 0x3873c000, + 0x38740000, + 0x38744000, + 0x38748000, + 0x3874c000, + 0x38750000, + 0x38754000, + 0x38758000, + 0x3875c000, + 0x38760000, + 0x38764000, + 0x38768000, + 0x3876c000, + 0x38770000, + 0x38774000, + 0x38778000, + 0x3877c000, + 0x38780000, + 0x38784000, + 0x38788000, + 0x3878c000, + 0x38790000, + 0x38794000, + 0x38798000, + 0x3879c000, + 0x387a0000, + 0x387a4000, + 0x387a8000, + 0x387ac000, + 0x387b0000, + 0x387b4000, + 0x387b8000, + 0x387bc000, + 0x387c0000, + 0x387c4000, + 0x387c8000, + 0x387cc000, + 0x387d0000, + 0x387d4000, + 0x387d8000, + 0x387dc000, + 0x387e0000, + 0x387e4000, + 0x387e8000, + 0x387ec000, + 0x387f0000, + 0x387f4000, + 0x387f8000, + 0x387fc000, + 0x38000000, + 0x38002000, + 0x38004000, + 0x38006000, + 0x38008000, + 0x3800a000, + 0x3800c000, + 0x3800e000, + 0x38010000, + 0x38012000, + 0x38014000, + 0x38016000, + 0x38018000, + 0x3801a000, + 0x3801c000, + 0x3801e000, + 0x38020000, + 0x38022000, + 0x38024000, + 0x38026000, + 0x38028000, + 0x3802a000, + 0x3802c000, + 0x3802e000, + 0x38030000, + 0x38032000, + 0x38034000, + 0x38036000, + 0x38038000, + 0x3803a000, + 0x3803c000, + 0x3803e000, + 0x38040000, + 0x38042000, + 0x38044000, + 0x38046000, + 0x38048000, + 0x3804a000, + 0x3804c000, + 0x3804e000, + 0x38050000, + 0x38052000, + 0x38054000, + 0x38056000, + 0x38058000, + 0x3805a000, + 0x3805c000, + 0x3805e000, + 0x38060000, + 0x38062000, + 0x38064000, + 0x38066000, + 0x38068000, + 0x3806a000, + 0x3806c000, + 0x3806e000, + 0x38070000, + 0x38072000, + 0x38074000, + 0x38076000, + 0x38078000, + 0x3807a000, + 0x3807c000, + 0x3807e000, + 0x38080000, + 0x38082000, + 0x38084000, + 0x38086000, + 0x38088000, + 0x3808a000, + 0x3808c000, + 0x3808e000, + 0x38090000, + 0x38092000, + 0x38094000, + 0x38096000, + 0x38098000, + 0x3809a000, + 0x3809c000, + 0x3809e000, + 0x380a0000, + 0x380a2000, + 0x380a4000, + 0x380a6000, + 0x380a8000, + 0x380aa000, + 0x380ac000, + 0x380ae000, + 0x380b0000, + 0x380b2000, + 0x380b4000, + 0x380b6000, + 0x380b8000, + 0x380ba000, + 0x380bc000, + 0x380be000, + 0x380c0000, + 0x380c2000, + 0x380c4000, + 0x380c6000, + 0x380c8000, + 0x380ca000, + 0x380cc000, + 0x380ce000, + 0x380d0000, + 0x380d2000, + 0x380d4000, + 0x380d6000, + 0x380d8000, + 0x380da000, + 0x380dc000, + 0x380de000, + 0x380e0000, + 0x380e2000, + 0x380e4000, + 0x380e6000, + 0x380e8000, + 0x380ea000, + 0x380ec000, + 0x380ee000, + 0x380f0000, + 0x380f2000, + 0x380f4000, + 0x380f6000, + 0x380f8000, + 0x380fa000, + 0x380fc000, + 0x380fe000, + 0x38100000, + 0x38102000, + 0x38104000, + 0x38106000, + 0x38108000, + 0x3810a000, + 0x3810c000, + 0x3810e000, + 0x38110000, + 0x38112000, + 0x38114000, + 0x38116000, + 0x38118000, + 0x3811a000, + 0x3811c000, + 0x3811e000, + 0x38120000, + 0x38122000, + 0x38124000, + 0x38126000, + 0x38128000, + 0x3812a000, + 0x3812c000, + 0x3812e000, + 0x38130000, + 0x38132000, + 0x38134000, + 0x38136000, + 0x38138000, + 0x3813a000, + 0x3813c000, + 0x3813e000, + 0x38140000, + 0x38142000, + 0x38144000, + 0x38146000, + 0x38148000, + 0x3814a000, + 0x3814c000, + 0x3814e000, + 0x38150000, + 0x38152000, + 0x38154000, + 0x38156000, + 0x38158000, + 0x3815a000, + 0x3815c000, + 0x3815e000, + 0x38160000, + 0x38162000, + 0x38164000, + 0x38166000, + 0x38168000, + 0x3816a000, + 0x3816c000, + 0x3816e000, + 0x38170000, + 0x38172000, + 0x38174000, + 0x38176000, + 0x38178000, + 0x3817a000, + 0x3817c000, + 0x3817e000, + 0x38180000, + 0x38182000, + 0x38184000, + 0x38186000, + 0x38188000, + 0x3818a000, + 0x3818c000, + 0x3818e000, + 0x38190000, + 0x38192000, + 0x38194000, + 0x38196000, + 0x38198000, + 0x3819a000, + 0x3819c000, + 0x3819e000, + 0x381a0000, + 0x381a2000, + 0x381a4000, + 0x381a6000, + 0x381a8000, + 0x381aa000, + 0x381ac000, + 0x381ae000, + 0x381b0000, + 0x381b2000, + 0x381b4000, + 0x381b6000, + 0x381b8000, + 0x381ba000, + 0x381bc000, + 0x381be000, + 0x381c0000, + 0x381c2000, + 0x381c4000, + 0x381c6000, + 0x381c8000, + 0x381ca000, + 0x381cc000, + 0x381ce000, + 0x381d0000, + 0x381d2000, + 0x381d4000, + 0x381d6000, + 0x381d8000, + 0x381da000, + 0x381dc000, + 0x381de000, + 0x381e0000, + 0x381e2000, + 0x381e4000, + 0x381e6000, + 0x381e8000, + 0x381ea000, + 0x381ec000, + 0x381ee000, + 0x381f0000, + 0x381f2000, + 0x381f4000, + 0x381f6000, + 0x381f8000, + 0x381fa000, + 0x381fc000, + 0x381fe000, + 0x38200000, + 0x38202000, + 0x38204000, + 0x38206000, + 0x38208000, + 0x3820a000, + 0x3820c000, + 0x3820e000, + 0x38210000, + 0x38212000, + 0x38214000, + 0x38216000, + 0x38218000, + 0x3821a000, + 0x3821c000, + 0x3821e000, + 0x38220000, + 0x38222000, + 0x38224000, + 0x38226000, + 0x38228000, + 0x3822a000, + 0x3822c000, + 0x3822e000, + 0x38230000, + 0x38232000, + 0x38234000, + 0x38236000, + 0x38238000, + 0x3823a000, + 0x3823c000, + 0x3823e000, + 0x38240000, + 0x38242000, + 0x38244000, + 0x38246000, + 0x38248000, + 0x3824a000, + 0x3824c000, + 0x3824e000, + 0x38250000, + 0x38252000, + 0x38254000, + 0x38256000, + 0x38258000, + 0x3825a000, + 0x3825c000, + 0x3825e000, + 0x38260000, + 0x38262000, + 0x38264000, + 0x38266000, + 0x38268000, + 0x3826a000, + 0x3826c000, + 0x3826e000, + 0x38270000, + 0x38272000, + 0x38274000, + 0x38276000, + 0x38278000, + 0x3827a000, + 0x3827c000, + 0x3827e000, + 0x38280000, + 0x38282000, + 0x38284000, + 0x38286000, + 0x38288000, + 0x3828a000, + 0x3828c000, + 0x3828e000, + 0x38290000, + 0x38292000, + 0x38294000, + 0x38296000, + 0x38298000, + 0x3829a000, + 0x3829c000, + 0x3829e000, + 0x382a0000, + 0x382a2000, + 0x382a4000, + 0x382a6000, + 0x382a8000, + 0x382aa000, + 0x382ac000, + 0x382ae000, + 0x382b0000, + 0x382b2000, + 0x382b4000, + 0x382b6000, + 0x382b8000, + 0x382ba000, + 0x382bc000, + 0x382be000, + 0x382c0000, + 0x382c2000, + 0x382c4000, + 0x382c6000, + 0x382c8000, + 0x382ca000, + 0x382cc000, + 0x382ce000, + 0x382d0000, + 0x382d2000, + 0x382d4000, + 0x382d6000, + 0x382d8000, + 0x382da000, + 0x382dc000, + 0x382de000, + 0x382e0000, + 0x382e2000, + 0x382e4000, + 0x382e6000, + 0x382e8000, + 0x382ea000, + 0x382ec000, + 0x382ee000, + 0x382f0000, + 0x382f2000, + 0x382f4000, + 0x382f6000, + 0x382f8000, + 0x382fa000, + 0x382fc000, + 0x382fe000, + 0x38300000, + 0x38302000, + 0x38304000, + 0x38306000, + 0x38308000, + 0x3830a000, + 0x3830c000, + 0x3830e000, + 0x38310000, + 0x38312000, + 0x38314000, + 0x38316000, + 0x38318000, + 0x3831a000, + 0x3831c000, + 0x3831e000, + 0x38320000, + 0x38322000, + 0x38324000, + 0x38326000, + 0x38328000, + 0x3832a000, + 0x3832c000, + 0x3832e000, + 0x38330000, + 0x38332000, + 0x38334000, + 0x38336000, + 0x38338000, + 0x3833a000, + 0x3833c000, + 0x3833e000, + 0x38340000, + 0x38342000, + 0x38344000, + 0x38346000, + 0x38348000, + 0x3834a000, + 0x3834c000, + 0x3834e000, + 0x38350000, + 0x38352000, + 0x38354000, + 0x38356000, + 0x38358000, + 0x3835a000, + 0x3835c000, + 0x3835e000, + 0x38360000, + 0x38362000, + 0x38364000, + 0x38366000, + 0x38368000, + 0x3836a000, + 0x3836c000, + 0x3836e000, + 0x38370000, + 0x38372000, + 0x38374000, + 0x38376000, + 0x38378000, + 0x3837a000, + 0x3837c000, + 0x3837e000, + 0x38380000, + 0x38382000, + 0x38384000, + 0x38386000, + 0x38388000, + 0x3838a000, + 0x3838c000, + 0x3838e000, + 0x38390000, + 0x38392000, + 0x38394000, + 0x38396000, + 0x38398000, + 0x3839a000, + 0x3839c000, + 0x3839e000, + 0x383a0000, + 0x383a2000, + 0x383a4000, + 0x383a6000, + 0x383a8000, + 0x383aa000, + 0x383ac000, + 0x383ae000, + 0x383b0000, + 0x383b2000, + 0x383b4000, + 0x383b6000, + 0x383b8000, + 0x383ba000, + 0x383bc000, + 0x383be000, + 0x383c0000, + 0x383c2000, + 0x383c4000, + 0x383c6000, + 0x383c8000, + 0x383ca000, + 0x383cc000, + 0x383ce000, + 0x383d0000, + 0x383d2000, + 0x383d4000, + 0x383d6000, + 0x383d8000, + 0x383da000, + 0x383dc000, + 0x383de000, + 0x383e0000, + 0x383e2000, + 0x383e4000, + 0x383e6000, + 0x383e8000, + 0x383ea000, + 0x383ec000, + 0x383ee000, + 0x383f0000, + 0x383f2000, + 0x383f4000, + 0x383f6000, + 0x383f8000, + 0x383fa000, + 0x383fc000, + 0x383fe000, + 0x38400000, + 0x38402000, + 0x38404000, + 0x38406000, + 0x38408000, + 0x3840a000, + 0x3840c000, + 0x3840e000, + 0x38410000, + 0x38412000, + 0x38414000, + 0x38416000, + 0x38418000, + 0x3841a000, + 0x3841c000, + 0x3841e000, + 0x38420000, + 0x38422000, + 0x38424000, + 0x38426000, + 0x38428000, + 0x3842a000, + 0x3842c000, + 0x3842e000, + 0x38430000, + 0x38432000, + 0x38434000, + 0x38436000, + 0x38438000, + 0x3843a000, + 0x3843c000, + 0x3843e000, + 0x38440000, + 0x38442000, + 0x38444000, + 0x38446000, + 0x38448000, + 0x3844a000, + 0x3844c000, + 0x3844e000, + 0x38450000, + 0x38452000, + 0x38454000, + 0x38456000, + 0x38458000, + 0x3845a000, + 0x3845c000, + 0x3845e000, + 0x38460000, + 0x38462000, + 0x38464000, + 0x38466000, + 0x38468000, + 0x3846a000, + 0x3846c000, + 0x3846e000, + 0x38470000, + 0x38472000, + 0x38474000, + 0x38476000, + 0x38478000, + 0x3847a000, + 0x3847c000, + 0x3847e000, + 0x38480000, + 0x38482000, + 0x38484000, + 0x38486000, + 0x38488000, + 0x3848a000, + 0x3848c000, + 0x3848e000, + 0x38490000, + 0x38492000, + 0x38494000, + 0x38496000, + 0x38498000, + 0x3849a000, + 0x3849c000, + 0x3849e000, + 0x384a0000, + 0x384a2000, + 0x384a4000, + 0x384a6000, + 0x384a8000, + 0x384aa000, + 0x384ac000, + 0x384ae000, + 0x384b0000, + 0x384b2000, + 0x384b4000, + 0x384b6000, + 0x384b8000, + 0x384ba000, + 0x384bc000, + 0x384be000, + 0x384c0000, + 0x384c2000, + 0x384c4000, + 0x384c6000, + 0x384c8000, + 0x384ca000, + 0x384cc000, + 0x384ce000, + 0x384d0000, + 0x384d2000, + 0x384d4000, + 0x384d6000, + 0x384d8000, + 0x384da000, + 0x384dc000, + 0x384de000, + 0x384e0000, + 0x384e2000, + 0x384e4000, + 0x384e6000, + 0x384e8000, + 0x384ea000, + 0x384ec000, + 0x384ee000, + 0x384f0000, + 0x384f2000, + 0x384f4000, + 0x384f6000, + 0x384f8000, + 0x384fa000, + 0x384fc000, + 0x384fe000, + 0x38500000, + 0x38502000, + 0x38504000, + 0x38506000, + 0x38508000, + 0x3850a000, + 0x3850c000, + 0x3850e000, + 0x38510000, + 0x38512000, + 0x38514000, + 0x38516000, + 0x38518000, + 0x3851a000, + 0x3851c000, + 0x3851e000, + 0x38520000, + 0x38522000, + 0x38524000, + 0x38526000, + 0x38528000, + 0x3852a000, + 0x3852c000, + 0x3852e000, + 0x38530000, + 0x38532000, + 0x38534000, + 0x38536000, + 0x38538000, + 0x3853a000, + 0x3853c000, + 0x3853e000, + 0x38540000, + 0x38542000, + 0x38544000, + 0x38546000, + 0x38548000, + 0x3854a000, + 0x3854c000, + 0x3854e000, + 0x38550000, + 0x38552000, + 0x38554000, + 0x38556000, + 0x38558000, + 0x3855a000, + 0x3855c000, + 0x3855e000, + 0x38560000, + 0x38562000, + 0x38564000, + 0x38566000, + 0x38568000, + 0x3856a000, + 0x3856c000, + 0x3856e000, + 0x38570000, + 0x38572000, + 0x38574000, + 0x38576000, + 0x38578000, + 0x3857a000, + 0x3857c000, + 0x3857e000, + 0x38580000, + 0x38582000, + 0x38584000, + 0x38586000, + 0x38588000, + 0x3858a000, + 0x3858c000, + 0x3858e000, + 0x38590000, + 0x38592000, + 0x38594000, + 0x38596000, + 0x38598000, + 0x3859a000, + 0x3859c000, + 0x3859e000, + 0x385a0000, + 0x385a2000, + 0x385a4000, + 0x385a6000, + 0x385a8000, + 0x385aa000, + 0x385ac000, + 0x385ae000, + 0x385b0000, + 0x385b2000, + 0x385b4000, + 0x385b6000, + 0x385b8000, + 0x385ba000, + 0x385bc000, + 0x385be000, + 0x385c0000, + 0x385c2000, + 0x385c4000, + 0x385c6000, + 0x385c8000, + 0x385ca000, + 0x385cc000, + 0x385ce000, + 0x385d0000, + 0x385d2000, + 0x385d4000, + 0x385d6000, + 0x385d8000, + 0x385da000, + 0x385dc000, + 0x385de000, + 0x385e0000, + 0x385e2000, + 0x385e4000, + 0x385e6000, + 0x385e8000, + 0x385ea000, + 0x385ec000, + 0x385ee000, + 0x385f0000, + 0x385f2000, + 0x385f4000, + 0x385f6000, + 0x385f8000, + 0x385fa000, + 0x385fc000, + 0x385fe000, + 0x38600000, + 0x38602000, + 0x38604000, + 0x38606000, + 0x38608000, + 0x3860a000, + 0x3860c000, + 0x3860e000, + 0x38610000, + 0x38612000, + 0x38614000, + 0x38616000, + 0x38618000, + 0x3861a000, + 0x3861c000, + 0x3861e000, + 0x38620000, + 0x38622000, + 0x38624000, + 0x38626000, + 0x38628000, + 0x3862a000, + 0x3862c000, + 0x3862e000, + 0x38630000, + 0x38632000, + 0x38634000, + 0x38636000, + 0x38638000, + 0x3863a000, + 0x3863c000, + 0x3863e000, + 0x38640000, + 0x38642000, + 0x38644000, + 0x38646000, + 0x38648000, + 0x3864a000, + 0x3864c000, + 0x3864e000, + 0x38650000, + 0x38652000, + 0x38654000, + 0x38656000, + 0x38658000, + 0x3865a000, + 0x3865c000, + 0x3865e000, + 0x38660000, + 0x38662000, + 0x38664000, + 0x38666000, + 0x38668000, + 0x3866a000, + 0x3866c000, + 0x3866e000, + 0x38670000, + 0x38672000, + 0x38674000, + 0x38676000, + 0x38678000, + 0x3867a000, + 0x3867c000, + 0x3867e000, + 0x38680000, + 0x38682000, + 0x38684000, + 0x38686000, + 0x38688000, + 0x3868a000, + 0x3868c000, + 0x3868e000, + 0x38690000, + 0x38692000, + 0x38694000, + 0x38696000, + 0x38698000, + 0x3869a000, + 0x3869c000, + 0x3869e000, + 0x386a0000, + 0x386a2000, + 0x386a4000, + 0x386a6000, + 0x386a8000, + 0x386aa000, + 0x386ac000, + 0x386ae000, + 0x386b0000, + 0x386b2000, + 0x386b4000, + 0x386b6000, + 0x386b8000, + 0x386ba000, + 0x386bc000, + 0x386be000, + 0x386c0000, + 0x386c2000, + 0x386c4000, + 0x386c6000, + 0x386c8000, + 0x386ca000, + 0x386cc000, + 0x386ce000, + 0x386d0000, + 0x386d2000, + 0x386d4000, + 0x386d6000, + 0x386d8000, + 0x386da000, + 0x386dc000, + 0x386de000, + 0x386e0000, + 0x386e2000, + 0x386e4000, + 0x386e6000, + 0x386e8000, + 0x386ea000, + 0x386ec000, + 0x386ee000, + 0x386f0000, + 0x386f2000, + 0x386f4000, + 0x386f6000, + 0x386f8000, + 0x386fa000, + 0x386fc000, + 0x386fe000, + 0x38700000, + 0x38702000, + 0x38704000, + 0x38706000, + 0x38708000, + 0x3870a000, + 0x3870c000, + 0x3870e000, + 0x38710000, + 0x38712000, + 0x38714000, + 0x38716000, + 0x38718000, + 0x3871a000, + 0x3871c000, + 0x3871e000, + 0x38720000, + 0x38722000, + 0x38724000, + 0x38726000, + 0x38728000, + 0x3872a000, + 0x3872c000, + 0x3872e000, + 0x38730000, + 0x38732000, + 0x38734000, + 0x38736000, + 0x38738000, + 0x3873a000, + 0x3873c000, + 0x3873e000, + 0x38740000, + 0x38742000, + 0x38744000, + 0x38746000, + 0x38748000, + 0x3874a000, + 0x3874c000, + 0x3874e000, + 0x38750000, + 0x38752000, + 0x38754000, + 0x38756000, + 0x38758000, + 0x3875a000, + 0x3875c000, + 0x3875e000, + 0x38760000, + 0x38762000, + 0x38764000, + 0x38766000, + 0x38768000, + 0x3876a000, + 0x3876c000, + 0x3876e000, + 0x38770000, + 0x38772000, + 0x38774000, + 0x38776000, + 0x38778000, + 0x3877a000, + 0x3877c000, + 0x3877e000, + 0x38780000, + 0x38782000, + 0x38784000, + 0x38786000, + 0x38788000, + 0x3878a000, + 0x3878c000, + 0x3878e000, + 0x38790000, + 0x38792000, + 0x38794000, + 0x38796000, + 0x38798000, + 0x3879a000, + 0x3879c000, + 0x3879e000, + 0x387a0000, + 0x387a2000, + 0x387a4000, + 0x387a6000, + 0x387a8000, + 0x387aa000, + 0x387ac000, + 0x387ae000, + 0x387b0000, + 0x387b2000, + 0x387b4000, + 0x387b6000, + 0x387b8000, + 0x387ba000, + 0x387bc000, + 0x387be000, + 0x387c0000, + 0x387c2000, + 0x387c4000, + 0x387c6000, + 0x387c8000, + 0x387ca000, + 0x387cc000, + 0x387ce000, + 0x387d0000, + 0x387d2000, + 0x387d4000, + 0x387d6000, + 0x387d8000, + 0x387da000, + 0x387dc000, + 0x387de000, + 0x387e0000, + 0x387e2000, + 0x387e4000, + 0x387e6000, + 0x387e8000, + 0x387ea000, + 0x387ec000, + 0x387ee000, + 0x387f0000, + 0x387f2000, + 0x387f4000, + 0x387f6000, + 0x387f8000, + 0x387fa000, + 0x387fc000, + 0x387fe000, + }; + + const static unsigned g_exponent[64] = { + 0x00000000, + 0x00800000, + 0x01000000, + 0x01800000, + 0x02000000, + 0x02800000, + 0x03000000, + 0x03800000, + 0x04000000, + 0x04800000, + 0x05000000, + 0x05800000, + 0x06000000, + 0x06800000, + 0x07000000, + 0x07800000, + 0x08000000, + 0x08800000, + 0x09000000, + 0x09800000, + 0x0a000000, + 0x0a800000, + 0x0b000000, + 0x0b800000, + 0x0c000000, + 0x0c800000, + 0x0d000000, + 0x0d800000, + 0x0e000000, + 0x0e800000, + 0x0f000000, + 0x47800000, + 0x80000000, + 0x80800000, + 0x81000000, + 0x81800000, + 0x82000000, + 0x82800000, + 0x83000000, + 0x83800000, + 0x84000000, + 0x84800000, + 0x85000000, + 0x85800000, + 0x86000000, + 0x86800000, + 0x87000000, + 0x87800000, + 0x88000000, + 0x88800000, + 0x89000000, + 0x89800000, + 0x8a000000, + 0x8a800000, + 0x8b000000, + 0x8b800000, + 0x8c000000, + 0x8c800000, + 0x8d000000, + 0x8d800000, + 0x8e000000, + 0x8e800000, + 0x8f000000, + 0xc7800000, + }; + + const static unsigned g_offset[64] = { + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + }; + + float float16ToFloat32(unsigned short h) + { + unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return bitCast(i32); + } + + +//------------------------------------------------------------------------------- +bool PictureIO::TgaSave(const Picture &picture, const char *uri) +{ + if ( + (picture.GetPixelFormat() != PixelFormat::RGBA8) && + (picture.GetPixelFormat() != PixelFormat::BGRA8) && + (picture.GetPixelFormat() != PixelFormat::BGR8) && + (picture.GetPixelFormat() != PixelFormat::RGB8) && + (picture.GetPixelFormat() != PixelFormat::RGB555) && + (picture.GetPixelFormat() != PixelFormat::RGBAF) + ) + __ERR__(__LOG_E__ << "Only supports BGRA8/BGR8/RGB24/RGB555.\n", false) + + AutoPtr h(Platform::Get().io->Open(uri, IO::ModeWrite)); + if (h.IsNull()) + __ERR__(__LOG_E__ << "Cannot write to '" << uri << "'.\n", false) + + // Dump header. + char header[18]; + for (uint n = 0; n < 18; n++) + header[n] = 0; + + header[2] = 2; + header[12] = (char)(picture.GetWidth() & 255); + header[13] = (char)((picture.GetWidth() >> 8) & 255); + header[14] = (char)(picture.GetHeight() & 255); + header[15] = (char)((picture.GetHeight() >> 8) & 255); + header[16] = 32;//picture.GetBpp(); + header[17] = 0x20 | picture.GetPixelFormat().acount; // We output straight picture. + h->Write(header, 18); + + // Dump data. + if (picture.GetBpp() == 32) + { + uchar *pdata = picture.GetData(); + for (uint n = 0; n < picture.GetWidth() * picture.GetHeight(); ++n) + { + h->Write (pdata[picture.GetPixelFormat().bshift >> 3]); + h->Write (pdata[picture.GetPixelFormat().gshift >> 3]); + h->Write (pdata[picture.GetPixelFormat().rshift >> 3]); + h->Write (pdata[picture.GetPixelFormat().ashift >> 3]); + pdata += 4; + } + } + else + { + unsigned short *pdata = (unsigned short*)picture.GetData(); + for (uint n = 0; n < picture.GetWidth() * picture.GetHeight(); ++n) + { + h->Write (((uchar)(Types::Clamp(float16ToFloat32(pdata[2])*255.f, 0, 255)))); + h->Write (((uchar)(Types::Clamp(float16ToFloat32(pdata[1])*255.f, 0, 255)))); + h->Write (((uchar)(Types::Clamp(float16ToFloat32(pdata[0])*255.f, 0, 255)))); + h->Write (((uchar)(Types::Clamp(float16ToFloat32(pdata[3])*255.f, 0, 255)))); + pdata += 4; + } + } + // h->Write(picture.GetData(), picture.GetWidth() * picture.GetHeight() * (picture.GetBpp() >> 3)); + + return true; +} +//------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------- +static void ReadTgaPalette(uchar pbpp, Array &plt, IO::Handle &handle) +{ + if (pbpp < 16) + __ERRRAW__(__LOG_E__ << "Palette is in unsupported pixel format (neither RGB16, RGB24 or BGR8).\n") + + Array _plt; + if (!plt.Allocate(256) || !_plt.Allocate(256 * (pbpp / 8))) + __ERRRAW__(__LOG_E__ << "Could not allocate temporary palette.\n") + + handle.Read(&_plt[0], 256 * (pbpp / 8)); + + // Convert palette to BGRA8. + for (int n = 0; n < 256; n++) + switch (pbpp) + { + case 16: + break; + case 24: + plt[n] = (_plt[n * 3 + 2] == 255) && (_plt[n * 3 + 1] == 0) && (_plt[n * 3 + 0] == 255) ? 0x00000000 : 0xff000000; + plt[n] |= (_plt[n * 3 + 2] << 16) + (_plt[n * 3 + 1] << 8) + _plt[n * 3 + 0]; + ToHost(&plt[n], 4, Intel); + break; + case 32: + break; + } +} +static bool TgaDecodeIndexed(const Picture &picture, int &i, IO::Handle &handle, uchar *&ob, const Array &plt) +{ + Array scan(picture.GetWidth(), Alloc::Picture); + if (!scan) + return false; + + // Read scanline. + i = picture.GetHeight(); + + while (i--) + { + if (handle.Read(&scan[0], picture.GetWidth()) == (uint)EOF) + break; + + uchar *b = scan; + for (uint n = 0; n < picture.GetWidth(); n++) + { + *(uint *)ob = plt[b[n]]; + ob += 4; + } + } + return true; +} +static void TgaDecodeRLEIndexed(uchar *ob, const Picture &picture, IO::Handle &handle, const Array &plt, uchar *read_buffer) +{ + uchar input[5]; + uint c = 0, RLErun; + uint *_ob = (uint *)ob; + + while (c < uint(picture.GetWidth() * picture.GetHeight())) + { + handle.Read(input, 2); + + if (input[0] > 127) + { + RLErun = input[0] - 127; + c += RLErun; + for (uint _r = 0; _r < RLErun; _r++) + *_ob++ = plt[input[1]]; + } + else + { + RLErun = input[0]; + *_ob++ = plt[input[1]]; + c += RLErun + 1; + + while (RLErun) + { + uint packet_size = RLErun > 48 ? 48 : RLErun; + handle.Read(read_buffer, packet_size); + + uchar *prb = read_buffer; + RLErun -= packet_size; + while (packet_size--) + *_ob++ = plt[*prb++]; + } + } + } +} +static bool TgaDecodeRaw(ushort obpp, IO::Handle &handle, uchar *&ob, const Picture &picture, int &i) +{ + if (obpp == 32) + { + handle.Read(ob, picture.GetWidth() * picture.GetHeight() * 4); + ob += picture.GetWidth() * picture.GetHeight() * 4; + } + else + { + // Allocate scan line. + Array scan(picture.GetWidth() * (obpp >> 3), Alloc::Picture); + if (!scan) + return false; + + // Convert scanline. + for (i = picture.GetHeight(); i; --i) + { + if (handle.Read(scan, picture.GetWidth() * (obpp >> 3)) == (uint)EOF) + break; + uchar *b = scan; + + switch (obpp) + { + case 8: + for (uint n = 0; n < picture.GetWidth() * 4; n += 4) + { + uchar c = *b++; + ob[n] = c; + ob[n + 1] = c; + ob[n + 2] = c; + ob[n + 3] = c; + } + break; + + case 16: + for (uint n = 0; n < picture.GetWidth() * 4; n += 4) + { + ushort _w = (b[1] << 8) + b[0]; + b += 2; + ob[n + 3] = 255; + ob[n + 2] = (uchar)((_w & 0x7c00) >> 7); + ob[n + 1] = (uchar)((_w & 0x3e0) >> 2); + ob[n] = (uchar)((_w & 0x1f) << 3); + } + break; + + case 24: + for (uint n = 0; n < picture.GetWidth() * 4; n += 4) + { + ob[n] = *b++; + ob[n + 1] = *b++; + ob[n + 2] = *b++; + ob[n + 3] = 255; + } + break; + } + ob += picture.GetWidth() * 4; + } + } + return true; +} +static void TgaDecodeRLE(uchar *ob, ushort obpp, const Picture &picture, IO::Handle &handle, uchar *read_buffer) +{ + uchar input[5]; + uint c = 0, tmp, RLErun; + uint *_ob = (uint *)ob; + + switch (obpp) + { + case 16: + while (c < uint(picture.GetWidth() * picture.GetHeight())) + { + handle.Read(input, 3); + + if (input[0] > 127) + { + RLErun = input[0] - 127; + tmp = (input[2] << 8) + input[1]; + tmp = 0xff000000 + (((tmp >> 10) & 31) << (3+16)) + (((tmp >> 5) & 31) << (3+8)) + ((tmp & 31) << 3); + ToHost(&tmp, 4, Intel); + + c += RLErun; + for (uint _r = 0; _r < RLErun; _r++) + *_ob++ = tmp; + } + else + { + RLErun = input[0]; + tmp = (input[2] << 8) + input[1]; + *_ob++ = 0xff000000 + (((tmp >> 10) & 31) << (3+16)) + (((tmp >> 5) & 31) << (3+8)) + ((tmp & 31) << 3); + c += RLErun + 1; + + while (RLErun) + { + uint packet_size = RLErun > 48 ? 48 : RLErun; + handle.Read(read_buffer, 2 * packet_size); + + uchar *prb = read_buffer; + RLErun -= packet_size; + while (packet_size--) + { + tmp = (prb[1] << 8) + input[0]; + prb += 2; + _ob[0] = 0xff000000 + (((tmp >> 10) & 31) << (3+16)) + (((tmp >> 5) & 31) << (3+8)) + ((tmp & 31) << 3); + ToHost(_ob, 4, Intel); + _ob++; + } + } + } + } + break; + + case 24: + while (c < uint(picture.GetWidth() * picture.GetHeight())) + { + handle.Read(input, 4); + + if (input[0] > 127) + { + RLErun = input[0] - 127; + tmp = 0xff000000 + (input[3] << 16) + (input[2] << 8) + input[1]; + ToHost(&tmp, 4); + c += RLErun; + + for (uint c2 = 0; c2 < RLErun; c2++) + *_ob++ = tmp; + } + else + { + RLErun = input[0]; + *_ob++ = 0xff000000 + (input[3] << 16) + (input[2] << 8) + input[1]; + c += RLErun + 1; + + while (RLErun) + { + uint packet_size = RLErun > 32 ? 32 : RLErun; + handle.Read(read_buffer, 3 * packet_size); + + uchar *prb = read_buffer; + RLErun -= packet_size; + while (packet_size--) + { + _ob[0] = 0xff000000 + (prb[2] << 16) + (prb[1] << 8) + prb[0]; + ToHost(_ob, 4); + _ob++; + prb += 3; + } + } + } + } + break; + + case 32: + while (c < uint(picture.GetWidth() * picture.GetHeight())) + { + handle.Read(input, 5); + + if (input[0] > 127) + { + RLErun = input[0] - 127; + tmp = (input[4] << 24) + (input[3] << 16) + (input[2] << 8) + input[1]; + ToHost(&tmp, 4); + c += RLErun; + + for (uint _r = 0; _r < RLErun; _r++) + *_ob++ = tmp; + } + else + { + RLErun = input[0]; + *_ob++ = (input[4] << 24) + (input[3] << 16) + (input[2] << 8) + input[1]; + c += RLErun + 1; + + while (RLErun) + { + uint packet_size = RLErun > 24 ? 24 : RLErun; + handle.Read(read_buffer, 4 * packet_size); + + uchar *prb = read_buffer; + RLErun -= packet_size; + while (packet_size--) + { + _ob[0] = (prb[3] << 24) + (prb[2] << 16) + (prb[1] << 8) + prb[0]; + ToHost(_ob, 4); + _ob++; + prb += 4; + } + } + } + } + break; + } +} +bool PictureIO::TgaLoad(Picture &picture, IO::Handle &handle) +{ + uchar *ob; + int i; + + handle.Rewind(); + + uchar bdum[18]; + ushort dum[9]; + handle.Read(dum, 18); + memcpy(bdum, dum, 18); + + for (uint n = 0; n < 9; ++n) + ToHost(&dum[n], 2, Intel); + + // Compression flag. We only support RAW/RLE TGA. + if ((dum[1] != 0x1) && (dum[1] != 0x2) && (dum[1] != 0x3) && (dum[1] != 0x9) && (dum[1] != 0xa)) + { + /* + If we don't support the mode then it certainly is because + the file is not a TGA so we just exit silently. + */ + return false; + } + + // Bpp. + ushort obpp = dum[8] & 255; +/* + if ((dum[1] != 0x1) && (dum[1] != 0x2) && (dum[1] != 0x3) && (dum[1] != 0x9)) + __ERR__(__LOG_E__ << "Unsupported format.\n", false) +*/ + // Palette format. + uchar pbpp = (dum[3] & 0xff00) >> 8; + Array plt(Alloc::Picture); + + // Read and convert palette. + if ((dum[1] == 0x1) || (dum[1] == 0x9)) + ReadTgaPalette(pbpp, plt, handle); + + // Canvas dimension. + // TODO Load in the native source format? + picture.AllocAs((uint)dum[6], (uint)dum[7], PixelFormat::BGRA8); + if ((ob = picture.GetData()) == NULL) + return false; + + // Decode. + int data_offset = bdum[0]; + handle.Seek(data_offset); // Skip to data. + + uchar read_buffer[96]; // Small local cache to minimize fread() calls. + + switch (dum[1]) + { + case 0x1: + if (!TgaDecodeIndexed(picture, i, handle, ob, plt)) + return false; + break; + + case 0x2: + case 0x3: + if (!TgaDecodeRaw(obpp, handle, ob, picture, i)) + return false; + break; + + case 0x9: + TgaDecodeRLEIndexed(ob, picture, handle, plt, read_buffer); + break; + + case 0xa: + TgaDecodeRLE(ob, obpp, picture, handle, read_buffer); + break; + } + + /* + Orientation (Can be made faster but the goal here + is to use as little memory as possible.) + */ + if ((dum[8] & 0x2000) ^ 0x2000) + picture.Flip(false, true); + + return true; +} +//------------------------------------------------------------------------------- diff --git a/include/framework/picture/pict_tools.cpp b/include/framework/picture/pict_tools.cpp new file mode 100644 index 0000000..c1e97e1 --- /dev/null +++ b/include/framework/picture/pict_tools.cpp @@ -0,0 +1,122 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "picture/pict_tools.h" + #include "picture/pict.h" + + using namespace GS; + + +namespace GS { + namespace PictureTools { + +bool Compare(const Picture &a, const Picture &b, float threshold) +{ + if ((a.GetWidth() != b.GetWidth()) || (a.GetHeight() != b.GetHeight())) + return false; + + float dt = 0.f; + for (uint y = 0; y < a.GetHeight(); ++y) + for (uint x = 0; x < a.GetWidth(); ++x) + for (int c = 0; c < 4; ++c) + dt += (a.GetDataOffset(x, y)[c] - b.GetDataOffset(x, y)[c]) / 255.f; + + return asbool(dt <= threshold); +} + + } // PictureTools +} // GS + +//------------------------------------------------------------------------------ +bool Picture::Fill(float r, float g, float b, float a, const iRect *rect, bool lock_alpha) +{ + uint *data = (uint *)GetData(); + + if (GetBpp() != 32) + return false; + if (!data) + return false; + + // Convert color. + uint fill = GetPixelFormat().Format(r, g, b, a); + + uchar ur = uchar(r * 255), + ug = uchar(g * 255), + ub = uchar(b * 255)/*, + ua = uchar(a * 255)*/; + + if (rect) + { + Rect _rect = rect->Intersection(GetRect()); + + if ((_rect.sy >= _rect.ey) || (_rect.sx >= _rect.ex)) + return false; + + data += _rect.sx + _rect.sy * width; + for (int y = 0; y < _rect.GetHeight(); ++y) + { + if (lock_alpha) + { + uchar *scan = (uchar *)data; + for (int x = 0; x < _rect.GetWidth(); ++x) + { + scan[GetPixelFormat().rshift >> 3] = ur; + scan[GetPixelFormat().gshift >> 3] = ug; + scan[GetPixelFormat().bshift >> 3] = ub; + // scan[GetPixelFormat().ashift >> 3] = ua; + scan += 4; + } + } + else + { + uint *scan = data; + for (int x = 0; x < _rect.GetWidth(); ++x) + *scan++ = fill; + } + data += width; + } + } + else + { + if (lock_alpha) + { + uchar *scan = (uchar *)data; + for (uint n = 0; n < GetWidth() * GetHeight(); n++) + { + scan[GetPixelFormat().rshift >> 3] = ur; + scan[GetPixelFormat().gshift >> 3] = ug; + scan[GetPixelFormat().bshift >> 3] = ub; + // scan[GetPixelFormat().ashift >> 3] = ua; + scan += 4; + } + } + else + for (uint n = 0; n < GetWidth() * GetHeight(); n++) + data[n] = fill; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Picture::ToGrayscale() +{ + if (!(GetWidth() && GetHeight())) + return false; + if (GetBpp() != 32) + return false; + + uchar *ptr = GetData(); + for (uint y = 0; y < GetHeight(); y++) + for (uint x = 0; x < GetWidth(); x++) + { + int v = (ptr[0] + ptr[1] + ptr[2]) / 3; + ptr[0] = ptr[1] = ptr[2] = (uchar)v; + ptr += 4; + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/framework/picture/pict_yuv_tools.cpp b/include/framework/picture/pict_yuv_tools.cpp new file mode 100644 index 0000000..a331309 --- /dev/null +++ b/include/framework/picture/pict_yuv_tools.cpp @@ -0,0 +1,206 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "picture/pict.h" + #if __PLATFORM_WINDOWS__ && __MMX__ + #include "mmintrin.h" + #endif + + using namespace GS; + + +//------------------------------------------------------------------------------ +static void mmx_yuv2rgb (uchar *py, uchar *pu, uchar *pv, uchar *image) +{ +#if __PLATFORM_WINDOWS__ && __MMX__ + static __m64 mmx_80w = {0x0080008000800080LL}; + static __m64 mmx_U_green = {0xf37df37df37df37dLL}; + static __m64 mmx_U_blue = {0x4093409340934093LL}; + static __m64 mmx_V_red = {0x3312331233123312LL}; + static __m64 mmx_V_green = {0xe5fce5fce5fce5fcLL}; + static __m64 mmx_10w = {0x1010101010101010LL}; + static __m64 mmx_00ffw = {0x00ff00ff00ff00ffLL}; + static __m64 mmx_Y_coeff = {0x253f253f253f253fLL}; + static __m64 mmx_A_unpack = {0xffffffffffffffffLL}; + + __asm + { + push esi + pxor mm4, mm4 ; mm4 = 0 + + mov esi, pu + movd mm0, [esi] ; mm0 = 00 00 00 00 u3 u2 u1 u0 + mov esi, pv + movd mm1, [esi] ; mm1 = 00 00 00 00 v3 v2 v1 v0 + mov esi, py + movq mm6, [esi] ; mm6 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + + ; Multiply part of the conversion. + punpcklbw mm0, mm4 ; mm0 = u3 u2 u1 u0 + punpcklbw mm1, mm4 ; mm1 = v3 v2 v1 v0 + psubsw mm0, mmx_80w ; u -= 128 + psubsw mm1, mmx_80w ; v -= 128 + psllw mm0, 3 ; promote precision + psllw mm1, 3 ; promote precision + movq mm2, mm0 ; mm2 = u3 u2 u1 u0 + movq mm3, mm1 ; mm3 = v3 v2 v1 v0 + pmulhw mm2, mmx_U_green ; mm2 = u * u_green + pmulhw mm3, mmx_V_green ; mm3 = v * v_green + pmulhw mm0, mmx_U_blue ; mm0 = chroma_b + pmulhw mm1, mmx_V_red ; mm1 = chroma_r + paddsw mm2, mm3 ; mm2 = chroma_g + + psubusb mm6, mmx_10w ; Y -= 16 + movq mm7, mm6 ; mm7 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + pand mm6, mmx_00ffw ; mm6 = Y6 Y4 Y2 Y0 + psrlw mm7, 8 ; mm7 = Y7 Y5 Y3 Y1 + psllw mm6, 3 ; promote precision + psllw mm7, 3 ; promote precision + pmulhw mm6, mmx_Y_coeff ; mm6 = luma_rgb even + pmulhw mm7, mmx_Y_coeff ; mm7 = luma_rgb odd + + ; Addition part of the conversion for even and odd pixels. + movq mm3, mm0 ; mm3 = chroma_b + movq mm4, mm1 ; mm4 = chroma_r + movq mm5, mm2 ; mm5 = chroma_g + paddsw mm0, mm6 ; mm0 = B6 B4 B2 B0 + paddsw mm3, mm7 ; mm3 = B7 B5 B3 B1 + paddsw mm1, mm6 ; mm1 = R6 R4 R2 R0 + paddsw mm4, mm7 ; mm4 = R7 R5 R3 R1 + paddsw mm2, mm6 ; mm2 = G6 G4 G2 G0 + paddsw mm5, mm7 ; mm5 = G7 G5 G3 G1 + packuswb mm0, mm0 ; saturate to 0-255 + packuswb mm1, mm1 ; saturate to 0-255 + packuswb mm2, mm2 ; saturate to 0-255 + packuswb mm3, mm3 ; saturate to 0-255 + packuswb mm4, mm4 ; saturate to 0-255 + packuswb mm5, mm5 ; saturate to 0-255 + punpcklbw mm0, mm3 ; mm0 = B7 B6 B5 B4 B3 B2 B1 B0 + punpcklbw mm1, mm4 ; mm1 = R7 R6 R5 R4 R3 R2 R1 R0 + punpcklbw mm2, mm5 ; mm2 = G7 G6 G5 G4 G3 G2 G1 G0 + + mov esi, image + ;pxor mm3, mm3 + movq mm3, mmx_A_unpack + movq mm6, mm0 + movq mm7, mm1 + movq mm4, mm0 + movq mm5, mm1 + punpcklbw mm6, mm2 + punpcklbw mm7, mm3 + punpcklwd mm6, mm7 + movq [esi], mm6 + movq mm6, mm0 + punpcklbw mm6, mm2 + punpckhwd mm6, mm7 + movq [esi + 8], mm6 + punpckhbw mm4, mm2 + punpckhbw mm5, mm3 + punpcklwd mm4, mm5 + movq [esi + 16], mm4 + movq mm4, mm0 + punpckhbw mm4, mm2 + punpckhwd mm4, mm5 + movq [esi + 24], mm4 + pop esi + + emms + } +#endif +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Picture::YUV422toRGB32(uchar * const yuv_plane[3], uchar *rgb32, int width, int height, int dst_pitch, int dst_height) +{ + // Default pitch if none specified. + if (!dst_pitch) + dst_pitch = width * 4; + if (!dst_height) + dst_height = height; + + // Target resolution. + int c_width = dst_pitch / 4; + + if (width < c_width) + c_width = width; + if (height < dst_height) + dst_height = height; + + #pragma omp parallel for + for (int y = 0; y < dst_height; ++y) + { + uchar *p_out = rgb32 + dst_pitch * y, + *p_yuv[3] = { + yuv_plane[0] + width * y, + yuv_plane[1] + (width / 2) * (y / 2), + yuv_plane[2] + (width / 2) * (y / 2) + }; + + // Convert scan line. + for (int x = 0; x < c_width; x += 8) + { + mmx_yuv2rgb(p_yuv[0], p_yuv[1], p_yuv[2], p_out); + + p_yuv[0] += 8; + p_yuv[1] += 4; + p_yuv[2] += 4; + p_out += 32; + } + } +} +void Picture::UnpackYCbCr(uchar *y, uchar *cb, uchar *cr) +{ + if (!y || !cb || !cr || (GetBpp() != 32)) + return; + + uchar *pdata = GetData(); + for (uint n = 0; n < (GetHeight() * GetWidth()); ++n) + { + float r = (float)pdata[0], g = (float)pdata[1], b = (float)pdata[2]; + + *y++ = (uchar)( 0.2990f * r + 0.5870f * g + 0.1140f * b + 0.5f); + *cb++ = (uchar)(-0.1687f * r - 0.3313f * g + 0.5000f * b + 128.f + 0.5f); + *cr++ = (uchar)( 0.5000f * r - 0.4187f * g - 0.0813f * b + 128.f + 0.5f); + pdata += 4; + } +} +void Picture::PackYCbCr(uchar *y, uchar *cb, uchar *cr) +{ + if (!y || !cb || !cr || (GetBpp() != 32)) + return; + + uchar *pdata = GetData(); + for (uint n = 0; n < (GetHeight() * GetWidth()); ++n) + { + float _y = (float)*y++, _cb = ((float)*cb++) - 128.f, _cr = ((float)*cr++) - 128.f; + + float r = _y + 1.402f * _cr; + float g = _y - 0.34414f * _cb - 0.71414f * _cr; + float b = _y + 1.77200f * _cb; + + if (r < 0) + pdata[0] = 0; + else if (r > 255.f) + pdata[0] = 255; + else pdata[0] = (uchar)r; + + if (g < 0) + pdata[1] = 0; + else if (g > 255.f) + pdata[1] = 255; + else pdata[1] = (uchar)g; + + if (b < 0) + pdata[2] = 0; + else if (b > 255.f) + pdata[2] = 255; + else pdata[2] = (uchar)b; + + pdata += 4; + } +} +//------------------------------------------------------------------------------ diff --git a/include/framework/plugin/shared_systems.cpp b/include/framework/plugin/shared_systems.cpp new file mode 100644 index 0000000..b8ac0b9 --- /dev/null +++ b/include/framework/plugin/shared_systems.cpp @@ -0,0 +1,31 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "plugin/shared_systems.h" + #include "picture/pict_io.h" + #include "audio/audio_io.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void SharedSystems::Get() +{ + platform = &Platform::Get(); + log_system = &LogSystem::Get(); + picture_io = &PictureIO::Get(); + audio_io = &AudioIO::Get(); +} +void SharedSystems::Set() +{ + Platform::Set(platform); + LogSystem::Set(log_system); + PictureIO::Set(picture_io); + AudioIO::Set(audio_io); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/sort/sort.cpp b/include/framework/sort/sort.cpp new file mode 100644 index 0000000..a6a59d9 --- /dev/null +++ b/include/framework/sort/sort.cpp @@ -0,0 +1,7 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "sort/sort.h" diff --git a/include/framework/timing/benchmark.cpp b/include/framework/timing/benchmark.cpp new file mode 100644 index 0000000..265641f --- /dev/null +++ b/include/framework/timing/benchmark.cpp @@ -0,0 +1,39 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "timing/benchmark.h" + #include "sort/sort.h" + #include "platform.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void Benchmark::Start() +{ + r_clock = Platform::Get().GetTime(); +} +void Benchmark::Stop() +{ + Time c_clock = Platform::Get().GetTime(); + + t_clock += c_clock - r_clock; + r_clock = c_clock; +} +float Benchmark::GetMs() const +{ return avg.GetMedian(); } +void Benchmark::Reset() +{ + avg.LogValue(t_clock.toMs()); + t_clock.setSec(0); +} + +Benchmark::Benchmark(bool start) +{ + if (start) + Start(); +} +//------------------------------------------------------------------------------ diff --git a/include/framework/timing/loop_benchmark.cpp b/include/framework/timing/loop_benchmark.cpp new file mode 100644 index 0000000..3953ad5 --- /dev/null +++ b/include/framework/timing/loop_benchmark.cpp @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "timing/loop_benchmark.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void LoopBenchmark::MarkLoop() +{ + ++loop_count; + + Time c_time = Platform::Get().GetTime(); + + t_time += c_time - r_time; + r_time = c_time; + + float t_ms = t_time.toMs(); + + if (t_ms > 1000.f) + { + ms = t_ms / loop_count; + + loop_count = 0; + t_time.setSec(0); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float LoopBenchmark::GetMs() const +{ return ms; } +float LoopBenchmark::GetFps() const +{ return ms ? 1000.f / ms : 0.f; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void LoopBenchmark::Reset() +{ + ms = 0.f; + + loop_count = 0; + + r_time = Platform::Get().GetTime(); + t_time.setSec(0); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/archive/archive.cpp b/include/modules/archive/archive.cpp new file mode 100644 index 0000000..ba4567b --- /dev/null +++ b/include/modules/archive/archive.cpp @@ -0,0 +1,440 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "zlib.h" + #include "archive/archive.h" + #include "metafile/nml.h" + #include "filesystem/filesystem.h" + #include "thread/mutex.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::NML; + + +//------------------------------------------------------------------------------ +#define __CorrectOffsetPadding \ +{\ + if (offset_padding)\ + {\ + size_t error = handle->Tell() % offset_padding;\ + if (error)\ + handle->Seek((long)(offset_padding - error));\ + }\ +} +bool ArchiveIndex::Load(const char *uri) +{ + index.Clear(); + + __LOG_V__ << "Loading archive index '" << uri << "'...\n"; + + File file; + if (!Parser::Load(uri, file)) + return false; + + // Grab index tag. + Tag *index_tag = file.GetTag("Index;"); + if (!index_tag) + __ERR__(__LOG_E__ << "No archive index tag found in '" << uri << "'.\n", false) + + // Pool for entries. + NMLTagForeach(t, *index_tag) + if (t->name == "Entry") + { + Tag *id_tag = t->GetTypedTag("ID;", Variant::VariantString), + *compressed_tag = t->GetTypedTag("CompLen", Variant::VariantInteger), + *length_tag = t->GetTypedTag("Len", Variant::VariantInteger), + *method_tag = t->GetTypedTag("Method", Variant::VariantString), + *offset_tag = t->GetTypedTag("Offset", Variant::VariantInteger); + + if (id_tag && compressed_tag && length_tag && method_tag) + { + // Import the entry. + if (ArchiveEntry *entry = new ArchiveEntry) + { + entry->path = id_tag->GetString(); + entry->length = length_tag->GetInteger(); + entry->compressed_length = compressed_tag->GetInteger(); + entry->offset = offset_tag->GetInteger(); + + String method(method_tag->GetString()); + + if (method == "Raw") + entry->method = ArchiveEntry::MethodRaw; + else if (method == "Zlib") + entry->method = ArchiveEntry::MethodZLibCompress; + + index.Add(entry); + } + else + __LOG_E__ << "Failed to allocate new archive index entry.\n"; + } + else + __LOG_E__ << "Incomplete index entry.\n"; + } + else + __LOG_W__ << "Unexpected tag <" << t->name << "> in .\n"; + + __LOG_V__ << "Done, found " << index.GetCount() << " entries.\n"; + return true; +} +bool ArchiveIndex::Save(const char *uri) +{ + File file; + Tag *index_tag = file.AddRoot("Index"); + + ListForeachPtr(ArchiveEntry *, entry, index) + { + // Create entry. + Tag *entry_tag = index_tag->AddChild("Entry"); + + entry_tag->AddChild("ID", entry->path.c_str()); + entry_tag->AddChild("CompLen", (int)entry->compressed_length); + entry_tag->AddChild("Len", (int)entry->length); + entry_tag->AddChild("Offset", (int)entry->offset); + + switch (entry->method) + { + case ArchiveEntry::MethodRaw: + entry_tag->AddChild("Method", "Raw"); + break; + + case ArchiveEntry::MethodZLibCompress: + entry_tag->AddChild("Method", "Zlib"); + break; + } + } + + return Parser::Save(uri, file); +} +ArchiveEntry *ArchiveIndex::FindEntry(const char *alias) const +{ + ListForeachPtr(ArchiveEntry *, e, index) + if (e->path == alias) + return e; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Archive::LoadIndex(const char *uri) +{ return index.Load(uri); } +bool Archive::SaveIndex(const char *uri) +{ return index.Save(uri); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Archive::OpenRead(const char *uri, const char *idx) +{ + Close(); + if (!uri) + __ERR__(__LOG_E__ << "No archive to open.\n", false) + + if (!(handle = Platform::Get().io->Open(uri))) + __ERR__(__LOG_E__ << "Failed to open archive '" << uri << "'.\n", false) + + // Check archive header. + __CorrectOffsetPadding + + uint magic_word = handle->Read (); + + if (magic_word == 0x4E415244) // 'NARD' (padding support). + { + __CorrectOffsetPadding + offset_padding = handle->Read (); + __CorrectOffsetPadding + size_padding = handle->Read (); + revision = EnhancedLegacy; + } + else if (magic_word == 0x4E415243) // 'NARC' backward compatibility. + { + offset_padding = 0; + size_padding = 0; + revision = Legacy; + } + else + { + __LOG_E__ << "Invalid archive type '" << uri << "'.\n"; + Close(); + return false; + } + + // Open or create index if none provided. + if (!idx) + { + size_t alen = handle->GetSize(); + + if (verbose) + __LOG__ << "No index provided, please wait while scanning archive...\n"; + + while (handle->Tell() < alen) + { + // Fetch alias. + char tmp[512]; + __CorrectOffsetPadding + uint tsz = handle->Read (); + + if (tsz > 511) + break; + + else + { + handle->Read((void *)tmp, tsz); + tmp[tsz] = 0; + } + + // Attributes. + __CorrectOffsetPadding + char cmp = handle->Read () & 1; + __CorrectOffsetPadding + uint len = handle->Read (), clen = len; + if (cmp) + { + __CorrectOffsetPadding + clen = handle->Read (); + } + + // Store in index. + if (ArchiveEntry *entry = new ArchiveEntry) + { + entry->path = tmp; + entry->method = cmp; + entry->length = len; + entry->compressed_length = clen; + entry->offset = handle->Tell(); + index.index.Add(entry); + + if (verbose) + { + __LOG__ << "New entry: '" << entry->path << "'\n"; + __LOG__ << "[method = " << entry->method << ", len = " << (uint)entry->length << ", clen = " << (uint)entry->compressed_length << ", offset = " << (uint)entry->offset << "].\n"; + } + } + else + __LOG_E__ << "Could not allocate new index entry.\n"; + + handle->Seek(clen); + } + + if (verbose) + __LOG__ << "Done, index table built.\n\n"; + } + else + { + LoadIndex(idx); + + if (verbose) + ListForeachPtr(ArchiveEntry *, entry, index.index) + { + __LOG__ << "New entry: '" << entry->path << "'\n"; + __LOG__ << "[method = " << entry->method << ", len = " << (uint)entry->length << ", clen = " << (uint)entry->compressed_length << ", offset = " << (uint)entry->offset << "].\n"; + } + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Archive::CreateNew(const char *uri) +{ + Close(); + + if (!(handle = Platform::Get().io->Open(uri, IO::ModeWrite))) + __ERR__(__LOG_E__ << "Failed to open '" << uri << "' as output archive.\n", false) + + // Output header. + __CorrectOffsetPadding + handle->Write (0x4E415244); // 'NARD' + __CorrectOffsetPadding + handle->Write (offset_padding); + __CorrectOffsetPadding + handle->Write (size_padding); + + append_mode = true; + return true; +} +void Archive::Close() +{ + if (append_mode) + { + // EOF marker. + handle->Write (0xffffffff); + + // Size padding. + size_t size = handle->Tell(); + size_t pad_count = size_padding ? size_padding - size % size_padding : 0; + + for (size_t n = 0; n < pad_count; ++n) + handle->Write (0xff); // End of archive marker (entry id length > 512). + } + + // Close archive. + handle = NULL; + index.index.Clear(); + + if (append_mode) + __LOG__ << "Archive complete, closing.\n"; + append_mode = false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Archive::FileRead(const char *path, void *out) +{ + if (append_mode) + __ERR__(__LOG_E__ << "Cannot load '" << path << "' (r/w mode error).\n", false) + + ArchiveEntry *entry = Exists(path); + if (!entry) + __ERR__(__LOG_E__ << "Could not find '" << path << "'.\n", false) + + Threading::MutexLock lock(access_mutex); + + size_t h_cursor = handle->Tell(); + + switch (entry->method) + { + case ArchiveEntry::MethodRaw: + handle->Seek(entry->offset, IO::Base::SeekStart); // Note: Should be padded to the right offset already. + if (handle->Read(out, entry->length) != entry->length) + __LOG_E__ << "Failed to load raw source.\n"; + break; + + case ArchiveEntry::MethodZLibCompress: + { + handle->Seek(entry->offset, IO::Base::SeekStart); // Note: Should be padded to the right offset already. + + Array cp((uint)(entry->compressed_length + 16)); + if (!cp) + __ERR__(__LOG_E__ << "Failed to allocated compressed memory support.\n", false) + + if (handle->Read((void *)cp, entry->compressed_length) != entry->compressed_length) + __ERR__(__LOG_E__ << "Failed to load compressed source.\n", false) + + uLong out_len = (uLong)entry->length; + uncompress((Bytef *)out, &out_len, (Bytef *)&cp[0], (uLong)entry->compressed_length); + } + break; + } + + handle->Seek(h_cursor, IO::Base::SeekStart); + return true; +} +//----------------------------------------------------------------- + +//------------------------------------------------------------------------------ +ArchiveEntry *Archive::MemoryBlockWrite(const char *alias, const void *in, size_t len, int level) +{ + if (!append_mode || !len) + __ERR__(__LOG_E__ << "Cannot write '" << alias << "' (r/w mode error).\n", NULL) + + Threading::MutexLock lock(access_mutex); + + // Ensure alias uniqueness. + if (ArchiveEntry *e = index.FindEntry(alias)) + return e; + + // Sync index. + ArchiveEntry *entry = new ArchiveEntry; + if (!entry) + __ERR__(__LOG_E__ << "Failed to allocate new index entry.\n", NULL) + entry->path = alias; + index.index.Add(entry); + + // Compress and add to archive. + Array out; + size_t clen; + + // Output alias. + __CorrectOffsetPadding + handle->Write (std::strlen(alias)); + __CorrectOffsetPadding + handle->Write((const void *)alias, std::strlen(alias)); + if (verbose) + __LOG_H__ << "Adding '" << alias << "' to archive...\n"; + + // Output data, ZLIB needs destination to be at least source * 100.1% + 12 bytes. + bool add_raw = true; + + if (level >= 0) + { + clen = len + (len / 1000 + 1) + 12; + + if (out.Allocate((uint)clen) && (compress2((Bytef *)&out[0], (uLongf *)&clen, (const Bytef *)in, (uLong)len, level) == Z_OK)) + { + // @TODO compression method as a bit flag here. + __CorrectOffsetPadding + handle->Write (1); + __CorrectOffsetPadding + handle->Write (len); + __CorrectOffsetPadding + handle->Write (clen); + + // Write compressed block. + __CorrectOffsetPadding + entry->method = ArchiveEntry::MethodZLibCompress; + entry->offset = handle->Tell(); + entry->length = len; + entry->compressed_length = clen; + + if (verbose) + __LOG__ << "Was " << (uint)(len / 1000) << " KB, is now " << (uint)(clen / 1000) << " KB (" << (uint)(clen * 100 / len) <<"%).\n"; + + handle->Write((const void *)out, clen); + add_raw = false; + } + else + if (verbose) + __LOG__ << "No compression achieved for '" << alias << "', adding uncompressed.\n"; + } + + if (add_raw) + { + __CorrectOffsetPadding + handle->Write (0); + __CorrectOffsetPadding + handle->Write (len); + + // Write raw block. + __CorrectOffsetPadding + + entry->method = ArchiveEntry::MethodRaw; + entry->offset = handle->Tell(); + entry->length = len; + entry->compressed_length = 0; + + handle->Write((const void *)in, len); + } + return entry; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ArchiveEntry *Archive::FileWrite(const char *path, const char *alias, int level) +{ + Array data; + if (!Platform::Get().io->FileLoad(path, data)) + return NULL; + return MemoryBlockWrite(alias ? alias : path, &data[0], data.GetSize(), level); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Archive::Archive() +{ + append_mode = false; + offset_padding = 0; + size_padding = 0; + + access_mutex = new Threading::Mutex; +} +Archive::~Archive() +{ + Close(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/audio_stream_ogg/audio_stream_ogg.cpp b/include/modules/audio_stream_ogg/audio_stream_ogg.cpp new file mode 100644 index 0000000..0b676ef --- /dev/null +++ b/include/modules/audio_stream_ogg/audio_stream_ogg.cpp @@ -0,0 +1,190 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "audio_stream_ogg/audio_stream_ogg.h" + #include "filesystem/filesystem.h" + #include "platform.h" + #include "log/log.h" + #include "stb_vorbis.c" + + using namespace GS; + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +bool AudioStreamOGG::Seek(int t_ms) +{ + /// Rewind the stream and seek to the correct frame. + int target = (vf->sample_rate * t_ms) / 1000; + + // Logic is broken when seeking below the first packet. + if (target < 1024) + { + h->Rewind(); + byte_left = 0; + + stb_vorbis_flush_pushdata(vf); + } + else + { + // TODO compute seek point and sample to skip. + int lo = 0, hi = h->GetSize(); + + forever + { + // Determine seek point. + int mid = (lo + hi) / 2; + + // Seek and reload push buffer. + h->Seek(mid, Base::SeekStart); + RefillBuffer(); + + stb_vorbis_flush_pushdata(vf); + + int ns = 0, ch = 0, cs = 0; + float **fo = NULL; + + forever + { + ConsumeBuffer(stb_vorbis_decode_frame_pushdata(vf, (uchar *)buffer.c_ptr(), byte_left, &ch, &fo, &ns)); + + if (ns) // Samples are coming in. + { + cs = stb_vorbis_get_sample_offset(vf); + if (cs != -1) // Sample located. + break; + } + } + + // Check if target sample is within reach. + if ((cs > (target - 24000)) && (cs <= target)) + forever + { + RefillBuffer(); + ConsumeBuffer(stb_vorbis_decode_frame_pushdata(vf, (uchar *)buffer.c_ptr(), byte_left, &ch, &fo, &ns)); + + int skip = target - cs; + if ((cs != -1) && (skip < ns)) + { + seek_correction = skip; + return true; + } + cs = stb_vorbis_get_sample_offset(vf); + } + + // Refine approximation. + if (cs > target) + hi = mid; + else + lo = mid; + } + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t AudioStreamOGG::GetPCMBufferSize() const +{ return vorbis_info.max_frame_size * format.channels * 2 * 2; } +size_t AudioStreamOGG::GetPCM(void *pcm) +{ + int ns, ch; + float **fo = NULL; + + RefillBuffer(); + ConsumeBuffer(stb_vorbis_decode_frame_pushdata(vf, (uchar *)buffer.c_ptr(), byte_left, &ch, &fo, &ns)); + + if (vf->error != VORBIS__no_error) + return 0; + + if (seek_correction) + { + for (int n = 0; n < ch; ++n) + fo[n] += seek_correction; + ns -= seek_correction; + seek_correction = 0; + } + if (ns < 0) + ns = 0; + + convert_channels_short_interleaved(ch, (short *)pcm, ch, fo, 0, ns); // size = ns * 2 * format.channels + return ns * 2 * format.channels; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t AudioStreamOGG::RefillBuffer() +{ + size_t request_size = buffer.GetSize() - byte_left; + size_t read = h->Read(&buffer[(int)byte_left], request_size); + byte_left += read; + return read; +} +void AudioStreamOGG::ConsumeBuffer(size_t size) +{ + memmove(buffer, &buffer[(int)size], byte_left - size); + byte_left -= size; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool AudioStreamOGG::IsEOF() const +{ + if (byte_left > 0) + return false; + if (h->IsEOF()) + return true; + return vf ? asbool(vf->eof) : false; +} +bool AudioStreamOGG::Open(const char *uri) +{ + h = Platform::Get().io->Open(uri); + if (!h) + return false; + + if (!buffer.Allocate(16384)) + return false; + + RefillBuffer(); + vf = stb_vorbis_open_pushdata((uchar *)buffer.c_ptr(), byte_left, &consumed, &err, NULL); + if (!vf) + { + h = NULL; + return false; + } + ConsumeBuffer(consumed); + + vorbis_info = stb_vorbis_get_info(vf); + seek_correction = 0; + + format.channels = vorbis_info.channels; + format.resolution = 16; + format.frequency = vorbis_info.sample_rate; + + __LOG_H__ << "Vorbis stream '" << uri << "' - " << vorbis_info.sample_rate << "hz 16bit " << vorbis_info.channels << " channel(s).\n"; + __LOG__ << " Max frame size = " << vorbis_info.max_frame_size << "\n"; + return true; +} +void AudioStreamOGG::Close() +{ + if (vf) + stb_vorbis_close(vf); + vf = NULL; + + __LOG_H__ << "Vorbis stream closed.\n"; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +AudioStreamOGG::AudioStreamOGG() +{ + vf = NULL; + seek_correction = 0; + byte_left = 0; +} +AudioStreamOGG::~AudioStreamOGG() +{ Close(); } +//------------------------------------------------------------------------------ diff --git a/include/modules/audio_stream_ogg/audio_stream_ogg_factory.cpp b/include/modules/audio_stream_ogg/audio_stream_ogg_factory.cpp new file mode 100644 index 0000000..a0044f9 --- /dev/null +++ b/include/modules/audio_stream_ogg/audio_stream_ogg_factory.cpp @@ -0,0 +1,21 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "audio_stream_ogg/audio_stream_ogg_factory.h" + #include "audio_stream_ogg/audio_stream_ogg.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +IAudioStream *OGGStreamFactory::Open(const char *path) +{ + AutoPtr stream(new AudioStreamOGG); + if (!stream->Open(path)) + return NULL; + return stream.Detach(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/debug_enet/network_debugger.cpp b/include/modules/debug_enet/network_debugger.cpp new file mode 100644 index 0000000..656b9c6 --- /dev/null +++ b/include/modules/debug_enet/network_debugger.cpp @@ -0,0 +1,136 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "network_debugger.h" + #include "network_debugger_thread.h" + #include "metafile/nml.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void NetworkDebugger::OnControllerPacketReceived(const Array &data) +{ + using namespace NML; + + Tag tag; + Parser::ParseTag(tag, data.Start(), data.End()); + + //---------------------------------------------------------------------- + if (tag.name == "Start") + start_signal = true; + else if (tag.name == "StepInto") + debugger->StepInto(); + else if (tag.name == "StepOver") + debugger->Step(); + else if (tag.name == "StepOut") + debugger->StepOut(); + else if (tag.name == "Resume") + debugger->Resume(); + //---------------------------------------------------------------------- + + //---------------------------------------------------------------------- + else if (tag.name == "SetDebugStackFrame") + debugger->SetDebugStackFrame(tag.GetInteger()); + else if (tag.name == "SetTopDebugStackFrame") + debugger->SetDebugStackFrame(-1); + + else if (tag.name == "RequestDebugStackFrameSource") + { + const char *source; int line; + debugger->GetStackFrameSource(source, line); + + if (source) + BroadcastNetworkCommand(String::Format(">", source, line)); + } + else if (tag.name == "RequestDebugCallStack") + BroadcastNetworkCommand(GetCallstack()); + else if (tag.name == "RequestDebugStackFrameLocals") + BroadcastNetworkCommand(GetDebugStackFrameLocals()); + else if (tag.name == "SetBreakpoints") + debugger->SetBreakpoints(tag); + //---------------------------------------------------------------------- +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String NetworkDebugger::GetPeerAddress() +{ + ASync::Future address; + thread->async.QueueMemberCall(address, thread, &NetworkDebuggerThread::GetControllerAddress); + return address.Get(); +} +bool NetworkDebugger::IsConnected() const +{ return thread->IsConnected(); } +void NetworkDebugger::Stop() +{ thread->Stop(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetworkDebugger::BroadcastNetworkCommand(const String &cmd) +{ + // Queue an asynchronous call to the controller thread. + thread->async.QueueMemberCall(thread, &NetworkDebuggerThread::SendToController, cmd); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetworkDebugger::OnSuspendExecution(const char *source, int line) +{ + // Set callstack, stack frame locals and source. + BroadcastNetworkCommand(GetCallstack()); + BroadcastNetworkCommand(debugger->GetStackFrameLocals()); + BroadcastNetworkCommand(String::Format(">", source, line)); +} +bool NetworkDebugger::OnUpdateSuspendedExecution() +{ + async.Execute(); // [EJ] execute calls pushed by the debug thread to us so that we may receive new packets + return thread->IsConnected(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetworkDebugger::OnFatalError(const char *reason) +{ + BroadcastNetworkCommand(String::Format(">", reason)); +} +void NetworkDebugger::OnCompilerError(const char *error, const char *source, int line) +{ + // Make sure the error location is displayed prior to the VM kill event being received. + BroadcastNetworkCommand(String::Format(">", source, line)); + BroadcastNetworkCommand(String::Format(">", error)); +} +void NetworkDebugger::OnRuntimeException(const char *error) +{ + BroadcastNetworkCommand(String::Format(">", error)); + + /* + ...then suspend all execution beside the server inspection communication + channels. The VM along with the executing program will die when this + function returns. + */ + while ((vm->GetState() == IVM::StateExceptionThrown) && thread->IsConnected()) + { + async.Execute(); + Threading::Thread::Switch(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NetworkDebugger::NetworkDebugger(IVM *vm, IDebugger *debugger, const char *address, int port) : IDebuggerProfiler(vm, debugger) +{ + start_signal = false; + + thread = new NetworkDebuggerThread(*this, address, port); + thread->Start(); +} +NetworkDebugger::~NetworkDebugger() +{ + _safe_delete(thread); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/debug_enet/network_debugger_thread.cpp b/include/modules/debug_enet/network_debugger_thread.cpp new file mode 100644 index 0000000..a0cc01b --- /dev/null +++ b/include/modules/debug_enet/network_debugger_thread.cpp @@ -0,0 +1,167 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "network_debugger_thread.h" + #include "network_debugger.h" + #include "core/engine.h" + #include "metafile/nml.h" + #include "log/log.h" + + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void NetworkDebuggerThread::OnPacketReceived(void *peer, const void *data, size_t size) +{ + using namespace NML; + + Tag tag; + Parser::ParseTag(tag, (char *)data, (char *)data + size); + + if (ctl_peer == NULL) + { + if (tag.name == "HelloMonitor") + { + Tag *client_version = tag.GetTag("Version;"); + + if (client_version->GetInteger() == 1) + { + ctl_peer = peer; + SendString(peer, String::Format(">", Platform::Get().GetName().c_str(), Core::Version)); + + ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnControllerConnected); + + connected.Set(1); + } + } + else + Disconnect(peer); + } + else if (ctl_peer == peer) + ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnControllerPacketReceived, Array ((uint)size, (const char *)data)); + else + Disconnect(peer); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetworkDebuggerThread::OnPeerConnection(void *peer) +{ + if (ctl_peer == NULL) + { + SetPeerTimeout(peer, TimeoutVeryLong); + SendString(peer, ""); + } + else + Disconnect(peer); +} +void NetworkDebuggerThread::OnConnectionClosed(void *peer) +{ + if (peer == ctl_peer) + { + ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnControllerDisconnected); + ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::Kill); + ctl_peer = NULL; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetworkDebuggerThread::SendToController(const GS::String &p) +{ + if (ctl_peer) + SendString(ctl_peer, p.c_str()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool NetworkDebuggerThread::OpenServer(const char *address, int port) +{ + if (!Network::Enet::OpenServer(address, port)) + return false; + + String host_address; + GetHostAddress(host_address); + ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnNetworkReady, host_address, port); + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +GS::String NetworkDebuggerThread::GetControllerAddress() +{ + String address; + if (ctl_peer) + GetPeerAddress(ctl_peer, address); + return address; +} +void NetworkDebuggerThread::DisconnectController() +{ + if (ctl_peer) + { + SendString(ctl_peer, ""); + connected.Set(0); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetworkDebuggerThread::Execute() +{ + Thread::SetName("NetworkDebuggerThread"); + + if (!OpenServer(address, port)) + return; + + for (state.Set(StateWaitingController); state.Get() != StateStop; ) + { + switch (state.Get()) + { + case StateWaitingController: if (ctl_peer) state.Set(StateControllerConnected); break; + case StateControllerConnected: if (ctl_peer == NULL) state.Set(StateStop); break; // if controller lost, stop debugger + } + + UpdateHost(); + + while (async.Execute()); + + Platform::Get().Sleep(1); + } + + DisconnectController(); + Close(); + + connected.Set(0); + + state.Set(StateStopped); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetworkDebuggerThread::Stop() +{ + if (state.Get() != StateStopped) + { + state.Set(StateStop); + while (state.Get() != StateStopped); // spinlock + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NetworkDebuggerThread::NetworkDebuggerThread(NetworkDebugger &h, const char *a, int p) : ctl(h) +{ + address = a; + port = p; + + ctl_peer = NULL; +} +NetworkDebuggerThread::~NetworkDebuggerThread() +{ + Stop(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/font_freetype/ft2_font.cpp b/include/modules/font_freetype/ft2_font.cpp new file mode 100644 index 0000000..e603844 --- /dev/null +++ b/include/modules/font_freetype/ft2_font.cpp @@ -0,0 +1,155 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "font_freetype/ft2_font.h" + #include "picture/pict.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +int Freetype2Font::GetAdvance() const +{ return face ? face->glyph->advance.x : 0; } +bool Freetype2Font::SetPixelSize(int size) +{ + if (face == 0) + return false; + + FT_Set_Pixel_Sizes(face, 0, size); + return true; +} +int Freetype2Font::GetHeight() const +{ return face ? face->size->metrics.height : 0; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Freetype2Font::HasKerning() const +{ return has_kerning; } +int Freetype2Font::GetKerning(uint previous_codepoint, uint codepoint) const +{ + if (face == 0) + return 0; + + FT_Vector delta; + FT_UInt previous_glyph_index = FT_Get_Char_Index(face, previous_codepoint), glyph_index = FT_Get_Char_Index(face, codepoint); + return FT_Get_Kerning(face, previous_glyph_index, glyph_index, FT_KERNING_DEFAULT, &delta) == 0 ? delta.x : 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Freetype2Font::LoadGlyph(uint codepoint, bool for_render) +{ + FT_UInt index = FT_Get_Char_Index(face, codepoint); + return FT_Load_Glyph(face, index, for_render ? FT_LOAD_RENDER : FT_LOAD_DEFAULT) == 0; +} +bool Freetype2Font::RenderCurrentGlyph(Picture &picture, const iPoint &position, const iRect &clip, const Color &color) +{ + if (face == 0) + return false; + + if (position.x >= clip.ex) + return true; + + int r_offset = picture.GetPixelFormat().rshift / 8, g_offset = picture.GetPixelFormat().gshift / 8, b_offset = picture.GetPixelFormat().bshift / 8, a_offset = picture.GetPixelFormat().ashift / 8; + int ir = int(color.x), ig = int(color.y), ib = int(color.z), ia = int(color.w); + + FT_GlyphSlot slot = face->glyph; + FT_Bitmap *bmp = &slot->bitmap; + unsigned char *bpt = bmp->buffer; + + if (!bpt) + return false; + + int pos_x = position.x + slot->bitmap_left; + int pos_y = position.y - slot->bitmap_top ; + + unsigned char *opt = picture.GetData() + (pos_y * picture.GetWidth() + pos_x) * 4; + + for (int y = 0; y < bmp->rows; ++y) + { + if ((pos_y >= clip.sy) && (pos_y < clip.ey)) + { + uchar *spt = opt; + for (int x = 0; x < bmp->width; ++x) + { + int tx = pos_x + x; + + if ((tx >= clip.sx) && (tx < clip.ex)) + { + #if 1 + uchar alpha = (uchar)((bpt[x] * ia) >> 8); + uchar a_blend = Picture::AlphaCompositeAlpha(spt[a_offset], alpha); + + spt[r_offset] = Picture::AlphaCompositeColor(spt[r_offset], ir, spt[a_offset], alpha, a_blend); + spt[g_offset] = Picture::AlphaCompositeColor(spt[g_offset], ig, spt[a_offset], alpha, a_blend); + spt[b_offset] = Picture::AlphaCompositeColor(spt[b_offset], ib, spt[a_offset], alpha, a_blend); + spt[a_offset] = a_blend; + #else + uchar alpha = (bpt[x] * (uchar)state.a) >> 8; + spt[r_offset] = (uchar)state.r; + spt[g_offset] = (uchar)state.g; + spt[b_offset] = (uchar)state.b; + spt[a_offset] = Types::Max(spt[a_offset], alpha); + #endif + } + spt += 4; + } + } + bpt += bmp->pitch; + opt += picture.GetWidth() * 4; + + pos_y++; + if (pos_y >= (int)clip.ey) + break; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +iRect Freetype2Font::GetTextBoundRect(const char *text) const +{ + FT_GlyphSlot slot = face->glyph; + FT_UInt previous = 0; + + iRect rc(0, 0, 0, 0); + if (!text) + return rc; + + forever + { + char c = *text++; + if (c == 0) + break; + if (c == '\n') + continue; + + FT_UInt glyph_index = FT_Get_Char_Index(face, c); + + if (has_kerning && previous && glyph_index) + { + FT_Vector delta; + FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); + rc.ex += delta.x; + } + if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT)) + continue; + + rc.ex += slot->advance.x; + if (slot->metrics.height > rc.ey) + rc.ey = slot->metrics.height; + previous = glyph_index; + } + + rc.ex >>= 6; + rc.ey >>= 6; + return rc; +} +//------------------------------------------------------------------------------ + +Freetype2Font::~Freetype2Font() +{ FT_Done_Face(face); } diff --git a/include/modules/font_freetype/ft2_font_factory.cpp b/include/modules/font_freetype/ft2_font_factory.cpp new file mode 100644 index 0000000..2efa627 --- /dev/null +++ b/include/modules/font_freetype/ft2_font_factory.cpp @@ -0,0 +1,42 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "font_freetype/ft2_font_factory.h" + #include "font_freetype/ft2_font.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +IFont *Freetype2FontFactory::LoadFont(const char *path) +{ + __LOG_H__ << "Freetype2: Loading font '" << path << "'.\n"; + AutoPtr font(new Freetype2Font); + + if (font.IsNull()) + return NULL; + + font->name = path; + if (!Platform::Get().io->FileLoad(path, font->buffer)) + return NULL; + + if (FT_New_Memory_Face(ft2, (const FT_Byte *)&font->buffer[0], font->buffer.GetSize(), 0, &font->face)) + __ERR__(__LOG_W__ << "Failed to open font file '" << path << "'.\n", NULL) + + font->has_kerning = true; // FT_HAS_KERNING + + return font.Detach(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Freetype2FontFactory::Freetype2FontFactory() +{ FT_Init_FreeType(&ft2); } +Freetype2FontFactory::~Freetype2FontFactory() +{ FT_Done_FreeType(ft2); } +//------------------------------------------------------------------------------ diff --git a/include/modules/http_curl/http_curl.cpp b/include/modules/http_curl/http_curl.cpp new file mode 100644 index 0000000..db0ffd0 --- /dev/null +++ b/include/modules/http_curl/http_curl.cpp @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "http_curl/http_curl.h" + #include "async/async_call_queue_thread.h" + #include "platform.h" + + using namespace GS::Threading; + using namespace GS::HTTP; + + +namespace GS { + namespace HTTP { + +//------------------------------------------------------------------------------ +class CurlThread : public ASyncCallQueueThread +{ + Curl *icurl; + void *curl; + +public: + + void Execute() + { + curl = curl_easy_init(); + if (!curl) + return; + + ASyncCallQueueThread::Execute(); + + curl_easy_cleanup(curl); + curl = NULL; + } + +static size_t WriteData(void *buffer, size_t size, size_t nmemb, void *userp) + { + Array *data = (Array *)userp; + + size_t offset = data->GetSize(); + size_t total_size = offset + size * nmemb; + if (!data->Reallocate(total_size)) + return 0; + + Memory::Copy(&data->c_ptr()[offset], buffer, size * nmemb); + return size * nmemb; + } + void Post(int ticket_id, const String &url, const String &post) + { + Array response; + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteData); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + if (curl_easy_perform(curl) == 0) + icurl->event_queue.QueueMemberCall(icurl, &Curl::OnRequestComplete, ticket_id, response); + else + icurl->event_queue.QueueMemberCall(icurl, &Curl::OnRequestError, ticket_id); + } + + CurlThread(Curl *c) : icurl(c), curl(0) {} +}; +//------------------------------------------------------------------------------ + + } // HTTP +} // GS + +//------------------------------------------------------------------------------ +int Curl::GetTicketId() +{ return u_ticket_id++; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Curl::Update() +{ + event_queue.ExecuteAll(); +} +int Curl::Post(const char *url, const char *post) +{ + int ticket_id = GetTicketId(); + curl_thread->QueueMemberCall(curl_thread, &CurlThread::Post, ticket_id, url, post); + return ticket_id; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Curl::Curl() : u_ticket_id(0) +{ + curl_thread = new CurlThread(this); + curl_thread->Start(); +} +Curl::~Curl() +{ + curl_thread->Stop(); + _safe_delete(curl_thread); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/import_fbx/import_fbx.cpp b/include/modules/import_fbx/import_fbx.cpp new file mode 100644 index 0000000..d14bf3f --- /dev/null +++ b/include/modules/import_fbx/import_fbx.cpp @@ -0,0 +1,985 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + +#include "import_fbx/import_fbx.h" +#include "scene3d/scene.h" +#include "scene3d/mobject.h" +#include "scene3d/mlight.h" +#include "scene3d/mcamera.h" +#include "core/graphic_resource_factory.h" +#include "core/geometry.h" +#include "core/renderer.h" +#include "metafile/nml_object.h" +#include "picture/pict_io.h" +#include "filesystem/filesystem.h" +#include "platform.h" + +using namespace GS; +using namespace GS::Core; +using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +static FbxAMatrix ConvertGlobalMatrix(const FbxAMatrix &m) { + FbxAMatrix k_m; + k_m.SetS(FbxVector4(-1, 1, 1)); + return m * k_m; +} + +static Matrix4 FBXMatrixToMatrix4(const FbxAMatrix &fbx_m) { + Matrix4 matrix; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + matrix.m[i][j] = (float) fbx_m[j][i]; + + return matrix; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +FbxScene *FBXImporter::LoadNativeScene(const char *fbx_path) { + // Create an IOSettings object + FbxIOSettings *ios = FbxIOSettings::Create(sdk_manager, IOSROOT); + + // set some IOSettings options + ios->SetBoolProp(IMP_FBX_MATERIAL, true); + ios->SetBoolProp(IMP_FBX_TEXTURE, true); + ios->SetBoolProp(IMP_FBX_LINK, false); + ios->SetBoolProp(IMP_FBX_SHAPE, false); + ios->SetBoolProp(IMP_FBX_GOBO, false); + ios->SetBoolProp(IMP_FBX_ANIMATION, true); + ios->SetBoolProp(IMP_FBX_GLOBAL_SETTINGS, true); + + // Create an empty scene + FbxScene *fbx_scene = FbxScene::Create(sdk_manager, ""); + + // Create an importer. + FBXImporter *fbx_importer = FBXImporter::Create(sdk_manager, ""); + + if (fbx_importer->Initialize(fbx_path, -1, ios) && fbx_importer->Import(fbx_scene)) { + input_path = String(fbx_path).CutFileName(); + + // Convert to our axis system and scale. + FbxAxisSystem axis_system(FbxAxisSystem::eYAxis, FbxAxisSystem::eParityOdd, FbxAxisSystem::eRightHanded); + axis_system.ConvertScene(fbx_scene); + + const FbxSystemUnit::ConversionOptions options = + { + false, /* mConvertRrsNodes */ + true, /* mConvertAllLimits */ + true, /* mConvertClusters */ + true, /* mConvertLightIntensity */ + true, /* mConvertPhotometricLProperties */ + true /* mConvertCameraClipPlanes */ + }; + FbxSystemUnit unit_system(100.f / config->scale); + unit_system.ConvertScene(fbx_scene, options); + } else { + fbx_scene->Destroy(); + fbx_scene = NULL; + } + + fbx_importer->Destroy(); + return fbx_scene; +} + +//------------------------------------------------------------------------------ + +//#define __DEBUG_EULER__ + +//------------------------------------------------------------------------------ +void FBXImporter::ExportMotionChannel(FbxNode *pNode, FbxAnimCurve *pCurve, Motion *motion, + MotionChannel::Type channel_type) { + if (!pCurve) + return; + + MotionChannel *channel = motion->AddChannel(channel_type); + if (!channel) + return; + + channel->AllocatePoint(pCurve->KeyGetCount()); + + for (int n = 0; n < pCurve->KeyGetCount(); ++n) { + FbxTime time = pCurve->KeyGetTime(n); + + CurvePoint *point = (CurvePoint *) channel->GetPoints()[n]; + point->t = Time::fromSec(float(time.GetSecondDouble())); + point->v = pCurve->KeyGetValue(n); + + switch (pCurve->KeyGetInterpolation(n)) { + default: + case FbxAnimCurveDef::eInterpolationLinear: point->shape = CurvePoint::Shape_Linear; + break; + case FbxAnimCurveDef::eInterpolationConstant: point->shape = CurvePoint::Shape_Step; + break; + case FbxAnimCurveDef::eInterpolationCubic: point->shape = CurvePoint::Shape_Hermite; + break; + } + } +} + +void FBXImporter::BakeTransformation(FbxNode *pNode, MItem *item, Motion *motion) { + motion->SetUseQuaternion(true); + + // Allocate position/scale. +#ifdef __DEBUG_EULER__ + motion->AddChannels(9); +#else + motion->AddChannels(6); +#endif + + motion->GetChannel(0)->type = MotionChannel::XPos; + motion->GetChannel(1)->type = MotionChannel::YPos; + motion->GetChannel(2)->type = MotionChannel::ZPos; + motion->GetChannel(3)->type = MotionChannel::XScl; + motion->GetChannel(4)->type = MotionChannel::YScl; + motion->GetChannel(5)->type = MotionChannel::ZScl; + +#ifdef __DEBUG_EULER__ + motion->GetChannel(6)->type = MotionChannel::XRot; + motion->GetChannel(7)->type = MotionChannel::YRot; + motion->GetChannel(8)->type = MotionChannel::ZRot; +#endif + + // Bake animation. + FbxTime tStart = fbx_scene->GetEvaluator()->GetContext()->ReferenceStart.Get(), + tEnd = fbx_scene->GetEvaluator()->GetContext()->ReferenceStop.Get(); + + FbxTime tStep; + tStep.SetSecondDouble(1.0 / double(config->frame_per_second)); + + for (FbxTime t = tStart; t < (tEnd + tStep); t += tStep) // Make sure to include the last key. + { + Time ts = Time::fromSec(float(t.GetSecondDouble())); + + Vector4 p, s; + Matrix3 r; + FbxAMatrix m; + + int dummy = -1; + FbxAMatrix node_global_transform = fbx_scene->GetEvaluator()->GetNodeGlobalTransformFast(pNode, dummy, t); + dummy = -1; + + if (pNode->GetParent()) { + FbxAMatrix parent_global_transform = fbx_scene->GetEvaluator()->GetNodeGlobalTransformFast( + pNode->GetParent(), dummy, t); + dummy = -1; + m = ConvertGlobalMatrix(parent_global_transform).Inverse() * ConvertGlobalMatrix(node_global_transform); + } else + m = ConvertGlobalMatrix(node_global_transform); + + FBXMatrixToMatrix4(m).Decompose(&p, &s, &r); + + motion->GetChannel(0)->Append(CurvePoint(ts, p.x)); + motion->GetChannel(1)->Append(CurvePoint(ts, p.y)); + motion->GetChannel(2)->Append(CurvePoint(ts, p.z)); + motion->GetChannel(3)->Append(CurvePoint(ts, s.x)); + motion->GetChannel(4)->Append(CurvePoint(ts, s.y)); + motion->GetChannel(5)->Append(CurvePoint(ts, s.z)); + +#ifdef __DEBUG_EULER__ + Vector4 e = r.AsEuler(); + motion->GetChannel(6)->Insert(CurvePoint(ts, e.x)); + motion->GetChannel(7)->Insert(CurvePoint(ts, e.y)); + motion->GetChannel(8)->Insert(CurvePoint(ts, e.z)); +#else + Quaternion q = Quaternion::FromMatrix3(r); + motion->GetQuaternion().Insert(QuaternionKey(ts, q)); +#endif + } + // motion->Optimize(); +} + +void FBXImporter::ExportMotions(FbxNode *pNode, MItem *item) { + if (config->import_animation == false) + return; + + for (int n = 0; n < fbx_scene->GetSrcObjectCount(); n++) { + FbxAnimStack *anim_stack = FbxCast(fbx_scene->GetSrcObject(n)); + if (!anim_stack) + continue; + fbx_scene->GetEvaluator()->SetContext(anim_stack); + + // Convert to motion. + Motion *motion = new Motion; + if (!motion) + continue; + + String take_name(anim_stack->GetNameOnly()); + + motion->name = take_name; + BakeTransformation(pNode, item, motion); + + // Add to scene motion set. + { + SceneMotion *set = NULL; + ListForeachPtr(SceneMotion *, s, scene->motion.motions) + if (s->name == motion->name) { + set = s; + break; + } + + if (set == NULL) // create a new motion set + { + set = new SceneMotion; + + set->name = take_name; + scene->motion.motions.Add(set); + } + + SceneMotion::ItemMotion *item_motion = new SceneMotion::ItemMotion; // new item motion + item_motion->uid = item->GetUid(); + item_motion->motion = motion; + + set->item_motions.Add(item_motion); // add to set + } + + // Add to item motion list. + { + // item->automation_player->AddMotion(motion); + } + } +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool FBXImporter::ExportDeformers(FbxMesh *fbx_mesh, FbxNode *pNode, Geometry &geo, MObject *object) { + FbxSkin *fbx_skin = ((FbxSkin *) fbx_mesh->GetDeformer(0, FbxDeformer::eSkin)); + if (!fbx_skin) + return false; + + // Allocate geometry skin. + geo.skin.Allocate(geo.vtx.GetCount()); + + for (uint n = 0; n < geo.vtx.GetCount(); ++n) + for (int j = 0; j < __PV_BONE_LIMIT__; ++j) { + geo.skin[n].bone_index[j] = 0; + geo.skin[n].w[j] = 0.f; + } + + // For each skin entry select the clusters with the largest weight. + geo.AllocateBone(fbx_skin->GetClusterCount()); + + for (int n = 0; n < (int) geo.bone_name.GetCount(); ++n) { + FbxCluster *cluster = fbx_skin->GetCluster(n); + if (FbxNode *bone = cluster->GetLink()) + geo.bone_name[n] = bone->GetName(); + + // Import bind pose. + FbxAMatrix cluster_matrix, bind_matrix; + cluster->GetTransformMatrix(cluster_matrix); + cluster->GetTransformLinkMatrix(bind_matrix); + + geo.bone_bind_matrix[n] = FBXMatrixToMatrix4( + (ConvertGlobalMatrix(cluster_matrix).Inverse() * ConvertGlobalMatrix(bind_matrix)).Inverse()); + + // Import weights. + int *fbx_index = cluster->GetControlPointIndices(); + double *fbx_weight = cluster->GetControlPointWeights(); + + for (int i = 0; i < cluster->GetControlPointIndicesCount(); ++i) { + GeometrySkin *skin = &geo.skin[fbx_index[i]]; + + // Perform insertion. + for (int c = 0; c < __PV_BONE_LIMIT__; ++c) + if (fbx_weight[i] > skin->w[c]) { + // Shift the lower influences out. + for (int j = __PV_BONE_LIMIT__ - 1; j > c; --j) { + skin->w[j] = skin->w[j - 1]; + skin->bone_index[j] = skin->bone_index[j - 1]; + } + + // Insert new influence. + skin->w[c] = (float) fbx_weight[i]; + skin->bone_index[c] = (ushort) n; + break; + } + } + } + + // Normalize weights. + for (uint n = 0; n < geo.vtx.GetCount(); ++n) { + GeometrySkin *skin = &geo.skin[n]; + + float w_sum = 0; + for (int c = 0; c < __PV_BONE_LIMIT__; ++c) + w_sum += skin->w[c]; + if (w_sum > 0) + for (int c = 0; c < __PV_BONE_LIMIT__; ++c) + skin->w[c] /= w_sum; + } + + // Set geometry and bind bones. + object->geometry = geo.name; + if (object->AllocateSkin(geo.GetBoneCount())) + for (uint n = 0; n < geo.GetBoneCount(); ++n) + if (MItem *item = ExportNode(fbx_skin->GetCluster(n)->GetLink())) + object->BindBone(n, item->GetBaseItem()); + + return true; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String FBXImporter::ExportFileTexture(FbxFileTexture *fbx_texture) { + if (!fbx_texture) + return NULL; + + // Try to locate texture. + String in_path; + + forever { + in_path = fbx_texture->GetFileName(); + if (Platform::Get().io->Exists(in_path)) + break; + + in_path.FileCutPath(); + if (Platform::Get().io->Exists(in_path)) + break; + + in_path = input_path + "/" + in_path; + if (Platform::Get().io->Exists(in_path)) + break; + + return NULL; + } + + // Import texture. + String out_path; + if (GetOutputPath(out_path, config->base_path, in_path.GetFileName(), "texture", in_path.GetFileExtension(), + config->exists_policy_texture)) { + Platform::Get().io->FileCopy(in_path, out_path); + out_path = Platform::Get().io->StripRootPath(out_path); + } + return out_path; +} + +String FBXImporter::ExportLayeredTexture(FbxLayeredTexture *object) { + String out_path; + + for (int n = 0; n < object->GetSrcObjectCount(); ++n) { + if (FbxFileTexture *t = object->GetSrcObject(n)) + out_path = ExportFileTexture(t); + // if (FbxLayeredTexture *t = object->GetSrcObject(FBX_TYPE(FbxLayeredTexture), n)) + // texture = ExportLayeredTexture(t); + + if (!out_path.IsEmpty()) + break; + } + return out_path; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String FBXImporter::SaveMaterial(const Material &material, const char *name) { + String out_path; + if (GetOutputPath(out_path, config->base_path, name, "material", "nmm", config->exists_policy_material)) + NML::SaveToFile(material, out_path); + + return Platform::Get().io->StripRootPath(out_path); +} + +String FBXImporter::ExportMaterial(FbxSurfaceMaterial *fbx_material, FbxMesh *fbx_mesh, bool use_skin) { + static const char *texture_type_to_export[] = + { + FbxSurfaceMaterial::sDiffuse, + FbxSurfaceMaterial::sEmissive, + FbxSurfaceMaterial::sAmbient, + FbxSurfaceMaterial::sSpecular, + FbxSurfaceMaterial::sNormalMap, + FbxSurfaceMaterial::sShininess, + FbxSurfaceMaterial::sBump, + FbxSurfaceMaterial::sTransparentColor, + FbxSurfaceMaterial::sReflection, + 0 + }; + + static MaterialChannel export_texture_to_channel[] = + { + Channel_Diffuse, + Channel_SelfIllum, + Channel_Light, + Channel_Specular, + Channel_Normal, + Channel_Glossiness, + Channel_Normal, + Channel_Opacity, + Channel_Reflection + }; + + if (!fbx_material) + return NULL; + + Material material; + material.renderword |= Material::Render_Smooth; + if (use_skin) + material.renderword |= Material::Render_Skinned; + + // Phong. + if (fbx_material->GetClassId().Is(FbxSurfacePhong::ClassId)) { + FbxSurfacePhong *fbx_phong = (FbxSurfacePhong *) fbx_material; + material.specular.Set(float(fbx_phong->Specular.Get()[0] * fbx_phong->SpecularFactor.Get()), + float(fbx_phong->Specular.Get()[1] * fbx_phong->SpecularFactor.Get()), + float(fbx_phong->Specular.Get()[2] * fbx_phong->SpecularFactor.Get())); + material.glossiness = Types::Clamp((float) fbx_phong->Shininess.Get() / 64.f, 0.01f, 0.5f); + // Completely random conversion factor. + } + + // Lambert. + if (fbx_material->GetClassId().Is(FbxSurfacePhong::ClassId) || fbx_material->GetClassId().Is( + FbxSurfaceLambert::ClassId)) { + FbxSurfaceLambert *fbx_lambert = (FbxSurfaceLambert *) fbx_material; + material.ambient.Set(float(fbx_lambert->Ambient.Get()[0] * fbx_lambert->AmbientFactor.Get()), + float(fbx_lambert->Ambient.Get()[1] * fbx_lambert->AmbientFactor.Get()), + float(fbx_lambert->Ambient.Get()[2] * fbx_lambert->AmbientFactor.Get())); + material.diffuse.Set(float(fbx_lambert->Diffuse.Get()[0] * fbx_lambert->DiffuseFactor.Get()), + float(fbx_lambert->Diffuse.Get()[1] * fbx_lambert->DiffuseFactor.Get()), + float(fbx_lambert->Diffuse.Get()[2] * fbx_lambert->DiffuseFactor.Get())); + material.self.Set(float(fbx_lambert->Emissive.Get()[0] * fbx_lambert->EmissiveFactor.Get()), + float(fbx_lambert->Emissive.Get()[1] * fbx_lambert->EmissiveFactor.Get()), + float(fbx_lambert->Emissive.Get()[2] * fbx_lambert->EmissiveFactor.Get())); + // material.opacity = 1.f - fbx_lambert->GetTransparencyFactor().Get(); // Broken exporters make the importer appear broken. + } + + // Export material textures. + for (int t = 0; texture_type_to_export[t]; ++t) { + // Export texture from FBX. + FbxProperty fbx_texture_prop = fbx_material->FindProperty(texture_type_to_export[t]); + + FbxTexture *fbx_texture = fbx_texture_prop.GetSrcObject(0); + if (!fbx_texture) + continue; + + String texture; + if (FbxFileTexture *t = fbx_texture_prop.GetSrcObject(0)) + texture = ExportFileTexture(t); + if (FbxLayeredTexture *t = fbx_texture_prop.GetSrcObject(0)) + texture = ExportLayeredTexture(t); + + // Identify UV channel. + int uv_index = -1, uv_count = 0; + for (int l = 0; l < fbx_mesh->GetLayerCount(); ++l) { + FbxLayer *fbx_layer = fbx_mesh->GetLayer(l); + + for (int n = 0; n < fbx_layer->GetUVSetCount(); ++n) { + FbxArray uv_types = fbx_layer->GetUVSetChannels(); + for (int t = 0; t < uv_types.GetCount(); ++t) + if (fbx_texture->UVSet.Get() == fbx_layer->GetUVs(uv_types[t])->GetName()) { + uv_index = uv_count; + goto done_uv; + } + + ++uv_count; + if (uv_count == __UV_PER_GEOMETRY__) + goto done_uv; + } + } + + done_uv:; + + // Create stage. + if (Material::TextureStage *stage = material.NewStage(export_texture_to_channel[t], texture, Material::UV_UV, + (uchar) (uv_index == -1 ? 0 : uv_index))) { + // Normal map defaults to tangent. + if (stage->channel == Channel_Normal) + material.renderword |= Material::Render_NormalTangent; + } + } + return SaveMaterial(material, fbx_material->GetName()); +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String FBXImporter::ExportGeometry(FbxMesh *fbx_mesh, FbxNode *pNode, MObject *object) { + // Build local transformation. + FbxAMatrix mesh_matrix, mesh_rmatrix; + + if (pNode) { + mesh_matrix.SetTRS(pNode->GetGeometricTranslation(FbxNode::eSourcePivot), + pNode->GetGeometricRotation(FbxNode::eSourcePivot), + pNode->GetGeometricScaling(FbxNode::eSourcePivot)); + mesh_rmatrix.SetR(pNode->GetGeometricRotation(FbxNode::eSourcePivot)); + + FbxAMatrix export_global_mtx; + export_global_mtx.SetS(FbxVector4(-1, 1, 1)); + + mesh_matrix = export_global_mtx * mesh_matrix; + mesh_rmatrix = export_global_mtx * mesh_rmatrix; + } + + // Export. + Geometry geo; + geo.name = pNode->GetName(); + + // Transfer topology. + geo.AllocateVertex(fbx_mesh->GetControlPointsCount()); + for (uint n = 0; n < geo.vtx.GetCount(); ++n) { + FbxVector4 v = mesh_matrix.MultT(fbx_mesh->GetControlPoints()[n]); + geo.vtx[n].Set((float) v[0], (float) v[1], (float) v[2]); + } + + geo.AllocatePolygon(fbx_mesh->GetPolygonCount()); + for (uint n = 0; n < geo.pol.GetCount(); ++n) { + geo.pol[n].vtx_count = (ushort) fbx_mesh->GetPolygonSize(n); + geo.pol[n].material = 0; + } + + Array pol_index; + geo.ComputePolygonIndex(pol_index); + geo.AllocatePolygonBinding(); + +#define __PolIndex (pol_index[p] + v) +#define __PolRemapIndex (pol_index[p] + (geo.pol[p].vtx_count - 1 - v)) + // #define __PolRemapIndex (geometry->pol_index[p] + v) + + for (uint p = 0; p < geo.pol.GetCount(); ++p) + for (int v = 0; v < geo.pol[p].vtx_count; ++v) + geo.pol[p].binding[v] = fbx_mesh->GetPolygonVertices()[__PolRemapIndex]; + + // Export materials. + FbxLayer *fbx_layer = fbx_mesh->GetLayer(0); + + // Normal. + if (const FbxLayerElementNormal *normal_layer = fbx_layer->GetNormals()) + if (geo.vtx_normal.Allocate(geo.binding.GetCount())) + for (uint p = 0; p < geo.pol.GetCount(); ++p) + for (int v = 0; v < geo.pol[p].vtx_count; ++v) { + FbxVector4 N; + fbx_mesh->GetPolygonVertexNormal(p, v, N); + N = mesh_rmatrix.MultT(N); + geo.vtx_normal[__PolRemapIndex].Set((float) N[0], (float) N[1], (float) N[2]); + } + + // Tangent and binormal. + const FbxLayerElementTangent *tangent_layer = fbx_layer->GetTangents(); + const FbxLayerElementBinormal *binormal_layer = fbx_layer->GetBinormals(); + + if (tangent_layer && binormal_layer) { + if ((tangent_layer->GetMappingMode() == FbxLayerElement::eByPolygonVertex) && ( + binormal_layer->GetMappingMode() == FbxLayerElement::eByPolygonVertex)) { + if (geo.vtx_tangent.Allocate(geo.binding.GetCount())) + for (uint p = 0; p < geo.pol.GetCount(); ++p) + for (int v = 0; v < geo.pol[p].vtx_count; ++v) { + FbxVector4 T = tangent_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect + ? tangent_layer->GetDirectArray()[tangent_layer->GetIndexArray()[ + __PolRemapIndex]] + : tangent_layer->GetDirectArray()[__PolRemapIndex]; + T = mesh_rmatrix.MultT(T); + geo.vtx_tangent[__PolIndex].T.Set((float) T[0], (float) -T[1], (float) T[2]); + // This is UV dependent and textures are reversed on V from the FBX convention. + + FbxVector4 B = binormal_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect + ? binormal_layer->GetDirectArray()[binormal_layer->GetIndexArray()[ + __PolRemapIndex]] + : binormal_layer->GetDirectArray()[__PolRemapIndex]; + B = mesh_rmatrix.MultT(T); + geo.vtx_tangent[__PolIndex].B.Set((float) B[0], (float) -B[1], (float) B[2]); + // This is UV dependent and textures are reversed on V from the FBX convention. + } + } else + __LOG_W__ << "Unsupported tangent layer mapping mode (" << tangent_layer->GetMappingMode() << ").\n"; + } + + // Vertex color. + if (const FbxLayerElementVertexColor *color_layer = fbx_layer->GetVertexColors()) { + if (geo.rgb.Allocate(geo.binding.GetCount())) + switch (color_layer->GetMappingMode()) { + case FbxLayerElement::eByControlPoint: + for (uint p = 0; p < geo.pol.GetCount(); ++p) + for (int v = 0; v < geo.pol[p].vtx_count; ++v) { + uint v_idx = geo.pol[p].binding[v]; + const FbxColor &cl = color_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect + ? color_layer->GetDirectArray()[color_layer->GetIndexArray()[ + v_idx]] + : color_layer->GetDirectArray()[v_idx]; + geo.rgb[__PolIndex].Set((float) cl.mRed, (float) cl.mGreen, (float) cl.mBlue); + } + break; + + case FbxLayerElement::eByPolygonVertex: + for (uint p = 0; p < geo.pol.GetCount(); ++p) + for (int v = 0; v < geo.pol[p].vtx_count; ++v) { + const FbxColor &cl = color_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect + ? color_layer->GetDirectArray()[color_layer->GetIndexArray()[ + __PolRemapIndex]] + : color_layer->GetDirectArray()[__PolRemapIndex]; + geo.rgb[__PolIndex].Set((float) cl.mRed, (float) cl.mGreen, (float) cl.mBlue); + } + break; + + default: + __LOG_W__ << "Unsupported vertex color layer mapping mode (" << color_layer->GetMappingMode() << + ").\n"; + } + else + __LOG_E__ << "Failed to allocate vertex color set.\n"; + } + + // UV Channel (searched for on all available layers). + uint uv_count = 0; + for (int l = 0; l < fbx_mesh->GetLayerCount(); ++l) { + FbxLayer *fbx_layer = fbx_mesh->GetLayer(l); + + for (int n = 0; n < fbx_layer->GetUVSetCount(); ++n) { + const FbxLayerElementUV *uv_layer = fbx_layer->GetUVSets()[n]; + + if (geo.uv[uv_count].Allocate(geo.binding.GetCount())) + switch (uv_layer->GetMappingMode()) { + case FbxLayerElement::eByControlPoint: + for (uint p = 0; p < geo.pol.GetCount(); ++p) + for (int v = 0; v < geo.pol[p].vtx_count; ++v) { + uint v_idx = geo.pol[p].binding[v]; + const FbxVector2 &UV = uv_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect + ? uv_layer->GetDirectArray()[uv_layer->GetIndexArray()[ + v_idx]] + : uv_layer->GetDirectArray()[v_idx]; + geo.uv[uv_count][__PolIndex].Set((float) UV[0], 1.f - (float) UV[1]); + } + break; + + case FbxLayerElement::eByPolygonVertex: + for (uint p = 0; p < geo.pol.GetCount(); ++p) + for (int v = 0; v < geo.pol[p].vtx_count; ++v) { + const FbxVector2 &UV = uv_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect + ? uv_layer->GetDirectArray()[uv_layer->GetIndexArray()[ + __PolRemapIndex]] + : uv_layer->GetDirectArray()[__PolRemapIndex]; + geo.uv[uv_count][__PolIndex].Set((float) UV[0], 1.f - (float) UV[1]); + } + break; + + default: + __LOG_W__ << "Unsupported UV layer mapping mode (" << uv_layer->GetMappingMode() << ").\n"; + } + else + __LOG_E__ << "Failed to allocate UV set.\n"; + + if (++uv_count == __UV_PER_GEOMETRY__) { + __LOG_W__ << "UV map limit per geometry exceeded (" << __UV_PER_GEOMETRY__ << + "), increase nUVMapLimit.\n"; + break; + } + } + + if (uv_count == __UV_PER_GEOMETRY__) + break; + } + + // Export deformers. + bool use_skin = ExportDeformers(fbx_mesh, pNode, geo, object); + + // Materials. + int material_count = fbx_mesh->GetNode()->GetMaterialCount(); + + if (material_count > 0) { + geo.material_table.Allocate(material_count); + for (int n = 0; n < material_count; ++n) + geo.material_table[n].name = ExportMaterial((FbxSurfaceMaterial *) fbx_mesh->GetNode()->GetMaterial(n), + fbx_mesh, use_skin); + } else { + Material material; + if (use_skin) + material.renderword |= Material::Render_Skinned; + + geo.material_table.Allocate(1); + geo.material_table[0].name = SaveMaterial(material, geo.name); + } + + // Export the material mapping to polygon. + const FbxLayerElementMaterial *material_layer = fbx_layer->GetMaterials(); + + if (material_layer) + switch (material_layer->GetMappingMode()) { + case FbxLayerElement::eByPolygon: { + // Map polygon to material. + if (material_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect) + for (uint n = 0; n < geo.pol.GetCount(); ++n) { + int idx = material_layer->GetIndexArray().GetAt(n); + geo.pol[n].material = (ushort) idx; + if (geo.pol[n].material >= geo.material_table.GetCount()) { + __LOG_E__ << "Invalid material index (" << idx << ") for polygon " << n << + " (FBX powered).\n"; + geo.pol[n].material = 0; + } + } + else + for (uint n = 0; n < geo.pol.GetCount(); ++n) + geo.pol[n].material = (ushort) n; + } + break; + + case FbxLayerElement::eAllSame: { + if (material_layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect) + for (uint n = 0; n < geo.pol.GetCount(); ++n) { + int idx = material_layer->GetIndexArray().GetAt(0); + geo.pol[n].material = (ushort) idx; + if (geo.pol[n].material >= geo.material_table.GetCount()) { + __LOG_E__ << "Invalid material index (" << idx << ") for polygon " << n << + " (FBX powered).\n"; + geo.pol[n].material = 0; + } + } + else + for (uint n = 0; n < geo.pol.GetCount(); ++n) + geo.pol[n].material = 0; + } + break; + + default: + __LOG_W__ << "Unsupported material mapping mode (" << material_layer->GetMappingMode() << ").\n"; + break; + } + + // Output to path. + String out_path; + if (GetOutputPath(out_path, config->base_path, geo.name, "geometry", "nmg", config->exists_policy_geometry)) { + geo.name = out_path; + NML::SaveToFile(geo, geo.name); + geo.name = Platform::Get().io->StripRootPath(geo.name); + } + + object->geometry = geo.name; + return geo.name; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MObject *FBXImporter::ExportObject(FbxNodeAttribute *pAttr, FbxNode *pNode) { + FbxMesh *fbx_mesh = (FbxMesh *) pAttr; + MObject *object = new MObject; + object->name = pNode->GetNameOnly(); + scene->AddItem(object, true); + ExportGeometry(fbx_mesh, pNode, object); + return object; +} + +MItem *FBXImporter::ExportCamera(FbxNodeAttribute *pAttr, FbxNode *pNode) { + FbxCamera *fbx_camera = (FbxCamera *) pAttr; + MCamera *camera = new MCamera; + camera->name = pNode->GetNameOnly(); + scene->AddItem(camera, true); + + if (fbx_camera->GetNearPlane() != 10) + camera->SetNearClippingPlane((float) fbx_camera->GetNearPlane()); + if (fbx_camera->GetFarPlane() != 4000) + camera->SetFarClippingPlane((float) fbx_camera->GetFarPlane()); + + camera->aspect_ratio = (float) fbx_camera->GetPixelRatio(); + camera->SetFov(Units::DegreeToRadian((float) fbx_camera->FieldOfView.Get())); + camera->is_orthographic = asbool(fbx_camera->ProjectionType.Get() == FbxCamera::eOrthogonal); + + return camera; +} + +MItem *FBXImporter::ExportLight(FbxNodeAttribute *pAttr, FbxNode *pNode) { + FbxLight *fbx_light = (FbxLight *) pAttr; + MLight *light = new MLight; + light->name = pNode->GetNameOnly(); + scene->AddItem(light, true); + + switch (fbx_light->LightType.Get()) { + case FbxLight::ePoint: light->model = MLight::Model_Point; + break; + case FbxLight::eDirectional: light->model = MLight::Model_Linear; + break; + case FbxLight::eSpot: light->model = MLight::Model_Spot; + break; + } + + light->diffuse_color.Set((float) fbx_light->Color.Get()[0], (float) fbx_light->Color.Get()[1], + (float) fbx_light->Color.Get()[2]); + light->diffuse_intensity = (float) fbx_light->Intensity.Get() / 100.f; + light->specular_color = light->diffuse_color; + + if (fbx_light->EnableFarAttenuation.Get()) { + light->range = (float) fbx_light->FarAttenuationEnd.Get(); + light->volume_range = light->range + Units::Mtr(0.5f); + } + + if (fbx_light->CastShadows.Get()) + light->shadow = Light::Shadow_Map; + light->shadow_color.Set((float) fbx_light->ShadowColor.Get()[0], (float) fbx_light->ShadowColor.Get()[1], + (float) fbx_light->ShadowColor.Get()[2]); + return light; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool FBXImporter::GetNodeItem(FbxNode *pNode, MItem **item) { + ListForeachPtr(ExportedNode *, exported_node, node_list) + if (exported_node->node == pNode) { + if (item) + *item = exported_node->item; + return true; + } + return false; +} + +MItem *FBXImporter::ExportNode(FbxNode *pNode) { + if (config->event_handler) + config->event_handler->LoadProgress(String::Format("Importing node '%s'...", pNode->GetName()), + (float) current_node_index / fbx_scene->GetNodeCount()); + current_node_index++; + + MItem *item = NULL; + if (GetNodeItem(pNode, &item)) + return item; + + // Export this node. + if (pNode != fbx_scene->GetRootNode()) { + if (pNode->GetNodeAttribute()) { + FbxNodeAttribute::EType type = pNode->GetNodeAttribute()->GetAttributeType(); + + switch (type) { + default: + case FbxNodeAttribute::eUnknown: + case FbxNodeAttribute::eNull: + case FbxNodeAttribute::eMarker: + case FbxNodeAttribute::eNurbs: + case FbxNodeAttribute::ePatch: + case FbxNodeAttribute::eCameraStereo: + case FbxNodeAttribute::eCameraSwitcher: + case FbxNodeAttribute::eOpticalReference: + case FbxNodeAttribute::eOpticalMarker: + case FbxNodeAttribute::eNurbsCurve: + case FbxNodeAttribute::eTrimNurbsSurface: + case FbxNodeAttribute::eBoundary: + case FbxNodeAttribute::eNurbsSurface: + case FbxNodeAttribute::eShape: + case FbxNodeAttribute::eLODGroup: + case FbxNodeAttribute::eSubDiv: + case FbxNodeAttribute::eSkeleton: + if (MObject *o = new MObject) { + o->name = pNode->GetNameOnly(); + scene->AddItem(o, true); + item = o; + } + break; + + case FbxNodeAttribute::eMesh: + item = ExportObject(pNode->GetNodeAttribute(), pNode); + break; + case FbxNodeAttribute::eCamera: + item = ExportCamera(pNode->GetNodeAttribute(), pNode); + break; + case FbxNodeAttribute::eLight: + item = ExportLight(pNode->GetNodeAttribute(), pNode); + break; + } + } else { + MObject *o = new MObject; + o->name = pNode->GetNameOnly(); + scene->AddItem(o, true); + item = o; + } + } + + // Register node. + node_list.Add(new ExportedNode(pNode, item)); + + if (item) { + FbxAMatrix m; + if (pNode->GetParent()) + m = ConvertGlobalMatrix(fbx_scene->GetEvaluator()->GetNodeGlobalTransform(pNode->GetParent())).Inverse() * + ConvertGlobalMatrix(fbx_scene->GetEvaluator()->GetNodeGlobalTransform(pNode)); + else m = ConvertGlobalMatrix(fbx_scene->GetEvaluator()->GetNodeGlobalTransform(pNode)); + + item->GetBaseItem()->SetMatrix(FBXMatrixToMatrix4(m)); + ExportMotions(pNode, item); + } + + // Export children. + for (int i = 0; i < pNode->GetChildCount(); i++) { + MItem *child = ExportNode(pNode->GetChild(i)); + if (child && item) + child->GetBaseItem()->SetParent(item->GetBaseItem()); + } + return item; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool FBXImporter::TestImport(const char *uri) { + String ext = String::FileGetExtension(uri).Lower(); + return asbool((ext == "dae") || (ext == "fbx") || (ext == "3ds")); +} + +bool FBXImporter::ImportScene(Scene *_scene, const char *_input, const Config &_config, Group **) { + if (!sdk_manager) + __ERR__(__LOG_E__ << "Importer not initialized.\n", false) + if (_input == NULL) + __ERR__(__LOG_E__ << "No input file specified.\n", false) + if (_scene == NULL) + __ERR__(__LOG_E__ << "No scene to load into.\n", false) + + // Load native FBX. + scene = _scene; + config = &_config; + if ((fbx_scene = LoadNativeScene(_input)) == NULL) + return false; + + if (config->event_handler) + config->event_handler->OpenLoad(); + + // Drop lists. + geometry_list.Clear(); + + // Perform conversion. + current_node_index = 0; + ExportNode(fbx_scene->GetRootNode()); + + // Convert globals. + FbxGlobalLightSettings &gsettings = fbx_scene->GlobalLightSettings(); + + scene->ambient_color.Set((float) gsettings.GetAmbientColor().mRed, (float) gsettings.GetAmbientColor().mGreen, + (float) gsettings.GetAmbientColor().mBlue); + scene->ambient_intensity = 1.f; + + scene->fog_color.Set((float) gsettings.GetFogColor().mRed, (float) gsettings.GetFogColor().mGreen, + (float) gsettings.GetFogColor().mBlue); + if (gsettings.GetFogEnable()) { + scene->fog_near = (float) gsettings.GetFogStart(); + scene->fog_far = (float) gsettings.GetFogEnd(); + } + + // Save. + if (!config->base_path.IsEmpty()) { + scene->name = String::Format("%s/%s.nms", config->base_path.toUtf8(), + String(_input).CutFilePath().CutFileExtension().toUtf8()); + NML::SaveToFile(*scene, scene->name); + scene->name = Platform::Get().io->StripRootPath(scene->name); + } + + fbx_scene->Destroy(); + ListDeleteAllPtr(ExportedNode *, node_list) + + if (config->event_handler) + config->event_handler->EndLoad(); + return true; +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +FBXImporter::FBXImporter() { + sdk_manager = FbxManager::Create(); + fbx_scene = NULL; +} + +FBXImporter::~FBXImporter() { + if (sdk_manager) + sdk_manager->Destroy(); +} + +//------------------------------------------------------------------------------ diff --git a/include/modules/import_obj/import_obj.cpp b/include/modules/import_obj/import_obj.cpp new file mode 100644 index 0000000..c9d01f8 --- /dev/null +++ b/include/modules/import_obj/import_obj.cpp @@ -0,0 +1,683 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "import_obj/import_obj.h" + #include "scene3d/scene.h" + #include "scene3d/mobject.h" + #include "core/graphic_resource_factory.h" + #include "core/geometry.h" + #include "metafile/nml_object.h" + #include "ascii/parser.h" + #include "filesystem/filesystem.h" + #include "filesystem/io_handle.h" + #include "platform.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::S3D; + using namespace GS::AsciiParser; + + +//------------------------------------------------------------------------------ +struct ObjPoly +{ + List vtx, uv, nrm; + uint mat; + + ObjPoly() : mat(0) {} +}; +struct ObjGroup +{ + String name; + List pol_list; + + void Free() + { ListDeleteAllPtr(ObjPoly *, pol_list) } + ~ObjGroup() + { Free(); } +}; +struct ObjMtl +{ + String name; + String path; +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static void ExportMaterialStage(NML::Tag *mtag, const String &texture, const char *channel, int index) +{ + if (texture.IsEmpty()) + return; + + if (NML::Tag *ttag = mtag->AddChild("TextureStage")) + { + ttag->AddChild("Active"); + ttag->AddChild("Texture", texture); + ttag->AddChild("Channel", channel); + ttag->AddChild("Index", index); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool OBJImporter::LoadMaterialLibrary(List &mtl_list, const char *uri) +{ + Array obj; + if (!Platform::Get().io->FileLoad(uri, obj)) + __ERR__(__LOG_E__ << "OBJ material library file '" << uri << "' not found.\n", false) + + // Now parse. + const char *pobj = &obj[0], *eobj = pobj + obj.GetSize(); + + ObjMtl *current_mtl = NULL; + String map_Ka, map_Kd, map_Ks, map_Ke; + + forever + { + String word(pobj, SkipEntry(pobj, eobj)); + + // Export material to file. + if ((word == "newmtl") || (pobj >= eobj)) + if (current_mtl) + { + current_mtl->path = String::Format("%s/%s.nmm", config->base_path.c_str(), current_mtl->name.c_str()); + + // Only export material if it does not exist. + if (!Platform::Get().io->Exists(current_mtl->path)) + { + String name = Platform::Get().io->StripRootPath(current_mtl->path); + + NML::File file; + if (NML::Tag *mtag = file.AddRoot("Material")) + { + mtag->AddChild("Id", name); + + ExportMaterialStage(mtag, map_Kd, "Diffuse", 0); + ExportMaterialStage(mtag, map_Ka, "Opacity", 1); + ExportMaterialStage(mtag, map_Ks, "Specular", 2); + ExportMaterialStage(mtag, map_Ke, "Emissive", 3); + + if (NML::Tag *rtag = mtag->AddChild("RenderMask")) + rtag->AddChild("NormalMapTangent"); + } + + NML::Parser::Save(current_mtl->path, file); + } + } + + if (pobj >= eobj) + break; + + // Create new material. + if (word == "newmtl") + { + // Create new material. + mtl_list.Add(current_mtl = new ObjMtl); + + pobj = NextEntry(pobj + 1, eobj); + const char *eon = SkipEntry(pobj, eobj); + + current_mtl->name.Set(pobj, eon); + pobj = NextEntry(eon, eobj, true); + } + else if (current_mtl) + { + //------------------------------------------------------------------ + #define __ReadObjMaterialMap(_map) \ + { \ + pobj = NextEntry(pobj + 1, eobj); \ + const char *eon = RunToEOL(pobj, eobj); \ + _map.Set(pobj, eon); \ + pobj = NextEntry(eon, eobj, true); \ + } + //------------------------------------------------------------------ + + if (word == "map_Ka") + __ReadObjMaterialMap(map_Ka) + else if (word == "map_Ks") + __ReadObjMaterialMap(map_Ks) + else if (word == "map_Kd") + __ReadObjMaterialMap(map_Kd) + else if (word == "map_Ke") + __ReadObjMaterialMap(map_Ke) + else + pobj = NextEntry(RunToEOL(pobj, eobj), eobj); + } + else + pobj = NextEntry(RunToEOL(pobj, eobj), eobj); + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool OBJImporter::TestImport(const char *uri) +{ + String ext = String::FileGetExtension(uri).Lower(); + return ext == "obj"; +} +bool OBJImporter::ImportScene(Scene *scene, const char *uri, const Config &_config, Group **) +{ + Array obj; + if (!Platform::Get().io->FileLoad(uri, obj)) + __ERR__(__LOG_E__ << "OBJ file '" << uri << "' not found.\n", false) + + // Now parse. + config = &_config; + if (config->event_handler) + config->event_handler->OpenLoad(); + + const char *pobj = &obj[0], *eobj = pobj + obj.GetSize(); + + //-------------------------------------------------------------------------- + { + bool has_uv = false, has_vnm = false; + AutoList vtx_list, vnm_list; + AutoList uv_list; + + AutoList group_list; + AutoList mat_list; + + ObjGroup *current_group = new ObjGroup; + current_group->name = "default"; + group_list.Add(current_group); + + int current_mat = 0; + + while (pobj < eobj) + { + String word(pobj, SkipEntry(pobj, eobj)); + + if (config->event_handler) + config->event_handler->LoadProgress(String::Format("Parsing tag '%s'...", word.c_str()), (float)(pobj - &obj[0]) / obj.GetSize()); + + // Declare material library. + if (word == "mtllib") + { + pobj = NextEntry(pobj + 1, eobj); + const char *eon = RunToEOL(pobj, eobj); + + String lib_path = String(pobj, eon); + if (!lib_path.IsAbsolutePath()) + lib_path = String(uri).GetFilePath() + "/" + lib_path; + + LoadMaterialLibrary(mat_list, lib_path); + pobj = NextEntry(eon, eobj, true); + } + + // Use material. + else if (word == "usemtl") + { + pobj = NextEntry(pobj + 1, eobj); + const char *eon = SkipEntry(pobj, eobj); + String name(pobj, eon); + + // Locate in library. + current_mat = 0; + ListForeachPtr(ObjMtl *, mat, mat_list) + { + if (mat->name == name) + break; + current_mat++; + } + + pobj = NextEntry(eon, eobj, true); + } + + // Append vertex. + else if (word == "v") + { + // Parse vertex. + pobj = NextEntry(pobj, eobj); + + float x = 0, y = 0, z = 0; + + x = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + y = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + z = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + + vtx_list.Add(new Vector4(x * config->scale, y * config->scale, -z * config->scale)); + } + + // Append vertex normal. + else if (word == "vn") + { + pobj = NextEntry(pobj, eobj); + + float x = 0, y = 0, z = 0; + + x = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + y = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + z = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + +// vnm_list.Add(new nVector(-y, -z, -x)); + vnm_list.Add(new Vector4(x, y, -z)); + } + + // Append UV. + else if (word == "vt") + { + pobj = NextEntry(pobj, eobj); + + float u = 0, v = 0; + + u = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + v = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true); + + uv_list.Add(new Vector2(u, 1.f - v)); + } + + // Declare group. + else if (word == "g") + { + group_list.Add(current_group = new ObjGroup); + + // Check for named group. + const char *eol = RunToEOL(pobj, eobj); + pobj = NextEntry(pobj + 1, eobj); + + if (pobj <= eol) + { + const char *eon = SkipEntry(pobj, eobj); + current_group->name.Set(pobj, eon); + pobj = NextEntry(eon, eobj, true); + } + else // no name + pobj = NextEntry(eol, eobj, true); + } + + // Build group polygons. + else if (word == "f") + { + pobj = NextEntry(pobj, eobj); + + ObjPoly *pol = new ObjPoly; + pol->mat = current_mat; + + const char *eol = RunToEOL(pobj, eobj); + while (pobj < eol) + { + pol->vtx.Add(String::atoi(pobj)); // Index. + pobj = NextEntry(pobj, eobj, true); + + if (pobj[0] == '/') + { + pobj++; + if (pobj[0] != '/') + { + has_uv = true; + pol->uv.Add(String::atoi(pobj)); // UV index. + pobj = NextEntry(pobj, eobj, true); + } + } + + if (pobj[0] == '/') + { + pobj++; + has_vnm = true; + pol->nrm.Add(String::atoi(pobj)); // Normal index. + pobj = NextEntry(pobj, eobj, true); + } + } + + if (pol->vtx.GetCount() < 3) + delete pol; + else + current_group->pol_list.Add(pol); + } + else + pobj = NextEntry(RunToEOL(pobj, eobj), eobj); + } + + obj.Free(); + + //-------------------------------------------------------------------------- + + // Get flat UV array. + Array flat_uv; + if (has_uv && flat_uv.Allocate(uv_list.GetCount())) + { + Vector2 *pflat_uv = flat_uv; + ListForeachPtr(Vector2 *, uv, uv_list) + *pflat_uv++ = *uv; + } + + // Get flat vertex normal array. + Array flat_vnm; + if (has_vnm && flat_vnm.Allocate(vnm_list.GetCount())) + { + Vector4 *pflat_vnm = flat_vnm; + ListForeachPtr(Vector4 *, vnm, vnm_list) + *pflat_vnm++ = *vnm; + } + + //-------------------------------------------------------------------------- + + Array vtx_map(vtx_list.GetCount()), + mat_map(mat_list.GetCount()); + + //-------------------------------------------------------------------------- + + // Build scene. + int n_pg = 0; + ListForeachPtr(ObjGroup *, group, group_list) + { + ++n_pg; + if (!vtx_list.GetCount() || !group->pol_list.GetCount()) + continue; + + if (config->event_handler) + config->event_handler->LoadProgress(String::Format("Importing group '%s'...", group->name.toUtf8()), (float)(n_pg - 1) / group_list.GetCount()); + + // Create geometry. + Geometry *geo = new Geometry; + + // Remap vertices. + for (uint n = 0; n < vtx_map.GetCount(); ++n) + vtx_map[n] = -1; + + // Total vertex count. + uint vtx_count = 0; + ListForeachPtr(ObjPoly *, p, group->pol_list) + ListForeachPtr(int, i, p->vtx) + if (vtx_map[i - 1] == -1) + vtx_map[i - 1] = vtx_count++; + + // Transfer vertices. + if (geo->vtx.Allocate(vtx_count)) + { + for (uint i = 0; i < vtx_list.GetCount(); ++i) + if (vtx_map[i] != -1) + geo->vtx[vtx_map[i]] = *vtx_list[i]; + } + else + __LOG_E__ << "Failed to allocate " << geo->vtx.GetCount() << " vertices.\n"; + + // Transfer topology and attributes. + if (geo->pol.Allocate(group->pol_list.GetCount())) + { + // Compute bind index count. + uint binding_count = 0; + ListForeachPtr(ObjPoly *, p, group->pol_list) + binding_count += p->vtx.GetCount(); + + if (geo->binding.Allocate(binding_count)) + { + uint *pbind = &geo->binding[0]; + + // Allocate attributes. + Vector2 *puv = NULL; + if (has_uv) + { + geo->uv[0].Allocate(binding_count); + puv = &geo->uv[0][0]; + } + + Vector4 *pvnm = NULL; + if (has_vnm) + { + geo->vtx_normal.Allocate(binding_count); + pvnm = &geo->vtx_normal[0]; + } + + // Transfer data. + uint cpol = 0; + ListForeachPtr(ObjPoly *, p, group->pol_list) + { + Polygon *pol = &geo->pol[cpol++]; + + pol->vtx_count = (ushort)p->vtx.GetCount(); + pol->binding = pbind; + pol->material = 0; + + for (int i = p->vtx.GetCount(); i > 0; --i) + { + int idx = p->vtx[i - 1] - 1; + if (idx > (int)vtx_map.GetCount()) + idx = 0; + *pbind++ = vtx_map[idx]; + } + + if (puv) + for (int i = p->uv.GetCount(); i > 0; --i) + *puv++ = flat_uv[p->uv[i - 1] - 1]; + + if (pvnm) + for (int i = p->nrm.GetCount(); i > 0; --i) + *pvnm++ = flat_vnm[p->nrm[i - 1] - 1]; + } + } + else + __LOG_E__ << "Failed to allocate " << geo->binding.GetCount() << " polygon binding entries.\n"; + + // Remap and assign materials. + for (uint i = 0; i < mat_list.GetCount(); ++i) + mat_map[i] = -1; + + int mat_count = 0; + ListForeachPtr(ObjPoly *, p, group->pol_list) + if (p->mat < mat_map.GetCount()) + if (mat_map[p->mat] == -1) + mat_map[p->mat] = mat_count++; + + uint cpol = 0; + ListForeachPtr(ObjPoly *, p, group->pol_list) + geo->pol[cpol++].material = (ushort)(p->mat < mat_map.GetCount() ? mat_map[p->mat] : 0); + + // Load materials. + if (mat_list.GetCount()) + { + geo->material_table.Allocate(mat_count); + for (uint i = 0; i < mat_list.GetCount(); ++i) + if (mat_map[i] != -1) + geo->material_table[mat_map[i]].name = mat_list[i]->path; + } + else + geo->material_table.Allocate(1); + + // Vertex normal. + if (!has_vnm) + geo->ComputeVertexNormal(true); + + // Save geometry. + geo->name = String::Format("%s/%s.nmg", config->base_path.c_str(), group->name.toUtf8()); + NML::SaveToFile(*geo, geo->name); + + geo->name = Platform::Get().io->StripRootPath(geo->name); + + // Add to scene. + MObject *object = new MObject; + object->name = group->name; + scene->AddItem(object, true); + object->geometry = geo->name; + + // Ease up memory. + group->Free(); + } + else + __LOG_E__ << "Failed to allocate " << geo->pol.GetCount() << " polygons.\n"; + } + } + //-------------------------------------------------------------------------- + + // Save scene. + scene->name = String::Format("%s/scene.nms", config->base_path.c_str()); + NML::SaveToFile(*scene, scene->name); + scene->name = Platform::Get().io->StripRootPath(scene->name); + + if (config->event_handler) + config->event_handler->EndLoad(); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Geometry *OBJImporter::ImportGeometry(const char *uri, IResourceFactoryEvent *event_handler) +{ + if (!uri) + __ERR__(__LOG_E__ << "No URI to import.\n", NULL) + + AutoPtr geo(new Geometry); + + // Load file in memory. + Array obj; + if (!Platform::Get().io->FileLoad(uri, obj)) + __ERR__(__LOG_E__ << "File '" << uri << "' not found.\n", NULL) + + // Now parse. + List vtx_list; + List uv_list; + List pol_list; + + bool has_uv = false; + const char *pobj = &obj[0], *eobj = pobj + obj.GetSize(); + + while (pobj < eobj) + { + String word(pobj, SkipEntry(pobj, eobj)); + + if (word == "v") + { + pobj = NextEntry(pobj, eobj); + + float x = 0, y = 0, z = 0; + + x = String::atof(pobj, eobj); + pobj = NextEntry(pobj, eobj, true); + y = String::atof(pobj, eobj); + pobj = NextEntry(pobj, eobj, true); + z = -String::atof(pobj, eobj); + pobj = NextEntry(pobj, eobj, true); + + vtx_list.Add(new Vector4(x, y, z)); + } + else if (word == "vt") + { + pobj = NextEntry(pobj, eobj); + + float u = 0, v = 0; + + u = String::atof(pobj, eobj); + pobj = NextEntry(pobj, eobj, true); + v = String::atof(pobj, eobj); + pobj = NextEntry(pobj, eobj, true); + + uv_list.Add(new Vector2(u, v)); + } + else if (word == "f") + { + pobj = NextEntry(pobj, eobj); + + ObjPoly *pol = new ObjPoly; + pol_list.Add(pol); + + const char *eol = RunToEOL(pobj, eobj); + while (pobj < eol) + { + pol->vtx.Add(String::atoi(pobj)); // Index. + pobj = NextEntry(pobj, eobj, true); + + if (pobj[0] == '/') + { + pobj++; + if (pobj[0] != '/') + { + has_uv = true; + pol->uv.Add(String::atoi(pobj)); // UV index. + pobj = NextEntry(pobj, eobj, true); + } + } + + if (pobj[0] == '/') + { + pobj++; + pol->nrm.Add(String::atoi(pobj)); // Normal index. + pobj = NextEntry(pobj, eobj, true); + } + } + } + else + pobj = NextEntry(RunToEOL(pobj, eobj), eobj); + } + + // Drop OBJ. + obj.Free(); + + // Transfer vertice. + if (geo->vtx.Allocate(vtx_list.GetCount())) + { + uint cvtx = 0; + ListForeachPtr(Vector4 *, v, vtx_list) + geo->vtx[cvtx++] = *v; + } + else + __LOG_E__ << "Failed to allocate " << vtx_list.GetCount() << " vertices.\n"; + + ListDeleteAllPtr(Vector4 *, vtx_list) + + // Transfer polygon. + if (geo->pol.Allocate(pol_list.GetCount())) + { + uint binding_count = 0; + ListForeachPtr(ObjPoly *, p, pol_list) + binding_count += p->vtx.GetCount(); + + geo->binding.Allocate(binding_count); + + Array flat_uv; + + if (has_uv) + if (flat_uv.Allocate(binding_count)) + { + geo->uv[0].Allocate(binding_count); + + Vector2 *pflat_uv = &flat_uv[0]; + ListForeachPtr(Vector2 *, uv, uv_list) + *pflat_uv++ = *uv; + + ListDeleteAllPtr(Vector2 *, uv_list) + } + + Vector2 *puv = &geo->uv[0][0]; + + if (geo->binding) + { + uint *pbind = &geo->binding[0]; + + uint cpol = 0; + ListForeachPtr(ObjPoly *, p, pol_list) + { + Polygon *pol = &geo->pol[cpol]; + + pol->vtx_count = (ushort)p->vtx.GetCount(); + pol->binding = pbind; + pol->material = 0; + + for (int v = p->vtx.GetCount(); v > 0; --v) + *pbind++ = p->vtx.ObjectAt(v - 1) - 1; + + ListForeachPtr(int, i, p->uv) + *puv++ = flat_uv[i - 1]; + } + } + else + __LOG_E__ << "Failed to allocate " << geo->binding.GetCount() << " polygon binding entries.\n"; + } + else + __LOG_E__ << "Failed to allocate " << geo->pol.GetCount() << " polygons.\n"; + + ListDeleteAllPtr(ObjPoly *, pol_list) + + // Load materials. + geo->material_table.Allocate(1); + geo->material_table[0].name = "Default"; + + // Setup defaults. + geo->ComputeVertexNormal(); + + return geo.Detach(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/io_archive/io_archive.cpp b/include/modules/io_archive/io_archive.cpp new file mode 100644 index 0000000..7926d70 --- /dev/null +++ b/include/modules/io_archive/io_archive.cpp @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "io_archive/io_archive.h" + #include "log/log.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +uint Archive::GetCaps() const +{ return CanSeek | CanRead | IsCaseSensitive; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *Archive::Open(const char *uri, Mode mode) +{ + if (mode == ModeRead) + if (ArchiveEntry *e = archive.Exists(uri)) + { + AutoPtr h(new ArchiveHandle(this)); + if (!h->data.Allocate(e->length) || !archive.FileRead(uri, (void *)h->data.c_ptr())) + return NULL; + return h.Detach(); + } + return NULL; +} +void Archive::Close(Handle *) {} +bool Archive::Delete(const char *) { return false; } + +size_t Archive::Tell(Handle *h) +{ + if (ArchiveHandle *_h = (ArchiveHandle *)h) + return _h->cursor; + return (size_t)-1; +} +size_t Archive::Seek(Handle *h, ptrdiff_t offset, SeekRef seek_ref) +{ + if (ArchiveHandle *_h = (ArchiveHandle *)h) + { + switch (seek_ref) + { + case SeekStart: + _h->cursor = Types::Clamp (offset, 0, _h->data.GetSize()); + break; + case SeekCurrent: + _h->cursor = Types::Clamp (_h->cursor + offset, 0, _h->data.GetSize()); + break; + case SeekEnd: + _h->cursor = Types::Clamp (_h->data.GetSize() - offset, 0, _h->data.GetSize()); + break; + } + return _h->cursor; + } + return (size_t)-1; +} + +size_t Archive::Read(Handle *h, void *ptr, size_t size) +{ + size_t read_size = 0; + if (ArchiveHandle *_h = (ArchiveHandle *)h) + { + read_size = Types::Min (size, _h->data.GetSize() - _h->cursor); + GS::Memory::Copy(ptr, &_h->data[(int)_h->cursor], read_size); + _h->cursor += read_size; + } + return read_size; +} +size_t Archive::Write(Handle *, const void *, size_t size) +{ return 0; } +//------------------------------------------------------------------------------ + +Archive::Archive(const char *uri, const char *index_uri) +{ + if ((connected = archive.OpenRead(uri, index_uri)) == false) + __LOG_E__ << "Failed to connect filesystem to archive '" << uri << "'.\n"; +} diff --git a/include/modules/io_net/io_net_client.cpp b/include/modules/io_net/io_net_client.cpp new file mode 100644 index 0000000..b950c0a --- /dev/null +++ b/include/modules/io_net/io_net_client.cpp @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "io_net/io_net_client.h" + #include "io_net/io_net_client_worker_thread.h" + #include "ascii/parser.h" + #include "container/nlist.h" + #include "nstring/nstring.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +uint Net::GetCaps() const +{ return IsCaseSensitive | CanRead | CanSeek; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Net::QueueTask(NetWorkerBaseTask &task) +{ + if (!worker.QueueTask(task)) + __ERR__("Net::QueueTask failed.\n", false); + + while (task.processed.Get() == 0) {} + return asbool(task.success.Get()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *Net::Open(const char *path, Mode mode) +{ + NetWorkerOpenTask task(path, mode); + return QueueTask(task) ? new NetHandle(this, task.handle) : NULL; +} +void Net::Close(Handle *h) +{ + NetWorkerCloseTask task(((NetHandle *)h)->remote_id); + QueueTask(task); +} +size_t Net::Tell(Handle *h) +{ + NetWorkerTellTask task(((NetHandle *)h)->remote_id); + return QueueTask(task) ? task.pos : 0; +} +size_t Net::Seek(Handle *h, ptrdiff_t offset, SeekRef ref) +{ + NetWorkerSeekTask task(((NetHandle *)h)->remote_id, offset, ref); + return QueueTask(task) ? task.pos : 0; +} +size_t Net::Read(Handle *h, void *data, size_t size) +{ + NetWorkerReadTask task(((NetHandle *)h)->remote_id, data, size); + return QueueTask(task) ? task.read_size : 0; +} +GS::String Net::Hash(const char *uri) +{ + NetWorkerHashTask task(uri); + return QueueTask(task) ? task.hash : 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Net::IsConnected() const +{ return worker.IsConnected(); } +bool Net::Connect(const char *ip, int port) +{ return worker.Start(ip, port); } +void Net::Disconnect() +{ worker.Stop(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NetHandle::~NetHandle() +{ GetIOSystem()->Close(this); } +//------------------------------------------------------------------------------ diff --git a/include/modules/io_net/io_net_client_worker_thread.cpp b/include/modules/io_net/io_net_client_worker_thread.cpp new file mode 100644 index 0000000..03f01b0 --- /dev/null +++ b/include/modules/io_net/io_net_client_worker_thread.cpp @@ -0,0 +1,297 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "io_net/io_net_client.h" + #include "ascii/parser.h" + #include "container/nlist.h" + #include "nstring/nstring.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS::IO; + using namespace GS::Threading; + + +//------------------------------------------------------------------------------ +bool NetWorkerThread::ProcessOpenTask(NetWorkerOpenTask &task) +{ + if (!server_peer) + __ERR__(__LOG_F__ << "No peer.\n", false) + if (!SendString(server_peer, String("Open,") << task.path)) + __ERR__(__LOG_F__ << "SendString failed, server = '" << server_peer << "', task.path = '" << task.path << "'\n", false) + + if (!WaitServerResponse()) + __ERR__(__LOG_F__ << "WaitServerResponse = false\n", false) + + String answer(response.c_ptr(), response.GetSize()); + ClearServerResponse(); + + StringList args; + if (answer.Split(",", args) != 2) + __ERR__(__LOG_F__ << "NetWorkerThread Wrong arg count: " << answer << "\n", false) + + if (args[0] != "Success") + __ERR__(__LOG_F__ << "args[0] != Success ('" << args[0] << "')\n", false) + + task.handle = args[1].Integer(); + return true; +} +bool NetWorkerThread::ProcessCloseTask(NetWorkerCloseTask &task) +{ + if (!server_peer || !SendString(server_peer, String("Close,") << task.handle)) + return false; + + if (WaitServerResponse()) // FIXME does not even check for success... + ClearServerResponse(); + return true; +} +bool NetWorkerThread::ProcessSeekTask(NetWorkerSeekTask &task) +{ + String seek_ref; + switch (task.seek_ref) + { + case Base::SeekStart: seek_ref = "Start"; break; + case Base::SeekCurrent: seek_ref = "Current"; break; + case Base::SeekEnd: seek_ref = "End"; break; + } + if (!server_peer || !SendString(server_peer, String::Format("Seek,%d,%s,%d", task.offset, seek_ref.c_str(), task.handle))) + return false; + + if (!WaitServerResponse()) + return false; + String answer(response.c_ptr(), response.GetSize()); + ClearServerResponse(); + + StringList args; + if (answer.Split(",", args) != 2) + return false; + if (args[0] != "Success") + return false; + + task.pos = size_t(args[1].Integer()); + return true; +} +bool NetWorkerThread::ProcessTellTask(NetWorkerTellTask &task) +{ + if (!server_peer || !SendString(server_peer, String("Tell,") << task.handle)) + return false; + + if (!WaitServerResponse()) + return false; + String answer(response.c_ptr(), response.GetSize()); + ClearServerResponse(); + + StringList args; + if (answer.Split(",", args) != 2) + return false; + if (args[0] != "Success") + return false; + + task.pos = size_t(args[1].Integer()); + return true; +} +bool NetWorkerThread::ProcessReadTask(NetWorkerReadTask &task) +{ + if (!server_peer || !SendString(server_peer, String::Format("Read,%d,%d", task.size, task.handle))) + return false; + + if (!WaitServerResponse()) + return false; + + // Check success. + if (Memory::Compare("Success,", response.c_ptr(), 8)) + return false; // failed + + // Parse size. + const char *p_size = response.c_ptr() + 8; + const char *e_size = AsciiParser::Find(response.c_ptr() + 8, response.End(), ','); + if (e_size == NULL) + return false; + task.read_size = size_t(String(p_size, e_size).Integer()); + + // Get data. + const char *p_data = e_size + 1; + if (task.read_size != size_t(response.End() - p_data)) + return false; // assert buffer size and reported size match + if (task.read_size > task.size) + return false; // prevent buffer overrun + + Memory::Copy(task.data, p_data, task.read_size); + + ClearServerResponse(); + return true; +} +bool NetWorkerThread::ProcessHashTask(NetWorkerHashTask &task) +{ + if (!server_peer || !SendString(server_peer, String("Hash,") << task.path)) + return false; + + if (!WaitServerResponse()) + return false; + + // Check success. + if (Memory::Compare("Success,", response.c_ptr(), 8)) + return false; // failed + + // Grab hash. + task.hash.Set(response.c_ptr() + 8); + + ClearServerResponse(); + return true; +} +void NetWorkerThread::ProcessTask(NetWorkerBaseTask &task) +{ + bool success = false; + + switch (task.type) + { + case NetWorkerBaseTask::TypeOpen: success = ProcessOpenTask((NetWorkerOpenTask &)task); break; + case NetWorkerBaseTask::TypeClose: success = ProcessCloseTask((NetWorkerCloseTask &)task); break; + case NetWorkerBaseTask::TypeSeek: success = ProcessSeekTask((NetWorkerSeekTask &)task); break; + case NetWorkerBaseTask::TypeTell: success = ProcessTellTask((NetWorkerTellTask &)task); break; + case NetWorkerBaseTask::TypeRead: success = ProcessReadTask((NetWorkerReadTask &)task); break; + case NetWorkerBaseTask::TypeHash: success = ProcessHashTask((NetWorkerHashTask &)task); break; + } + + // [EJ] Full memory barrier required here. + task.success.Set(success ? 1 : 0); + task.processed.Set(1); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool NetWorkerThread::QueueTask(NetWorkerBaseTask &task) +{ + if (server_peer == NULL) + return false; // [EJ] no queue when not connected + + MutexLock lock(&task_mutex); + return asbool(task_queue.Add(&task)); +} +bool NetWorkerThread::CancelTask(NetWorkerBaseTask &task) +{ + MutexLock lock(&task_mutex); + return asbool(task_queue.Remove(&task)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetWorkerThread::OnPeerConnection(void *peer) +{ + __LOG_V__ << "IO::Net: OnPeerConnection\n"; + + if (server_peer || (handshaking != 1)) // already connected + { + Disconnect(peer); + return; + } + + SetPeerTimeout(peer, TimeoutVeryLong); + SendString(peer, "RequestIOAccess"); + + ++handshaking; +} +void NetWorkerThread::OnPacketReceived(void *peer, const void *data, size_t size) +{ +// __LOG_V__ << "IO::Net: Packet received, handshaking = " << handshaking << ", data: " << String((const char *)data, (const char *)data + size) << "\n"; + + if (handshaking == 2) + { + if ((size == 8) && !GS::Memory::Compare(data, "Granted", size)) + { + server_peer = peer; + ++handshaking; + } + else + Disconnect(peer); + } + else + if (server_peer == peer) + ProcessIOPacket(data, size); +} +void NetWorkerThread::OnConnectionClosed(void *peer) +{ + if (server_peer == peer) + server_peer = NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetWorkerThread::ProcessIOPacket(const void *data, size_t size) +{ + if (response.Allocate(size)) + Memory::Copy(response.c_ptr(), data, size); +} +bool NetWorkerThread::WaitServerResponse() +{ + while (response.GetSize() == 0) + { + if (server_peer == NULL) + return false; + UpdateHost(); + } + return true; +} +void NetWorkerThread::ClearServerResponse() +{ response.Free(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetWorkerThread::Execute() +{ + Thread::SetName("GS::IO::NetWorkerThread"); + + handshaking = 1; + + __LOG_V__ << "IO::Net - Client worker thread connecting to " << ip << " port " << port << ".\n"; + if (!OpenClient(ip, port)) + __ERRRAW__(__LOG_E__ << "Connection failed.\n"); + + __LOG_V__ << "IO::Net - Entering file server loop...\n"; + for (running.Set(1); running.Get() != 2; ) + { + UpdateHost(); + + if (server_peer != NULL) + { + MutexLock lock(&task_mutex); + while (NetWorkerBaseTask *task = task_queue.GetCount() > 0 ? task_queue.GetRoot()->Object() : NULL) + { + task_queue.RemoveAt(0); + ProcessTask(*task); + } + + if (server_peer == NULL) // [EJ] if connection was lost during this run, drop all pending tasks. + task_queue.Clear(); + } + + Platform::Get().Sleep(1); + } + + handshaking = 0; + + __LOG_V__ << "IO::Net - Client worker thread exiting.\n"; + running.Set(0); +} +bool NetWorkerThread::Start(const char *_ip, int _port) +{ + ip = _ip; + port = _port; + return Thread::Start(); +} +void NetWorkerThread::Stop() +{ + if (running.Get() != 0) + { + running.Set(2); + while (running.Get() != 0); // spinlock + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NetWorkerThread::NetWorkerThread() : server_peer(0), handshaking(0) {} +//------------------------------------------------------------------------------ diff --git a/include/modules/io_net/io_net_server.cpp b/include/modules/io_net/io_net_server.cpp new file mode 100644 index 0000000..5d586ab --- /dev/null +++ b/include/modules/io_net/io_net_server.cpp @@ -0,0 +1,325 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "io_net/io_net_server.h" + #include "metafile/nml.h" + #include "async/task_loop.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS::IO; + +// #define VERBOSE_LOG + + +// @FIXME Rewrite communication with the controller thread using AsyncCallQueue. + +//------------------------------------------------------------------------------ +NetServer::Client *NetServer::GetClient(void *peer) +{ + ListForeachPtr(Client *, client, clients) + if (client->peer == peer) + return client; + return NULL; +} +int NetServer::GetClientFreeHandleIndex(const Client &client) const +{ + int free_id = 0; + ListForeachPtr(ClientHandleInfo *, i, client.handles) + if (i->id >= free_id) + free_id = i->id + 1; + return free_id; +} +Handle *NetServer::GetClientHandle(const Client &client, int id) const +{ + ListForeachPtr(ClientHandleInfo *, i, client.handles) + if (i->id == id) + return i->handle; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool NetServer::ProcessCloseCommand(Client &client, GS::StringList &args) +// Close,handle_id +{ + if (args.GetCount() != 2) + return false; + + int id = args[1].Integer(); + + ClientHandleInfo *hi = NULL; + ListForeachPtr(ClientHandleInfo *, i, client.handles) + if (i->id == id) + { + hi = i; + break; + } + + if (hi == NULL) + return false; + + client.handles.Remove(hi); + +#ifdef VERBOSE_LOG + __LOG__ << "IO::NetServer: Close handle " << id << " (client total: " << client.handles.GetCount() << ").\n"; +#endif + return SendString(client.peer, "Success"); +} +bool NetServer::ProcessReadCommand(Client &client, GS::StringList &args) +// Read,size,handle_id +{ + if (args.GetCount() != 3) + return false; + + Handle *h = GetClientHandle(client, args[2].Integer()); + if (h == NULL) + return false; + + // Read data. + size_t size = size_t(args[1].Integer()); + Array data(size); + size_t read_size = h->Read((void *)data, size); + + // Format answer data (FIXME two allocations are not required for this). + String answer = String::Format("Success,%d,", read_size); + + Array answer_data(answer.Len() + read_size); + Memory::Copy(answer_data.c_ptr(), answer.c_str(), answer.Len()); + Memory::Copy(answer_data.c_ptr() + answer.Len(), data.c_ptr(), read_size); + + return Send(client.peer, (void *)answer_data.c_ptr(), answer_data.GetSize()); +} +bool NetServer::ProcessSeekCommand(Client &client, GS::StringList &args) +// Seek,offset_from_start,ref,handle_id +{ + if (args.GetCount() != 4) + return false; + + Handle *h = GetClientHandle(client, args[3].Integer()); + if (h == NULL) + return false; + + ptrdiff_t offset = ptrdiff_t(args[1].Integer()); + + Base::SeekRef seek_ref; + if (args[2] == "Start") + seek_ref = Base::SeekStart; + else if (args[2] == "Current") + seek_ref = Base::SeekCurrent; + else if (args[2] == "End") + seek_ref = Base::SeekEnd; + else + return false; + + size_t r = h->Seek(offset, seek_ref); + return SendString(client.peer, String::Format("Success,%d", r)); +} +bool NetServer::ProcessTellCommand(Client &client, GS::StringList &args) +// Tell,handle_id +{ + if (args.GetCount() != 2) + return false; + + Handle *h = GetClientHandle(client, args[1].Integer()); + if (h == NULL) + return false; + + return SendString(client.peer, String::Format("Success,%d", h->Tell())); +} +bool NetServer::ProcessOpenCommand(Client &client, GS::StringList &args) +// Open,path +{ + if (args.GetCount() != 2) + __ERR__(__LOG_E__ << "NetServer::ProcessOpenCommand(): incorrect argument count.\n", false) + + int index = GetClientFreeHandleIndex(client); + + AutoPtr i(new ClientHandleInfo); + i->id = index; + i->name = args[1]; + i->handle = basefs->Open(i->name); + if (i->handle.IsNull()) + return false; // __ERR__(__LOG_E__ << "NetServer::ProcessOpenCommand(): failed to open '" << i->name << "' on base filesystem.\n", false) + + client.handles.Add(i.Detach()); + +#ifdef VERBOSE_LOG + __LOG__ << "IO::NetServer: Open handle '" << args[1] << "' => " << index << " (client total: " << client.handles.GetCount() << ").\n"; +#endif + return SendString(client.peer, String::Format("Success,%d", index)); +} +bool NetServer::ProcessHashCommand(Client &client, GS::StringList &args) +// Hash,path +{ + if (args.GetCount() != 2) + return false; + + String hash = basefs->Hash(args[1]); + if (hash.IsEmpty()) + return false; + + return SendString(client.peer, String::Format("Success,%s", hash.c_str())); +} +bool NetServer::ProcessClientRequest(Client &client, const GS::String &data) +{ + StringList args; + data.Split(",", args); + + bool r = false; + + // Command dispatch. + if (args[0] == "Open") + r = ProcessOpenCommand(client, args); + else if (args[0] == "Seek") + r = ProcessSeekCommand(client, args); + else if (args[0] == "Tell") + r = ProcessTellCommand(client, args); + else if (args[0] == "Read") + r = ProcessReadCommand(client, args); + else if (args[0] == "Close") + r = ProcessCloseCommand(client, args); + else if (args[0] == "Hash") + r = ProcessHashCommand(client, args); + + if (!r) + SendString(client.peer, "Failed"); + return r; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetServer::GetStatistics(Statistics &stats) +{ + Time t = Platform::Get().GetTime(); + + stats.connected = asbool(clients.GetCount()); + + Network::Enet::Statistics enet_stats; + Network::Enet::GetStatistics(enet_stats); + + if ((t - bandwidth_measure.time).toSec() > 2) + { + bandwidth = int((enet_stats.sent_data - bandwidth_measure.value) / (t - bandwidth_measure.time).toSec()); + + bandwidth_measure.time = t; + bandwidth_measure.value = enet_stats.sent_data; + } + + stats.sent_data = enet_stats.sent_data; + stats.bandwidth = bandwidth; + + stats.packet_loss = 0; + if (clients.GetCount() > 0) + { + ListForeachPtr(Client *, client, clients) + stats.packet_loss += GetPeerPacketLossRatio(client->peer); + stats.packet_loss /= clients.GetCount(); + } + + // Handle statistics. + int handle_count = 0; + ListForeachPtr(Client *, client, clients) + handle_count += client->handles.GetCount(); + + if (stats.handles.Allocate(handle_count)) + { + handle_count = 0; + ListForeachPtr(Client *, client, clients) + ListForeachPtr(ClientHandleInfo *, i, client->handles) + { + Statistics::Handle *h = &stats.handles[handle_count++]; + h->name = i->name; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetServer::OnPeerConnection(void *peer) +{ + __LOG_H__ << "IO::NetServer: OnPeerConnection\n"; + + __ASSERT__(GetClient(peer) == NULL); + clients.Add(new Client(peer)); + + SetPeerTimeout(peer, TimeoutVeryLong); +} +void NetServer::OnPacketReceived(void *peer, const void *data, size_t size) +{ + Client *client = GetClient(peer); + __ASSERT__(client != NULL); + + if (size > 512) + { + SendString(peer, "DataLengthError"); + return; // invalid + } + + String command((char *)data, (char *)data + size); + + if (client->handshake_step == -1) + ProcessClientRequest(*client, command); + + else + { + switch (client->handshake_step) + { + case 0: + if (command == "RequestIOAccess") + { + __LOG_V__ << "Granting client access.\n"; + client->handshake_step = -1; + + SendString(peer, "Granted"); + } + else + Disconnect(peer); + break; + } + } +} +void NetServer::OnConnectionClosed(void *peer) +{ + __LOG_H__ << "IO::NetServer: OnConnectionClosed\n"; + + Client *client = GetClient(peer); + __ASSERT__(client != NULL); + clients.Remove(client); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool NetServer::Start(const char *ip, int port) +{ + __LOG_H__ << "IO::NetServer: Starting on " << ip << " port " << port << ".\n"; + return OpenServer(ip, port); +} +void NetServer::Stop() +{ + __LOG_H__ << "IO::NetServer: Shutting down.\n"; + + // Disconnect all clients. + ListForeachPtr(Client *, c, clients) + Disconnect(c->peer); + + StartTaskLoop(clients.GetCount() > 0, 2000) + { + UpdateHost(); + Platform::Get().Sleep(1); + } + EndTaskLoop + + Close(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NetServer::NetServer(Base *fs) : basefs(fs), bandwidth(0) +{} +NetServer::~NetServer() +{ Stop(); } +//------------------------------------------------------------------------------ diff --git a/include/modules/io_net/io_net_server_thread.cpp b/include/modules/io_net/io_net_server_thread.cpp new file mode 100644 index 0000000..d5088f8 --- /dev/null +++ b/include/modules/io_net/io_net_server_thread.cpp @@ -0,0 +1,76 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "io_net/io_net_server_thread.h" + #include "filesystem/io_cfile.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +void NetServerThread::Execute() +{ + { + Threading::MutexLock lock(&server_mutex); + server = new NetServer(basefs); + } + + if (server->Start(ip.c_str(), port)) + for (state.Set(1); state.Get() != 2; ) + { + { + Threading::MutexLock lock(&server_mutex); + server->UpdateHost(); + } + Platform::Get().Sleep(1); + } + + { + Threading::MutexLock lock(&server_mutex); + server = NULL; + } + state.Set(0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool NetServerThread::Start(const char *_ip, int _port) +{ + ip = _ip; + port = _port; + + if (!Thread::Start()) + return false; + + while (state.Get() == 0) + ; + + return asbool(state.Get() != -1); +} +void NetServerThread::Stop() +{ + state.Set(2); + while (state.Get() != 0); // spinlock +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void NetServerThread::GetStatistics(NetServer::Statistics &stats) +{ + Threading::MutexLock lock(&server_mutex); + if (server.IsValid()) + server->GetStatistics(stats); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +NetServerThread::~NetServerThread() +{ + Stop(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/io_zip/io_zip.cpp b/include/modules/io_zip/io_zip.cpp new file mode 100644 index 0000000..5cbc1c5 --- /dev/null +++ b/include/modules/io_zip/io_zip.cpp @@ -0,0 +1,211 @@ +/*------------------------------------------------------------------------------ + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "io_zip/io_zip.h" + #include "unzip.h" + #include "filesystem/io_handle_segment.h" + #include "filesystem/filesystem.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +// I/O wrapper for unzip (allows archive access from various I/O systems). +static voidpf Zip_open_file_func(voidpf opaque, const char *filename, int mode) +{ + __LOG__ << "ZipOpenFileFunc(); filename: " << filename << ", mode: " << mode << ".\n"; + if (mode & ZLIB_FILEFUNC_MODE_READ) + return GS::Platform::Get().io->Open(filename); + if (mode & ZLIB_FILEFUNC_MODE_WRITE) + return GS::Platform::Get().io->Open(filename, ModeWrite); + return NULL; +} +static uLong Zip_read_file_func(voidpf opaque, voidpf stream, void *buf, uLong size) +{ return ((Handle *)stream)->Read(buf, size); } +static uLong Zip_write_file_func(voidpf opaque, voidpf stream, const void *buf, uLong size) +{ return ((Handle *)stream)->Write(buf, size); } +static int Zip_close_file_func(voidpf opaque, voidpf stream) +{ + __LOG__ << "ZipCloseFileFunc();\n"; + delete ((Handle *)stream); + return UNZ_OK; +} +static int Zip_testerror_file_func(voidpf opaque, voidpf stream) +{ return UNZ_OK; } + +static long Zip_tell_file_func(voidpf opaque, voidpf stream) +{ return ((Handle *)stream)->Tell(); } +static long Zip_seek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) +{ + static Base::SeekRef ref[] = { Base::SeekStart, Base::SeekCurrent, Base::SeekEnd }; + return ((Handle *)stream)->Seek(offset, ref[origin]) == -1 ? -1 : 0; +} +//------------------------------------------------------------------------------ + +static zlib_filefunc_def Zip_filefunc = +{ Zip_open_file_func, Zip_read_file_func, Zip_write_file_func, Zip_tell_file_func, Zip_seek_file_func, Zip_close_file_func, Zip_testerror_file_func, 0 }; + +//------------------------------------------------------------------------------ +bool Zip::SetArchive(const char *uri, const char *pass) +{ + if (zfile) + unzClose(zfile); + zfile = NULL; + + if (!uri) + return true; + + __LOG_H__ << "Zip::SetArchive() connect to archive '" << uri << "', password: " << (pass ? pass : "(empty)") << ".\n"; + + password = pass; + return uri ? (zfile = unzOpen2(uri, &Zip_filefunc)) != NULL : false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Zip::GetCaps() const +{ return CanRead | CanSeek| IsCaseSensitive; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *Zip::Open(const char *path, Mode mode) +{ + if (!zfile) + __ERR__(__LOG_E__ << "Cannot open file with no archive support.\n", NULL) + + if (mode == ModeWrite) + return NULL; // unsupported + + /* + Query the memory file system so that multiple accesses to the same + compressed file will share a single uncompressed memory buffer. + */ + bool is_memory_handle = false; + Handle *h = memfs->Open(path, mode); + + if (!h) + if (unzLocateFile(zfile, path, 1) == UNZ_OK) // case-sensitive + { + // Get file info. + unz_file_info info; + unzGetCurrentFileInfo(zfile, &info, 0, 0, 0, 0, 0, 0); + + if (info.compression_method == 0) + { + unzOpenCurrentFile(zfile); + size_t offset = (size_t)unzGetCurrentFileZStreamPos64(zfile); + unzCloseCurrentFile(zfile); + + __LOG__ << "Mapping zip segment to '" << path << "' @" << int(offset) << "\n"; + Handle *zh = (Handle *)unzGetFileStream(zfile); + h = new HandleSegment(zh, offset, info.uncompressed_size); + } + else + { + __LOG__ << "Mapping unzipped '" << path << "' to memory...\n"; + + // Load the whole file into memory. + Array data(info.uncompressed_size, Alloc::Filesystem); + if (data.GetSize() != info.uncompressed_size) + __ERR__(__LOG_E__ << "Failed to allocate decompression space for '" << path << "'.\n", NULL) + + int r = password.IsEmpty() ? unzOpenCurrentFile(zfile) : unzOpenCurrentFilePassword(zfile, password); + if (r != UNZ_OK) + __ERR__(__LOG_E__ << "Failed to open file '" << path << "'.\n", NULL) + if (unzReadCurrentFile(zfile, (voidp)data.c_ptr(), info.uncompressed_size) != (int)info.uncompressed_size) + __ERR__(__LOG_E__ << "Failed to read file '" << path << "'.\n", NULL) + unzCloseCurrentFile(zfile); + + // Write to the support I/O memory filesystem. + AutoPtr wh(memfs->Open(path, ModeWrite)); + if (wh.IsValid()) + wh->Write(data.c_ptr(), data.GetSize()); + + // Open memory based uncompressed file. + h = memfs->Open(path, mode); + is_memory_handle = true; + } + } + + if (h) + if (ZipHandle *z = new ZipHandle(this)) + { + // Wrap memory I/O handle. + if (is_memory_handle) + { + // Increase refcount for this file. + Pair *p = refc_map.Get(path); + if (!p) + p = refc_map.Add(path, 0); + ++p->value; + + z->p = p; + } + + z->h = h; + return z; + } + + return NULL; +} +void Zip::Close(Handle *h) +{ + if (ZipHandle *z = (ZipHandle *)h) + { + if (z->p) + { + // If refcount for this entry reaches 0, drop it from the support I/O. + if (--z->p->value == 0) + { + memfs->Delete(z->p->key); + refc_map.Delete(z->p); + } + z->p = NULL; + } + z->h = NULL; + } +} + +bool Zip::Delete(const char *uri) +{ return false; } + +size_t Zip::Seek(Handle *h, ptrdiff_t offset, SeekRef ref) +{ + if (ZipHandle *z = (ZipHandle *)h) + return z->h->Seek(offset, ref); + return (size_t)-1; +} +size_t Zip::Tell(Handle *h) +{ + if (ZipHandle *z = (ZipHandle *)h) + return z->h->Tell(); + return (size_t)-1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t Zip::Read(Handle *h, void *b, size_t size) +{ + if (ZipHandle *z = (ZipHandle *)h) + return z->h->Read(b, size); + return 0; +} +size_t Zip::Write(Handle *h, const void *b, size_t size) +{ return 0; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Zip::Zip(const char *uri, const char *password) +{ + zfile = NULL; + memfs = new Memory; + SetArchive(uri, password); +} +Zip::~Zip() +{ SetArchive(NULL, NULL); } +//------------------------------------------------------------------------------ diff --git a/include/modules/nav_detour/navmesh.cpp b/include/modules/nav_detour/navmesh.cpp new file mode 100644 index 0000000..a4c7b06 --- /dev/null +++ b/include/modules/nav_detour/navmesh.cpp @@ -0,0 +1,251 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "nav_detour/navmesh.h" + #include "core/geometry.h" + #include "Recast.h" + #include "DetourNavMeshQuery.h" + #include "DetourNavMeshBuilder.h" + #include "log/log.h" + + using namespace GS::Core; + using namespace GS::Nav; + + +//------------------------------------------------------------------------------ +bool Mesh::Build(const Geometry *geo, const BuildConfig &cfg) +{ + // Convert geometry to triangle. + uint nverts = geo->vtx.GetCount(); + + Array verts(nverts); + if (float *pverts = verts.c_ptr()) + for (uint n = 0; n < nverts; ++n) + { + *pverts++ = geo->vtx[n][0]; + *pverts++ = geo->vtx[n][1]; + *pverts++ = geo->vtx[n][2]; + } + + uint ntris = geo->GetTriangleCount(); + + Array tris(ntris * 3); + if (int *ptris = tris.c_ptr()) + for (uint n = 0; n < geo->pol.GetCount(); ++n) + { + Polygon &p = geo->pol[n]; + for (int i = 1; i < (p.vtx_count - 1); ++i) + { + *ptris++ = p.binding[0]; + *ptris++ = p.binding[i]; + *ptris++ = p.binding[i + 1]; + } + } + + // Init build configuration from GUI + rcConfig m_cfg; + + m_cfg.cs = 0.5f; // Cell size. + m_cfg.ch = 0.2f; // Cell height. + m_cfg.walkableSlopeAngle = 40.f; // Max slope. + m_cfg.walkableHeight = (int)Math::Ceil(cfg.agent.height / m_cfg.ch); + m_cfg.walkableClimb = (int)Math::Floor(cfg.agent.max_climb / m_cfg.ch); + m_cfg.walkableRadius = (int)Math::Ceil(cfg.agent.radius / m_cfg.cs); + +/* + m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); + m_cfg.maxSimplificationError = m_edgeMaxError; + m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size + m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size + m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly; + m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist; + m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError; +*/ + /* + Set the area where the navigation will be build. + Here the bounds of the input mesh are used, but the area could be + specified by an user defined box, etc. + */ + + MinMax mm = geo->ComputeMinMax(); + rcVcopy(m_cfg.bmin, &mm.mn.x); + rcVcopy(m_cfg.bmax, &mm.mx.x); + rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height); + + // Allocate voxel heightfield where we rasterize our input data to. + AutoPtr solid(rcAllocHeightfield()); + if (solid.IsNull()) + __ERR__(__LOG_E__ << "Failed to allocate heightfield.\n", false) + + rcContext ctx; + if (!rcCreateHeightfield(&ctx, *solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch)) + __ERR__(__LOG_E__ << "Failed to create heightfield.\n", false) + + /* + Allocate array that can hold triangle area types. + If you have multiple meshes you need to process, allocate an array which + can hold the max number of triangles you need to process. + */ + Array triareas(ntris); + if (triareas.IsNull()) + __ERR__(__LOG_E__ << "Failed to allocate triangle areas.\n", false) + + /* + Find triangles which are walkable based on their slope and rasterize + them. If your input data is multiple meshes, you can transform them + here, calculate the are type for each of the meshes and rasterize them. + */ + Memory::Set(triareas, 0, ntris * sizeof(unsigned char)); + rcMarkWalkableTriangles(&ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, triareas); + rcRasterizeTriangles(&ctx, verts, nverts, tris, triareas, ntris, *solid, m_cfg.walkableClimb); + + triareas.Free(); + + /* + Once all geometry is rasterized, we do initial pass of filtering to + remove unwanted overhangs caused by the conservative rasterization + as well as filter spans where the character cannot possibly stand. + */ + rcFilterLowHangingWalkableObstacles(&ctx, m_cfg.walkableClimb, *solid); + rcFilterLedgeSpans(&ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *solid); + rcFilterWalkableLowHeightSpans(&ctx, m_cfg.walkableHeight, *solid); + + /* + Compact the heightfield so that it is faster to handle from now on. + This will result more cache coherent data as well as the neighbours + between walkable cells will be calculated. + */ + rcCompactHeightfield *chf = rcAllocCompactHeightfield(); + if (!chf) + __ERR__(__LOG_E__ << "Failed to allocate compact heightfield.\n", false) + if (!rcBuildCompactHeightfield(&ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *solid, *chf)) + __ERR__(__LOG_E__ << "Failed to build compact heightfield.\n", false) + + solid = NULL; + + // Erode the walkable area by agent radius. + if (!rcErodeWalkableArea(&ctx, m_cfg.walkableRadius, *chf)) + __ERR__(__LOG_E__ << "Failed to erode walkable area.\n", false) + + // (Optional) Mark areas. +/* + const ConvexVolume *vols = m_geom->getConvexVolumes(); + for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i) + rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf); +*/ + // Prepare for region partitioning, by calculating distance field along the walkable surface. + if (!rcBuildDistanceField(&ctx, *chf)) + __ERR__(__LOG_E__ << "Failed to build distance fields.\n", false) + + // Partition the walkable surface into simple regions without holes. + if (!rcBuildRegions(&ctx, *chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) + __ERR__(__LOG_E__ << "Failed to build regions.\n", false) + + // Create contours. + rcContourSet *cset = rcAllocContourSet(); + if (!cset) + __ERR__(__LOG_E__ << "Failed to allocate contour set.\n", false) + if (!rcBuildContours(&ctx, *chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *cset)) + __ERR__(__LOG_E__ << "Failed to create contour set.\n", false) + + // Build polygon navmesh from the contours. + rcPolyMesh *pmesh = rcAllocPolyMesh(); + if (!pmesh) + __ERR__(__LOG_E__ << "Failed to allocate navmesh.\n", false) + if (!rcBuildPolyMesh(&ctx, *cset, m_cfg.maxVertsPerPoly, *pmesh)) + __ERR__(__LOG_E__ << "Failed to build navmesh.\n", false) + + rcPolyMeshDetail *dmesh = rcAllocPolyMeshDetail(); + if (!dmesh) + __ERR__(__LOG_E__ << "Failed to allocate detail mesh.\n", false) + if (!rcBuildPolyMeshDetail(&ctx, *pmesh, *chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *dmesh)) + __ERR__(__LOG_E__ << "Failed to build detail mesh.\n", false) + + rcFreeCompactHeightfield(chf); + chf = 0; + rcFreeContourSet(cset); + cset = 0; + + // The GUI may allow more max points per polygon than Detour can handle. + // Only build the detour navmesh if we do not exceed the limit. + if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON) + { + // Update poly flags from areas. +/* + for (int i = 0; i < pmesh->npolys; ++i) + { + if (pmesh->areas[i] == RC_WALKABLE_AREA) + pmesh->areas[i] = SAMPLE_POLYAREA_GROUND; + + if (pmesh->areas[i] == SAMPLE_POLYAREA_GROUND || pmesh->areas[i] == SAMPLE_POLYAREA_GRASS || pmesh->areas[i] == SAMPLE_POLYAREA_ROAD) + pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK; + + else if (pmesh->areas[i] == SAMPLE_POLYAREA_WATER) + pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM; + + else if (pmesh->areas[i] == SAMPLE_POLYAREA_DOOR) + pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR; + } +*/ + dtNavMeshCreateParams params; + Memory::Set(¶ms, 0, sizeof(params)); + params.verts = pmesh->verts; + params.vertCount = pmesh->nverts; + params.polys = pmesh->polys; + params.polyAreas = pmesh->areas; + params.polyFlags = pmesh->flags; + params.polyCount = pmesh->npolys; + params.nvp = pmesh->nvp; + params.detailMeshes = dmesh->meshes; + params.detailVerts = dmesh->verts; + params.detailVertsCount = dmesh->nverts; + params.detailTris = dmesh->tris; + params.detailTriCount = dmesh->ntris; +/* + params.offMeshConVerts = m_geom->getOffMeshConnectionVerts(); + params.offMeshConRad = m_geom->getOffMeshConnectionRads(); + params.offMeshConDir = m_geom->getOffMeshConnectionDirs(); + params.offMeshConAreas = m_geom->getOffMeshConnectionAreas(); + params.offMeshConFlags = m_geom->getOffMeshConnectionFlags(); + params.offMeshConUserID = m_geom->getOffMeshConnectionId(); + params.offMeshConCount = m_geom->getOffMeshConnectionCount(); +*/ + params.walkableHeight = cfg.agent.height; + params.walkableRadius = cfg.agent.radius; + params.walkableClimb = cfg.agent.max_climb; + rcVcopy(params.bmin, pmesh->bmin); + rcVcopy(params.bmax, pmesh->bmax); + params.cs = m_cfg.cs; + params.ch = m_cfg.ch; + params.buildBvTree = true; + + unsigned char *navData = 0; + int navDataSize = 0; + if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize)) + __ERR__(__LOG_E__ << "Failed to create Detour navmesh.\n", false) + + dtNavMesh *navMesh = dtAllocNavMesh(); + if (!navMesh) + { + dtFree(navData); + __ERR__(__LOG_E__ << "Failed to build Detour navmesh.\n", false) + } + + dtStatus status = navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA); + if (dtStatusFailed(status)) + { + dtFree(navData); + __ERR__(__LOG_E__ << "Failed to initialize Detour navmesh.\n", false) + } + /* + status = navQuery->init(navMesh, 2048); + if (dtStatusFailed(status)) + __ERR__(__LOG_E__ << "Failed to initialize Detour navmesh query.\n", false) + */ + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/network_enet/enet_network.cpp b/include/modules/network_enet/enet_network.cpp new file mode 100644 index 0000000..535658c --- /dev/null +++ b/include/modules/network_enet/enet_network.cpp @@ -0,0 +1,191 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "network_enet/enet_network.h" + #include "nstring/nstring.h" + #include "thread/mutex.h" + #include "log/log.h" + + using GS::String; + using namespace GS::Network; + + +//------------------------------------------------------------------------------ +void Enet::GetStatistics(Statistics &stat) +{ + stat.received_data = host->totalReceivedData; + stat.sent_data = host->totalSentData; +} +int Enet::GetPeerPacketLossRatio(void *peer) +{ + ENetPeer *enet_peer = (ENetPeer *)peer; + return enet_peer && enet_peer->packetsSent ? (enet_peer->packetsLost * 100) / enet_peer->packetsSent : 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Enet::SetPeerTimeout(void *peer, Timeout timeout) +{ + int k = 1; + + switch (timeout) + { + case TimeoutLong: k = 2; break; + case TimeoutVeryLong: k = 4; break; + + default: break; + } + + enet_peer_timeout((ENetPeer *)peer, ENET_PEER_TIMEOUT_LIMIT * k, ENET_PEER_TIMEOUT_MINIMUM * k, ENET_PEER_TIMEOUT_MAXIMUM * k); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Enet::UpdateHost() +{ + if (host) + { + ENetEvent event; + while (enet_host_service(host, &event, 0) > 0) + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + OnPeerConnection(event.peer); + break; + + case ENET_EVENT_TYPE_RECEIVE: + OnPacketReceived(event.peer, (void *)event.packet->data, (size_t)event.packet->dataLength); + enet_packet_destroy(event.packet); + break; + + case ENET_EVENT_TYPE_DISCONNECT: + OnConnectionClosed(event.peer); + break; + + default: break; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Enet::Close() +{ + if (host) + enet_host_destroy(host); + host = NULL; +} +bool Enet::OpenServer(const char *hostname, int port) +{ + Close(); + + ENetAddress address; + if (hostname) + enet_address_set_host(&address, hostname); + else + address.host = ENET_HOST_ANY; + address.port = (enet_uint16)port; + + __LOG__ << "Starting server on " << (hostname ? hostname : "ANY") << ":" << port << "... "; + if ((host = enet_host_create(&address, 4, 0, 0, 0)) != NULL) + __LOG__ << "OK\n"; + else + __LOG__ << "FAILED\n"; +/* + if (host) + enet_host_compress_with_range_coder(host); +*/ + return asbool(host); +} +bool Enet::OpenClient(const char *hostname, int port) +{ + Close(); + + if ((host = enet_host_create(NULL, 1, 0, 0, 0)) == NULL) + return false; + +// enet_host_compress_with_range_coder(host); + + ENetAddress address; + enet_address_set_host(&address, hostname); + address.port = (enet_uint16)port; + + // Connect on one channel to server. + __LOG__ << "Opening client connection to " << hostname << ":" << port << "... "; + bool r = asbool(enet_host_connect(host, &address, 1, 0)); + if (r) + __LOG__ << "OK.\n"; + else + __LOG__ << "FAILED\n"; + return r; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Enet::GetHostAddress(String &address) +{ + if (host) + { + char ip[64]; + if (enet_address_get_host_ip(&((ENetHost *)host)->address, ip, 63) < 0) + return false; + address = ip; + } + return true; +} +bool Enet::GetPeerAddress(void *peer, String &address) +{ + if (peer) + { + char ip[64]; + if (enet_address_get_host_ip(&((ENetPeer *)peer)->address, ip, 63) < 0) + return false; + address = ip; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Enet::Send(void *peer, const void *data, size_t size) +{ +// __LOG_V__ << "Send Enet packet of " << size << " bytes.\n"; + + ENetPacket *packet = enet_packet_create(data, size, ENET_PACKET_FLAG_RELIABLE); + if (!packet || enet_peer_send((ENetPeer *)peer, 0, packet)) + return false; + enet_host_flush(host); + return true; +} +bool Enet::Broadcast(const void *data, size_t size) +{ + ENetPacket *packet = enet_packet_create(data, size, ENET_PACKET_FLAG_RELIABLE); + if (!packet) + return false; + enet_host_broadcast(host, 0, packet); + enet_host_flush(host); + return true; +} +void Enet::Disconnect(void *peer) +{ + if (peer) + enet_peer_disconnect((ENetPeer *)peer, 0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Enet::Enet() +{ + host = NULL; + enet_initialize(); +} +Enet::~Enet() +{ + Close(); + enet_deinitialize(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/physic_bullet/bullet_character_controller.cpp b/include/modules/physic_bullet/bullet_character_controller.cpp new file mode 100644 index 0000000..588ba50 --- /dev/null +++ b/include/modules/physic_bullet/bullet_character_controller.cpp @@ -0,0 +1,486 @@ + + + #include "physic_bullet/bullet_character_controller.h" + #include "LinearMath/btIDebugDraw.h" + #include "nstring/nstring.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void btCustomCharacterController::debugDraw(btIDebugDraw *idebug) +{ + String output; + + output << "Vertical Velocity: " << mVerticalVelocity << "\n"; + output << "OnGround: " << (mGroundContact ? "Yes" : "No") << "\n"; + output << "Ground.y: " << mGroundNormal.y() << "\n"; + output << "Step high: " << dbg_step_high << "\n"; + output << "Down sweep: " << dbg_down_sweep_hit << "\n"; + + idebug->draw3dText(mCurrentPosition, output.c_str()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +btVector3 btCustomCharacterController::computeReflectionDirection(const btVector3 & direction, const btVector3 & normal) +{ return direction - (btScalar(2) * direction.dot(normal)) * normal; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +btCustomCharacterController::btCustomCharacterController(btPairCachingGhostObject * ghostObject, btConvexShape * convexShape, btScalar stepHeight, btCollisionWorld * collisionWorld, int upAxis) +{ + mUpAxis = upAxis; + mAddedMargin = 0.02; + mWalkDirection.setValue(0, 0, 0); +// mUseGhostObjectSweepTest = true; + mGhostObject = ghostObject; + mStepHeight = stepHeight; + mTurnAngle = 0; + mConvexShape = mStandingConvexShape = convexShape; + mUseWalkDirection = true; + mVelocityTimeInterval = 0; + mVerticalOffset = 0; + mVerticalVelocity = 0; + mGravity = 9.8 * 3.0; + mFallSpeed = 9.8; + mJumpSpeed = 10; +// mWasOnGround = false; +// mWasJumping = false; + setMaxSlope(btRadians(45)); + mCollisionWorld = collisionWorld; +// mCanStand = true; + mCurrentPosition.setValue(0, 0, 0); + mMass = 20; + mGroundContact = false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setDuckingConvexShape(btConvexShape * shape) +{ mDuckingConvexShape = shape; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setRBForceImpulseBasedOnCollision() +{ + if (mWalkDirection.isZero()) + return; + + for (int i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); ++i) + { + btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; + + btRigidBody *rb = (btRigidBody*)collisionPair->m_pProxy1->m_clientObject; + + if (mMass > rb->getInvMass()) + { + btScalar resultMass = mMass - rb->getInvMass(); + btVector3 reflection = computeReflectionDirection(mWalkDirection * resultMass, getNormalizedVector(mWalkDirection)); + rb->applyCentralImpulse(reflection * -1); + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setVelocityForTimeInterval(const btVector3 & velocity, btScalar timeInterval) +{ + mUseWalkDirection = false; + mWalkDirection = velocity; + mNormalizedDirection = getNormalizedVector(mWalkDirection); + mVelocityTimeInterval = timeInterval; +} + +void btCustomCharacterController::warp(const btVector3 & origin) +{ + btTransform xform; + xform.setIdentity(); + xform.setOrigin(origin); + mGhostObject->setWorldTransform(xform); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool btCustomCharacterController::SweepTest(const btVector3 &src, const btVector3 &dst, btScalar &hitFraction, btVector3 *normal, btVector3 *hit) +{ + btTransform start, end; + start.setIdentity(); end.setIdentity(); + start.setOrigin(src); end.setOrigin(dst); + + ClosestNotMeConvexResultCallback callback(mGhostObject, getUpAxisDirection(), 0); + callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup; + callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask; + + mGhostObject->convexSweepTest(mConvexShape, start, end, callback, mCollisionWorld->getDispatchInfo().m_allowedCcdPenetration); + + hitFraction = callback.hasHit() ? callback.m_closestHitFraction : btScalar(1); + if (normal) + *normal = callback.m_hitNormalWorld; + if (hit) + *hit = callback.m_hitPointWorld; + + return callback.hasHit(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool btCustomCharacterController::recoverFromPenetration(const btVector3 &step_direction) +{ +return false; + mCollisionWorld->getDispatcher()->dispatchAllCollisionPairs(mGhostObject->getOverlappingPairCache(), mCollisionWorld->getDispatchInfo(), mCollisionWorld->getDispatcher()); + + bool penetration = false; + for (int i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); ++i) + { + btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; + + mManifoldArray.resize(0); + if (collisionPair->m_algorithm) + collisionPair->m_algorithm->getAllContactManifolds(mManifoldArray); + + for (int j = 0; j < mManifoldArray.size(); ++j) + { + btPersistentManifold *manifold = mManifoldArray[j]; + btScalar directionSign = manifold->getBody0() == mGhostObject ? btScalar(1) : btScalar(-1); + + for (int p = 0; p < manifold->getNumContacts(); ++p) + { + const btManifoldPoint &pt = manifold->getContactPoint(p); + + btScalar dist = pt.getDistance(); + btVector3 normal = pt.m_normalWorldOnB * directionSign; + + if (dist < 0.0) + { + penetration = true; + + if (normal.y() > 0.9) + normal = btVector3(0, 1, 0); // prevent sliding down slopes + + mCurrentPosition -= normal * dist * btScalar(0.1); + } + } + } + } + return penetration; +} +//------------------------------------------------------------------------------ + + +#include "log/log.h" + +enum +{ + UpSweep, + ForwardSweep, + DownSweep +}; + +//------------------------------------------------------------------------------ +bool btCustomCharacterController::SweepAndSlide(btVector3 &from, btVector3 &to, int sweep) +{ + bool hit = false; + for (int it = 0; it < 4; ++it) + { + btScalar hit_fraction; + btVector3 hit_normal; + if (!SweepTest(from, to, hit_fraction, &hit_normal)) + return hit; + + switch (sweep) + { + case ForwardSweep: + if (hit_normal.y() < 0.75) + { + hit_normal.setY(0.0); + hit_normal.normalize(); + } + else + hit = true; + break; + } + + from += (to - from) * hit_fraction; + to -= hit_normal * (to - from).dot(hit_normal); + + if ((to - from).length2() < btScalar(0.0001)) + break; + } + return hit; +} +//------------------------------------------------------------------------------ + +void btCustomCharacterController::performStep(btScalar dt) +{ + btScalar hit_fraction; + btVector3 hit_normal, hit_point; + +mStepHeight = 0.25; + + // up sweep + btVector3 step_height = getUpAxisDirection() * mStepHeight; + + btVector3 wpos = mGhostObject->getWorldTransform().getOrigin(); + btVector3 tpos = wpos + step_height; + + SweepTest(wpos, tpos, hit_fraction, &hit_normal); + tpos = wpos + (tpos - wpos) * hit_fraction; + + // forward sweep + bool forward_hit = false; + + if (mWalkDirection.length2() > 0.0) + { + wpos = tpos; + tpos += mWalkDirection; + + forward_hit = SweepAndSlide(wpos, tpos, ForwardSweep); + } + + // down sweep + btVector3 g = btVector3(0, -9, 0) * dt; + + wpos = tpos; + tpos -= step_height; + tpos += g; + + bool down_hit = SweepTest(wpos, tpos, hit_fraction, &hit_normal); + tpos = wpos + (tpos - wpos) * hit_fraction; + + // landing on a steep slope higher than we starter, revert height change. + if (down_hit && (hit_normal.y() < 0.75)) + { + tpos += hit_normal * 0.2; + wpos = tpos; + tpos = wpos - btVector3(0, 4, 0); + + SweepTest(wpos, tpos, hit_fraction); + tpos = wpos + (tpos - wpos) * hit_fraction; + } + + + + mCurrentPosition = tpos; + return; +// } +/* + // perform high sweep to step above small obstacle + btVector3 step_height = getUpAxisDirection() * mStepHeight; + + wpos = mGhostObject->getWorldTransform().getOrigin() + step_height; + tpos = wpos + mWalkDirection; + + if (!SweepAndSlide(wpos, tpos, HighSweep)) + return; // high sweep is not cutting it either... drop its result entirely + + // step down from the high sweep + wpos = tpos; + tpos -= step_height; + + if (!SweepAndSlide(wpos, tpos, DownSweep)) + { + mVerticalVelocity = 0; + return; + } + + +// else + { + mVerticalVelocity = btClamped(mVerticalVelocity - mGravity * dt, -mFallSpeed, mJumpSpeed); + + wpos = tpos; + tpos += btVector3(0, mVerticalVelocity, 0) * dt; + + SweepAndSlide(wpos, tpos, GravitySweep); + } + + // commit + mCurrentPosition = tpos; +*/ +} + + +//------------------------------------------------------------------------------ +void btCustomCharacterController::preStep(btCollisionWorld *collisionWorld) +{} +void btCustomCharacterController::playerStep(btCollisionWorld * collisionWorld, btScalar dt) +{ + if (!mUseWalkDirection && mVelocityTimeInterval <= 0) + return; + +performStep(dt); +#if 0 + mCurrentPosition = mGhostObject->getWorldTransform().getOrigin(); + + // Apply gravity. + mVerticalVelocity = btClamped(mVerticalVelocity - mGravity * dt, -mFallSpeed, mJumpSpeed); + + // Compute total step velocity. + mTouchingContact = false; + for (int n = 0; (n < 4) && recoverFromPenetration(mWalkDirection + btVector3(0, -1, 0) * mVerticalVelocity); ++n) + mTouchingContact = true; + + // Perform sweep tests. + btVector3 stepHeight = getUpAxisDirection() * mStepHeight; + btVector3 stepHigh = mCurrentPosition + stepHeight; + + btScalar hitFraction; + + mGroundContact = false; + if (SweepTest(stepHigh, stepHigh + mWalkDirection, hitFraction, &mGroundNormal)) + { + btVector3 hit = stepHigh + mWalkDirection * hitFraction; + if (mGroundNormal.y() > 0.6) // on ground, take step + mCurrentPosition = hit; + } + else + { + stepHigh += mWalkDirection; // take the whole walk step + + btVector3 g = stepHeight - mVerticalVelocity * getUpAxisDirection(); + + bool down_sweep_hit = SweepTest(stepHigh, stepHigh - g, hitFraction, &mGroundNormal); + + if (!down_sweep_hit) + { + mCurrentPosition += mVerticalVelocity * getUpAxisDirection(); // free-falling + } + else + { + mGroundContact = mGroundNormal.y() > 0.6; + + btVector3 dp = stepHigh - g * hitFraction; + + if (dp.y() > mCurrentPosition.y()) // going up a slope + { + if (mGroundContact) + mCurrentPosition = dp; // ok if on ground + } + else + mCurrentPosition = dp; + } + } +#endif + + + + // + if (mGroundContact) + mVerticalVelocity = 0.0; + + // + btTransform xform = mGhostObject->getWorldTransform(); + xform.setOrigin(mCurrentPosition); + mGhostObject->setWorldTransform(xform); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setFallSpeed(btScalar fallSpeed) +{ mFallSpeed = fallSpeed; } +void btCustomCharacterController::setJumpSpeed(btScalar jumpSpeed) +{ mJumpSpeed = jumpSpeed; } +void btCustomCharacterController::setMaxJumpHeight(btScalar maxJumpHeight) +{ mMaxJumpHeight = maxJumpHeight; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool btCustomCharacterController::canJump() const +{ return onGround(); } +void btCustomCharacterController::jump() +{ + if (!canJump()) + return; + + mVerticalVelocity = mJumpSpeed; +// mWasJumping = true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::duck() +{ + mConvexShape = mDuckingConvexShape; + mGhostObject->setCollisionShape(mDuckingConvexShape); + + btTransform xform; + xform.setIdentity(); + xform.setOrigin(mCurrentPosition + btVector3(0, 0.1, 0)); + mGhostObject->setWorldTransform(xform); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::stand() +{ + mConvexShape = mStandingConvexShape; + mGhostObject->setCollisionShape(mStandingConvexShape); +} +bool btCustomCharacterController::canStand() +{ + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setGravity(const btScalar gravity) +{ mGravity = gravity; } +btScalar btCustomCharacterController::getGravity() const +{ return mGravity; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setMaxSlope(btScalar slopeRadians) +{ + mMaxSlopeRadians = slopeRadians; + mMaxSlopeCosine = btCos(slopeRadians); +} +btScalar btCustomCharacterController::getMaxSlope() const +{ return mMaxSlopeRadians; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool btCustomCharacterController::onGround() const +{ return mGroundContact; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setWalkDirection(const btVector3 & walkDirection) +{ + mUseWalkDirection = true; + mWalkDirection = walkDirection; + mNormalizedDirection = getNormalizedVector(mWalkDirection); +} +void btCustomCharacterController::setWalkDirection(const btScalar x, const btScalar y, const btScalar z) +{ + mUseWalkDirection = true; + mWalkDirection.setValue(x, y, z); + mNormalizedDirection = getNormalizedVector(mWalkDirection); +} +btVector3 btCustomCharacterController::getWalkDirection() const +{ return mWalkDirection; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +btVector3 btCustomCharacterController::getPosition() const +{ return mCurrentPosition; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::setOrientation(const btQuaternion &orientation) +{ + btTransform xform; + xform = mGhostObject->getWorldTransform(); + xform.setRotation(orientation); + mGhostObject->setWorldTransform(xform); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void btCustomCharacterController::updateAction(btCollisionWorld *collisionWorld, btScalar dt) +{ + preStep(collisionWorld); + playerStep(collisionWorld, dt); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/physic_bullet/bullet_constraint.cpp b/include/modules/physic_bullet/bullet_constraint.cpp new file mode 100644 index 0000000..28840c9 --- /dev/null +++ b/include/modules/physic_bullet/bullet_constraint.cpp @@ -0,0 +1,176 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic_bullet/bullet_constraint.h" + #include "physic_bullet/bullet_item.h" + #include "scene3d/mitem.h" + + using namespace GS; + using namespace GS::S3D; + +void BulletConstraint::setLimitHinge(float low, float high, float _softness, float _biasFactor, float _relaxationFactor) +{ + if (!constraint) + return; + + switch (type) + { + case PhysicConstraintDesc::TypeHinge: + ((btHingeConstraint*)constraint)->setLimit(low, high, _softness, _biasFactor, _relaxationFactor); + break; + } +} +//------------------------------------------------------------------------------ +void BulletConstraint::SetPivotA(const Matrix4 &pivot) +{ + if (!constraint) + return; + + switch (type) + { + case PhysicConstraintDesc::TypePoint: + { + Vector4 p = pivot.GetRow(3); + if (item_a.IsValid()) + p -= ((BulletPhysicItem *)item_a.c_ptr())->GetCenter(); + + btVector3 bt_pivot(p.x, p.y, p.z); + ((btPoint2PointConstraint *)constraint)->setPivotA(bt_pivot); + } + break; + + default: break; + } +} +void BulletConstraint::SetPivotB(const Matrix4 &pivot) +{ + if (constraint) + switch (type) + { + case PhysicConstraintDesc::TypePoint: + { + Vector4 p = pivot.GetRow(3); + if (item_b.IsValid()) + p -= ((BulletPhysicItem *)item_b.c_ptr())->GetCenter(); + + btVector3 bt_pivot(p.x, p.y, p.z); + ((btPoint2PointConstraint *)constraint)->setPivotB(bt_pivot); + } + break; + + default: break; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletConstraint::Enable(bool b) +{ + if (constraint) + constraint->setEnabled(b); +} +bool BulletConstraint::SetupConstraint(const PhysicConstraintDesc &desc) +{ + DeleteConstraint(); + + // Get constraint items. + item_a = desc.item_a.IsValid() ? desc.item_a->physic_item.c_ptr() : NULL; + item_b = desc.item_b.IsValid() ? desc.item_b->physic_item.c_ptr() : NULL; + + BulletPhysicItem *bullet_item_a = (BulletPhysicItem *)item_a.c_ptr(), + *bullet_item_b = (BulletPhysicItem *)item_b.c_ptr(); + + btRigidBody *rigid_body_a = bullet_item_a ? bullet_item_a->rigid_body.c_ptr() : NULL, + *rigid_body_b = bullet_item_b ? bullet_item_b->rigid_body.c_ptr() : NULL; + + if (!rigid_body_a && !rigid_body_b) + return false; + + // Create constraint. + type = desc.type; + + switch (type) + { + case PhysicConstraintDesc::TypePoint: + { + Vector4 np_a = desc.pivot_a.GetRow(3), np_b = desc.pivot_b.GetRow(3); + + if (bullet_item_a) + np_a -= bullet_item_a->GetCenter(); + if (bullet_item_b) + np_b -= bullet_item_b->GetCenter(); + + btVector3 btp_a(np_a.x, np_a.y, np_a.z), btp_b(np_b.x, np_b.y, np_b.z); + + if (rigid_body_a && rigid_body_b) + constraint = new btPoint2PointConstraint(*rigid_body_a, *rigid_body_b, btp_a, btp_b); + if (rigid_body_a && !rigid_body_b) + constraint = new btPoint2PointConstraint(*rigid_body_a, btp_a); + + // constraint->setParam(BT_CONSTRAINT_ERP, 0.8); + // constraint->setParam(BT_CONSTRAINT_CFM, 0); + } + break; + case PhysicConstraintDesc::TypeHinge: + { + Vector4 np_a = desc.pivot_a.GetRow(3), np_b = desc.pivot_b.GetRow(3); + + if (bullet_item_a) + np_a -= bullet_item_a->GetCenter(); + if (bullet_item_b) + np_b -= bullet_item_b->GetCenter(); + + btVector3 btp_a(np_a.x, np_a.y, np_a.z), btp_b(np_b.x, np_b.y, np_b.z); + + if (rigid_body_a && rigid_body_b) + constraint = new btHingeConstraint(*rigid_body_a, *rigid_body_b, btp_a, btp_b, btVector3(0,0,1), btVector3(0,0,1)); + if (rigid_body_a && !rigid_body_b) + constraint = new btHingeConstraint(*rigid_body_a, btp_a, btVector3(0,1,0)); + // ((btHingeConstraint*)constraint)->setLimit(0, 0); + // constraint->setParam(BT_CONSTRAINT_STOP_CFM, 0); + // constraint->setParam(BT_CONSTRAINT_CFM, 0); + // constraint->setParam(BT_CONSTRAINT_STOP_ERP, 0.8); + // constraint->setParam(BT_CONSTRAINT_ERP, 0.8); + } + break; + + + default: break; + } + + if (constraint) + world->addConstraint(constraint); + + return true; +} +void BulletConstraint::DeleteConstraint() +{ + if (constraint) + { + world->removeConstraint(constraint); + _safe_delete(constraint); + } + + item_a = NULL; + item_b = NULL; + + type = PhysicConstraintDesc::TypeNone; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +BulletConstraint::BulletConstraint(btDiscreteDynamicsWorld *_world) +{ + type = PhysicConstraintDesc::TypeNone; + + world = _world; + constraint = NULL; +} +BulletConstraint::~BulletConstraint() +{ + DeleteConstraint(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/physic_bullet/bullet_debug.cpp b/include/modules/physic_bullet/bullet_debug.cpp new file mode 100644 index 0000000..93bb7a9 --- /dev/null +++ b/include/modules/physic_bullet/bullet_debug.cpp @@ -0,0 +1,83 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic_bullet/bullet_debug.h" + #include "core/renderer.h" + #include "core/renderer_toolbox.h" + #include "core/camera.h" + #include "gpu/gpu_renderer.h" + + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +void BulletDebugDraw::Flush() +{ + renderer.DrawLine(line_count, vtx_cache, col_cache, xray_first_pass ? GS::Core::Material::Blend_Alpha : GS::Core::Material::Blend_None, GS::Core::Material::Render_NoZWrite); + line_count = 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float BulletDebugDraw::GetXRayAlpha() const +{ return xray_first_pass ? 0.2f : 1.f; } +void BulletDebugDraw::SetXRayFirstPass(bool pass) +{ + // FIXME: WTF!? + ((GS::GPU::Renderer &)renderer).SetDepthFunc(pass ? GS::GPU::Renderer::DepthGreater : GS::GPU::Renderer::DepthLessEqual); + xray_first_pass = pass; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletDebugDraw::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) +{ + if (line_count == 2048) + Flush(); + + vtx_cache[(line_count << 1) + 0].Set(from.x(), from.y(), from.z()); + vtx_cache[(line_count << 1) + 1].Set(to.x(), to.y(), to.z()); + col_cache[(line_count << 1) + 0].Set(color.x(), color.y(), color.z(), GetXRayAlpha()); + col_cache[(line_count << 1) + 1].Set(color.x(), color.y(), color.z(), GetXRayAlpha()); + + ++line_count; +} +void BulletDebugDraw::drawContactPoint(const btVector3 &PointOnB, const btVector3 &/*normalOnB*/, btScalar /*distance*/, int /*lifeTime*/, const btVector3 &color) +{ + drawLine(PointOnB - btVector3(0.25, 0, 0), PointOnB + btVector3(0.25, 0, 0), color); + drawLine(PointOnB - btVector3(0, 0.25, 0), PointOnB + btVector3(0, 0.25, 0), color); + drawLine(PointOnB - btVector3(0, 0, 0.25), PointOnB + btVector3(0, 0, 0.25), color); +} +void BulletDebugDraw::reportErrorWarning(const char *) +{} +void BulletDebugDraw::draw3dText(const btVector3 &p, const char *text) +{ + if (camera && raster_font) + { + Matrix4 m = camera->GetMatrix(); + m.SetRow(3, Vector4(p.x(), p.y(), p.z())); + renderer.SetWorldMatrix(m); + + float x = 0, y = 0; + Renderer::WriterConfig config(true, false); + renderer.Write(*raster_font, text, x, y, config, 2.f); + + renderer.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + } +} +//------------------------------------------------------------------------------ + +BulletDebugDraw::BulletDebugDraw(Renderer &r) : renderer(r) +{ + vtx_cache.Allocate(2048 * 2); + col_cache.Allocate(2048 * 2); + line_count = 0; + + camera = NULL; + raster_font = NULL; + + xray_first_pass = true; +} diff --git a/include/modules/physic_bullet/bullet_item.cpp b/include/modules/physic_bullet/bullet_item.cpp new file mode 100644 index 0000000..b079a1c --- /dev/null +++ b/include/modules/physic_bullet/bullet_item.cpp @@ -0,0 +1,821 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic_bullet/bullet_item.h" + #include "physic_bullet/bullet_world.h" + #include "BulletCollision/CollisionDispatch/btGhostObject.h" + #include "physic_bullet/bullet_character_controller.h" + #include "physic/physic_item_desc.h" + #include "core/item.h" + #include "core/terrain.h" + #include "scene3d/mitem.h" + #include "math/matrix4.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +static Vector4 btTonVector(const btVector3 &v) +{ return Vector4(v.x(), v.y(), v.z()); } +static btVector3 nTobtVector(const Vector4 &v) +{ return btVector3(v.x, v.y, v.z); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletMotionState::setWorldTransform(const btTransform &comt) +{ + btTransform wt = comt; + const Vector4 &com = item->GetCenter(); + wt.setOrigin(wt.getOrigin() - wt.getBasis() * btVector3(com.x, com.y, com.z)); + item->TransformToMatrix4(wt, bullet_matrix); + bullet_matrix = bullet_matrix * Matrix4::ScaleMatrix(item->GetScale()); +} +void BulletMotionState::getWorldTransform(btTransform &wt) const +{ + item->TransformFromMatrix4(engine_matrix, wt); + const Vector4 &com = item->GetCenter(); + wt.setOrigin(wt.getOrigin() + wt.getBasis() * btVector3(com.x, com.y, com.z)); +} +BulletMotionState::BulletMotionState(BulletPhysicItem *_item) : item(_item) +{ + MItem *mitem = (MItem *)_item->GetUserPointer(); + bullet_matrix = mitem->GetBaseItem()->GetMatrix(); + engine_matrix = bullet_matrix; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint BulletPhysicItem::GetSelfMask() const +{ + btBroadphaseProxy *handle = NULL; + if (rigid_body) + handle = rigid_body->getBroadphaseHandle(); + if (ghost_object) + handle = ghost_object->getBroadphaseHandle(); + + return handle ? handle->m_collisionFilterGroup : 0; +} +void BulletPhysicItem::SetSelfMask(uint m) +{ + self_mask = m; + + btBroadphaseProxy *handle = NULL; + if (rigid_body) + handle = rigid_body->getBroadphaseHandle(); + if (ghost_object) + handle = ghost_object->getBroadphaseHandle(); + + if (handle) + { + handle->m_collisionFilterGroup = (short)m; + + // Refresh pair cache. + btworld->getBroadphase()->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(handle, btworld->getDispatcher()); + } +} +uint BulletPhysicItem::GetCollisionMask() const +{ + btBroadphaseProxy *handle = NULL; + if (rigid_body) + handle = rigid_body->getBroadphaseHandle(); + if (ghost_object) + handle = ghost_object->getBroadphaseHandle(); + + return handle ? handle->m_collisionFilterMask : 0; +} +void BulletPhysicItem::SetCollisionMask(uint m) +{ + collision_mask = m; + + btBroadphaseProxy *handle = NULL; + if (rigid_body) + handle = rigid_body->getBroadphaseHandle(); + if (ghost_object) + handle = ghost_object->getBroadphaseHandle(); + + if (handle) + { + handle->m_collisionFilterMask = (short)m; + + // Refresh pair cache. + btworld->getBroadphase()->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(handle, btworld->getDispatcher()); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::SetLinearDamping(float k) +{ + if (rigid_body) + rigid_body->setDamping(1.f - k, rigid_body->getAngularDamping()); +} +float BulletPhysicItem::GetLinearDamping() const +{ + return rigid_body ? 1.f - rigid_body->getLinearDamping() : 0; +} +void BulletPhysicItem::SetAngularDamping(float k) +{ + if (rigid_body) + rigid_body->setDamping(rigid_body->getLinearDamping(), 1.f - k); +} +float BulletPhysicItem::GetAngularDamping() const +{ + return rigid_body ? 1.f - rigid_body->getAngularDamping() : 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::SetLinearFactor(const Vector4 &k) +{ + if (rigid_body) + rigid_body->setLinearFactor(btVector3(k.x, k.y, k.z)); +} +void BulletPhysicItem::SetAngularFactor(const Vector4 &k) +{ + if (rigid_body) + rigid_body->setAngularFactor(btVector3(k.x, k.y, k.z)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::TransformFromMatrix4(const Matrix4 &m, btTransform &transform) +{ + btScalar scalar[15]; + scalar[0] = m.m[0][0]; scalar[1] = m.m[1][0]; scalar[2] = m.m[2][0]; scalar[3] = 1; + scalar[4] = m.m[0][1]; scalar[5] = m.m[1][1]; scalar[6] = m.m[2][1]; scalar[7] = 1; + scalar[8] = m.m[0][2]; scalar[9] = m.m[1][2]; scalar[10] = m.m[2][2]; scalar[11] = 1; + scalar[12] = m.m[0][3]; scalar[13] = m.m[1][3]; scalar[14] = m.m[2][3]; + transform.setFromOpenGLMatrix(scalar); +} +void BulletPhysicItem::TransformToMatrix4(const btTransform &transform, Matrix4 &m) +{ + btScalar scalar[16]; + transform.getOpenGLMatrix(scalar); + m.m[0][0] = scalar[0]; m.m[1][0] = scalar[1]; m.m[2][0] = scalar[2]; m.m[3][0] = 0; + m.m[0][1] = scalar[4]; m.m[1][1] = scalar[5]; m.m[2][1] = scalar[6]; m.m[3][1] = 0; + m.m[0][2] = scalar[8]; m.m[1][2] = scalar[9]; m.m[2][2] = scalar[10]; m.m[3][2] = 0; + m.m[0][3] = scalar[12]; m.m[1][3] = scalar[13]; m.m[2][3] = scalar[14]; m.m[3][3] = scalar[15]; +} +void BulletPhysicItem::GetGraphicMatrix(Matrix4 &m) +{ + if (ghost_object) + { + btTransform wt = ghost_object->getWorldTransform(); + wt.setOrigin(wt.getOrigin() - wt.getBasis() * btVector3(center.x, center.y, center.z)); + TransformToMatrix4(wt, m); + } + else + if (motion_state) + m = motion_state->GetGraphicMatrix(); +} +void BulletPhysicItem::SetEngineMatrix(const Matrix4 &m) +{ + if (motion_state) + motion_state->SetEngineMatrix(m); +} +void BulletPhysicItem::GetMatrix(Matrix4 &m) +{ + if (ghost_object) + TransformToMatrix4(ghost_object->getWorldTransform(), m); + else + if (rigid_body) + TransformToMatrix4(rigid_body->getWorldTransform(), m); +} +void BulletPhysicItem::SetMatrix(const Matrix4 &m) +{ + Vector4 p; + Matrix3 m3; + m.Decompose(&p, 0, &m3); + Matrix4 m4(Matrix4::FromMatrix3(m3)); + m4.SetRow(3, p); + + btTransform wt; + TransformFromMatrix4(m4, wt); + wt.setOrigin(wt.getOrigin() + wt.getBasis() * btVector3(center.x, center.y, center.z)); + + if (ghost_object) + ghost_object->setWorldTransform(wt); + else + if (rigid_body) + rigid_body->setWorldTransform(wt); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::SetSleeping(bool sleep) +{ + if (!rigid_body) + return; + + if (sleep) + rigid_body->setActivationState(WANTS_DEACTIVATION); + else rigid_body->activate(); +} +bool BulletPhysicItem::IsSleeping() const +{ return rigid_body ? rigid_body->wantsSleeping() : false; } +void BulletPhysicItem::SetActive(bool active) +{ + if (!rigid_body) + return; + + if (active) + { + /* + Note the activation state MUST be changed from + DISABLE_SIMULATION or activate() will silently fail. + */ + rigid_body->getBroadphaseHandle()->m_collisionFilterGroup = self_mask; + rigid_body->getBroadphaseHandle()->m_collisionFilterMask = collision_mask; + rigid_body->forceActivationState(ACTIVE_TAG); + rigid_body->activate(); + } + else + { + rigid_body->setActivationState(DISABLE_SIMULATION); + rigid_body->getBroadphaseHandle()->m_collisionFilterGroup = 0; + rigid_body->getBroadphaseHandle()->m_collisionFilterMask = 0; + } +} +bool BulletPhysicItem::GetActive() const +{ return rigid_body ? rigid_body->isActive() : false; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::VehicleSetForce(float F, uint i) +{ + if (vehicle && (i < (uint)vehicle->getNumWheels())) + vehicle->applyEngineForce(F, i); +} +void BulletPhysicItem::VehicleSetBrake(float F, uint i) +{ + if (vehicle && (i < (uint)vehicle->getNumWheels())) + vehicle->setBrake(F, i); +} +void BulletPhysicItem::VehicleSetSteering(float v, uint i) +{ + if (vehicle && (i < (uint)vehicle->getNumWheels())) + vehicle->setSteeringValue(v, i); +} +void BulletPhysicItem::VehicleSetFriction(float f, uint i) +{ + if (vehicle && (i < (uint)vehicle->getNumWheels())) + vehicle->getWheelInfo(i).m_frictionSlip = f; +} +Matrix4 BulletPhysicItem::VehicleGetWheelMatrix(uint i) +{ + Matrix4 m(Matrix4::IdentityMatrix()); + if (vehicle && (i < (uint)vehicle->getNumWheels())) + { + vehicle->updateWheelTransform(i, true); + TransformToMatrix4(vehicle->getWheelInfo(i).m_worldTransform, m); + } + return m; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::CharacterSetRotationMatrix(const Matrix3 &m) +{ + if (ghost_object) + { + btMatrix3x3 basis + ( + m.m[0][0], m.m[0][1], m.m[0][2], + m.m[1][0], m.m[1][1], m.m[1][2], + m.m[2][0], m.m[2][1], m.m[2][2] + ); + ghost_object->getWorldTransform().setBasis(basis); + } +} +void BulletPhysicItem::CharacterSetVelocity(const Vector4 &v) +{ + if (character_controller) + character_controller->setWalkDirection(nTobtVector(v)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::SetScale(const Vector4 &_scale) +{ + scale = _scale; + if (compound) + compound->setLocalScaling(nTobtVector(scale)); +} +Vector4 BulletPhysicItem::GetScale() const +{ return scale; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::ResetBody() +{ + if (rigid_body) + { + rigid_body->setLinearVelocity(btVector3(0, 0, 0)); + rigid_body->setAngularVelocity(btVector3(0, 0, 0)); + rigid_body->clearForces(); + } +} +void BulletPhysicItem::ForceUpdateMassShapePhysic(const PhysicItemDesc &desc, PhysicWorld *world) +{ + float total_mass = 0; + if (!desc.shape_list.GetCount()) + return; + + Array mass_array; + mass_array.Allocate(desc.shape_list.GetCount()); + center.Set(0, 0, 0); + btScalar *pmass_array = mass_array.c_ptr(); + + ListForeachPtr(PhysicShape *, shape, desc.shape_list) + { + Vector4 shape_center = shape->position; + center += shape_center * shape->mass; + total_mass += shape->mass; + *pmass_array++ = shape->mass; + } + center /= total_mass; + btTransform principal; + btVector3 body_inertia(0, 0, 0); + compound->calculatePrincipalAxisTransform(mass_array, principal, body_inertia); + + rigid_body->setMassProps(total_mass, body_inertia); + rigid_body->updateInertiaTensor(); + +} +//------------------------------------------------------------------------------ +float BulletPhysicItem::SetupCollisionShapes(const PhysicItemDesc &desc, Array &mass_array, PhysicWorld *world) +{ + float total_mass = 0; + if (!desc.shape_list.GetCount()) + return total_mass; + + mass_array.Allocate(desc.shape_list.GetCount()); + btScalar *pmass_array = mass_array.c_ptr(); + + // WTF man... can't Bullet handle COM offset by itself? + shapes.Allocate(desc.shape_list.GetCount()); + + center.Set(0, 0, 0); + + uint n = 0; + ListForeachPtr(PhysicShape *, shape, desc.shape_list) + { + btCollisionShape *btshape = NULL; + Vector4 shape_center = shape->position; + + switch (shape->GetType()) + { + case PhysicShape::TypeNone: + break; + + case PhysicShape::TypeHeightmap: + if (float *ph = shape->GetHeightmap()) + { + float min, max; + min = max = ph[0]; + for (int v = 0; v < shape->GetHeight(); ++v) + for (int u = 0; u < shape->GetWidth(); ++u) + { + if (ph[0] > max) + max = ph[0]; + if (ph[0] < min) + min = ph[0]; + ph++; + } + + btshape = new btHeightfieldTerrainShape(shape->GetWidth(), shape->GetHeight(), (void *)shape->GetHeightmap(), 1.f, min, max, 1, PHY_FLOAT, false); + } + break; + + case PhysicShape::TypeSphere: + btshape = new btSphereShape(shape->dimensions.x); + break; + + case PhysicShape::TypeBox: + { + const Vector4 &d = shape->dimensions; + btshape = new btBoxShape(btVector3(d.x * 0.5f, d.y * 0.5f, d.z * 0.5f)); + } + break; + + case PhysicShape::TypeCapsule: + { + const Vector4 &d = shape->dimensions; + btshape = new btCapsuleShapeZ(d.x * 0.5f, d.z); + } + break; + + case PhysicShape::TypeCylinder: + { + const Vector4 &d = shape->dimensions; + btshape = new btCylinderShapeZ(btVector3(d.x * 0.5f, d.y * 0.5f, d.z * 0.5f)); + } + break; + + case PhysicShape::TypeCone: + { + const Vector4 &d = shape->dimensions; + btshape = new btConeShapeZ(d.x * 0.5f, d.z * 0.5f); + } + break; + + case PhysicShape::TypeConvex: + if (BulletConvex *convex = ((BulletWorld *)world)->LoadConvex(shape->path)) + { + shapes[n].convex = convex; + + shape_center = convex->center * shape->GetMatrix(); + btshape = convex->convex; + } + break; + + case PhysicShape::TypeMesh: + if (desc.physic_mode == PhysicItemDesc::Mode_Static) + { + /* + [EJ] 06/03/13 - Bullet SILENTLY rescales the cached mesh + vertices to comply with the item scale. In order to support + multiple scales on the same mesh the path is suffixed with + the item scale. + */ + String suffix = String::Format("%.02f_%.02f_%.02f", scale.x, scale.y, scale.z); + + if (BulletMesh *mesh = ((BulletWorld *)world)->LoadMesh(shape->path, suffix)) + { + shapes[n].mesh = mesh; + + shape_center = mesh->center * shape->GetMatrix(); + btshape = mesh->mesh; + } + } + break; + } + + shapes[n].shape = btshape; + + center += shape_center * shape->mass; + total_mass += shape->mass; + *pmass_array++ = shape->mass; + + ++n; + } + + center /= total_mass; + if (desc.physic_mode == PhysicItemDesc::Mode_Vehicle) + center.Set(0, 0, 0); + + n = 0; + ListForeachPtr(PhysicShape *, shape, desc.shape_list) + { + if (btCollisionShape *btshape = shapes[n].shape) + { + Vector4 shape_offset(0, 0, 0); + + if (shape->GetType() == PhysicShape::TypeHeightmap) + { + float *ph = shape->GetHeightmap(); + + float min, max; + min = max = ph[0]; + + for (int v = 0; v < shape->GetHeight(); ++v) + for (int u = 0; u < shape->GetWidth(); ++u) + { + if (ph[0] > max) max = ph[0]; + if (ph[0] < min) min = ph[0]; + ph++; + } + + btshape->setLocalScaling(btVector3(1, 1, 1)); + + // Damn... what a mess. + float hy = (max - min) * -0.5f; + shape_offset.Set(0, min - hy, 0); + } + + Matrix4 m = Matrix4::TransformationMatrix(shape->position + shape_offset - center, shape->rotation, shape->scale); + btTransform transform; + TransformFromMatrix4(m, transform); + + compound->addChildShape(transform, btshape); + } + ++n; + } + return total_mass; +} +bool BulletPhysicItem::SetupCharacterController(const PhysicItemDesc &desc) +{ + ghost_object = new btPairCachingGhostObject(); + ghost_object->setUserPointer((PhysicItem *)this); + +#if 0 + convex_shape = new btCylinderShape(btVector3(desc.character.radius, desc.character.height * 0.5f, desc.character.radius)); + center.Set(0, desc.character.height * 0.5f, 0); +#else + float height = Types::Max(desc.character.height - desc.character.radius * 2.f, 0.f); + convex_shape = new btCapsuleShape(desc.character.radius, height); // Height is the distance between the center of the two spheres whose convex hull is a capsule. + center.Set(0, (height + desc.character.radius * 2.f) * 0.5f, 0); +#endif + + ghost_object->setCollisionShape(convex_shape); + ghost_object->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + +#if 1 + character_controller = new btKinematicCharacterController(ghost_object, convex_shape, desc.character.max_step); +#else + btCustomCharacterController *cc = new btCustomCharacterController(ghost_object, convex_shape, desc.character.max_step, btworld->getCollisionWorld()); + character_controller = cc; +#endif + return true; +} +bool BulletPhysicItem::SetupKinematicDynamicBody(const PhysicItemDesc &desc, PhysicWorld *world) +{ + // Setup collision shapes. + Array mass_array; + + compound = new btCompoundShape; + float total_mass = SetupCollisionShapes(desc, mass_array, world); + + if (!compound->getNumChildShapes()) + return true; + + // Initialize physic mode. + compound->setLocalScaling(nTobtVector(scale)); + btVector3 body_inertia(0, 0, 0); + + switch (desc.physic_mode) + { + case PhysicItemDesc::Mode_None: + break; + + case PhysicItemDesc::Mode_Dynamic: + case PhysicItemDesc::Mode_Vehicle: + if (compound->getNumChildShapes()) + { + btTransform principal; + compound->calculatePrincipalAxisTransform(mass_array, principal, body_inertia); + } + else + { + total_mass = 1; + body_inertia.setValue(1, 1, 1); + } + break; + + case PhysicItemDesc::Mode_Static: + case PhysicItemDesc::Mode_Kinematic: + total_mass = 0; + break; + } + + // Allocate motion state. + motion_state = new BulletMotionState(this); + + // Create rigid body. + rigid_body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(total_mass, motion_state, compound, body_inertia)); + rigid_body->setUserPointer((PhysicItem *)this); + + // Vehicle specialization. + if (desc.physic_mode == PhysicItemDesc::Mode_Vehicle) + { + rigid_body->setActivationState(DISABLE_DEACTIVATION); + + vehicle_raycaster = new btDefaultVehicleRaycaster(btworld); + vehicle = new btRaycastVehicle(btRaycastVehicle::btVehicleTuning(), rigid_body, vehicle_raycaster); + vehicle->setCoordinateSystem(0, 1, 2); + + // Add wheels. + ListForeachPtr(PhysicWheel *, wheel, desc.vehicle.wheel_list) + { + btRaycastVehicle::btVehicleTuning tuning; + + tuning.m_suspensionStiffness = wheel->stiffness; + tuning.m_suspensionDamping = wheel->damping; + tuning.m_suspensionCompression = wheel->damping; + tuning.m_frictionSlip = wheel->friction; + tuning.m_maxSuspensionTravelCm = wheel->max_compression * 10.f; // m to cm. + + Vector4 o = wheel->ref_matrix.GetRow(3), + u = wheel->ref_matrix.GetRow(1).Reversed(), + l = wheel->ref_matrix.GetRow(0).Reversed(); + + vehicle->addWheel(btVector3(o.x, o.y, o.z), btVector3(u.x, u.y, u.z), btVector3(l.x, l.y, l.z), wheel->rest_length, wheel->radius > 0.01f ? wheel->radius : 0.01f, tuning, false); + } + } + + // Set defaults. + SetLinearFactor(desc.linear_factor); + SetAngularFactor(desc.angular_factor); + SetLinearDamping(desc.linear_damping); + SetAngularDamping(desc.angular_damping); + + if (desc.shape_list.GetCount()) + { + PhysicShape *shape = desc.shape_list.GetRoot()->Object(); + rigid_body->setFriction(shape->static_friction); + rigid_body->setRestitution(shape->restitution); + } + + if (desc.physic_mode == PhysicItemDesc::Mode_Kinematic) + { + rigid_body->setCollisionFlags(rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + rigid_body->setActivationState(DISABLE_DEACTIVATION); + } + return true; +} +bool BulletPhysicItem::SetupBody(const PhysicItemDesc &desc, PhysicWorld *world) +{ + // EJ 11/10 + // + // - Bullet constraint holds strong/unmanaged reference to Bullet rigid bodies. + // - A Bullet rigid body is not meant to be radically modified once created. + +// BulletWorld *world = (PhysicWorld *)world; + + if (rigid_body || ghost_object) + return true; + + DeleteBody(); + + switch (desc.physic_mode) + { + case PhysicItemDesc::Mode_None: + return true; + + case PhysicItemDesc::Mode_Character: + if (!SetupCharacterController(desc)) + return false; + + btworld->addCollisionObject(ghost_object, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + btworld->addAction(character_controller); + break; + + default: + if (!SetupKinematicDynamicBody(desc, world)) + return false; + + if (rigid_body) + { + btworld->addRigidBody(rigid_body); + const Vector4 &g(world->GetGravity()); + rigid_body->setGravity(btVector3(g.x, g.y, g.z)); + } + if (vehicle) + btworld->addVehicle(vehicle); + break; + } + + SetCollisionMask(desc.collision_mask); + SetSelfMask(desc.self_mask); + return true; +} +void BulletPhysicItem::DeleteBody() +{ + // Destroy all shapes. + if (compound) + while (compound->getNumChildShapes()) + compound->removeChildShapeByIndex(0); + + // The collision shape for mesh/convex are cached and should not be deleted here! + for (uint n = 0; n < shapes.GetCount(); ++n) + if (shapes[n].convex.IsValid() || shapes[n].mesh.IsValid()) + shapes[n].shape.Detach(); + + shapes.Free(); + + // Destroy rigid body. + if (rigid_body) + btworld->removeRigidBody(rigid_body); + rigid_body = NULL; + + if (vehicle) + btworld->removeVehicle(vehicle); + vehicle = NULL; + vehicle_raycaster = NULL; + + if (ghost_object) + btworld->removeCollisionObject(ghost_object); + ghost_object = NULL; + + if (character_controller) + btworld->removeAction(character_controller); + character_controller = NULL; + + compound = NULL; + motion_state = NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletPhysicItem::SetGravity(const Vector4 &g) +{ + if (rigid_body) + rigid_body->setGravity(btVector3(g.x, g.y, g.z)); +} +Vector4 BulletPhysicItem::GetGravity() const +{ + if (!rigid_body) + return Vector4(0, 0, 0); + btVector3 g = rigid_body->getGravity(); + return Vector4(g.x(), g.y(), g.z()); +} +void BulletPhysicItem::ApplyImpulse(const Vector4 &I, const Vector4 *p) +{ + if (!rigid_body) + return; + + SetSleeping(false); + + if (p && (I.Len() > 0.0001)) + { + btVector3 l(p->x, p->y, p->z); + btVector3 J(I.x, I.y, I.z); + btScalar k = rigid_body->computeImpulseDenominator(l, J.normalized()); + rigid_body->applyImpulse(J / k, l - rigid_body->getCenterOfMassPosition()); + } + else + { + btVector3 J(I.x, I.y, I.z); + rigid_body->applyCentralImpulse(J / rigid_body->getInvMass()); + } +} +void BulletPhysicItem::ApplyForce(const Vector4 &F, const Vector4 *p) +{ + if (!rigid_body) + return; + + SetSleeping(false); + if (p) + rigid_body->applyForce(btVector3(F.x, F.y, F.z), btVector3(p->x, p->y, p->z) - rigid_body->getCenterOfMassPosition()); + else rigid_body->applyCentralForce(btVector3(F.x, F.y, F.z)); +} +void BulletPhysicItem::ApplyTorque(const Vector4 &T) +{ + if (rigid_body) + rigid_body->applyTorque(rigid_body->getCenterOfMassTransform().getBasis() * btVector3(T.x, T.y, T.z)); +} +void BulletPhysicItem::SetAngularVelocity(const Vector4 &w) +{ + if (rigid_body) + rigid_body->setAngularVelocity(btVector3(w.x, w.y, w.z)); +} +Vector4 BulletPhysicItem::GetAngularVelocity() const +{ + if (!rigid_body) + return Vector4(0, 0, 0); + const btVector3 &v = rigid_body->getAngularVelocity(); + return Vector4(v.x(), v.y(), v.z()); +} +void BulletPhysicItem::SetLinearVelocity(const Vector4 &v) +{ + if (rigid_body) + rigid_body->setLinearVelocity(btVector3(v.x, v.y, v.z)); +} +Vector4 BulletPhysicItem::GetLinearVelocity() const +{ + if (!rigid_body) + return Vector4(0, 0, 0); + const btVector3 &v = rigid_body->getLinearVelocity(); + return Vector4(v.x(), v.y(), v.z()); +} +Vector4 BulletPhysicItem::GetLocalPointVelocity(const Vector4 &p) const +{ + if (!rigid_body) + return Vector4(0, 0, 0); + btVector3 v = rigid_body->getVelocityInLocalPoint(rigid_body->getCenterOfMassTransform().getBasis() * btVector3(p.x, p.y, p.z)); + return Vector4(v.x(), v.y(), v.z()); +} +Vector4 BulletPhysicItem::GetWorldPointVelocity(const Vector4 &wp) const +{ + if (!rigid_body) + return Vector4(0, 0, 0); + btVector3 v = rigid_body->getVelocityInLocalPoint(btVector3(wp.x, wp.y, wp.z) - rigid_body->getCenterOfMassPosition()); + return Vector4(v.x(), v.y(), v.z()); +} +Vector4 BulletPhysicItem::GetCenterOfMass() const +{ + if (!rigid_body) + return Vector4(0, 0, 0); + btVector3 p = rigid_body->getCenterOfMassPosition(); + return Vector4(p.x(), p.y(), p.z()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +BulletPhysicItem::BulletPhysicItem(btDiscreteDynamicsWorld *w) +{ + btworld = w; + + center.Set(0, 0, 0); + scale.Set(1, 1, 1); +} +BulletPhysicItem::~BulletPhysicItem() +{ + DeleteBody(); +} +//---------------------------------------------------------------------------------- diff --git a/include/modules/physic_bullet/bullet_world.cpp b/include/modules/physic_bullet/bullet_world.cpp new file mode 100644 index 0000000..80560f7 --- /dev/null +++ b/include/modules/physic_bullet/bullet_world.cpp @@ -0,0 +1,345 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "physic_bullet/bullet_world.h" + #include "BulletCollision/CollisionDispatch/btGhostObject.h" + #include "physic_bullet/bullet_item.h" + #include "physic_bullet/bullet_constraint.h" + #include "physic_bullet/bullet_debug.h" + #include "core/geometry.h" + #include "metafile/nml_object.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +PhysicItem *BulletWorld::NewItem() +{ return new BulletPhysicItem(world); } +PhysicConstraint *BulletWorld::NewConstraint() +{ return new BulletConstraint(world); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +BulletConvex *BulletWorld::LoadConvex(const char *_name) +{ + String name(_name); + + // Check cache. + ListForeachPtr(BulletConvex *, convex, convex_cache) + if (convex->name == name) + return convex; + + // Load geometry. + AutoPtr g(new Core::Geometry); + if (!NML::LoadFromFile(*g, name)) + return NULL; + + // Setup convex. + BulletConvex *bullet_convex = new BulletConvex; + if (!bullet_convex) + __ERR__(__LOG_E__ << "Failed to allocate bullet convex.\n", NULL) + + Array bt_vtx(g->vtx.GetCount() * 3); + btScalar *p_bt_vtx = bt_vtx.c_ptr(); + + Vector4 gcenter(0, 0, 0); + for (uint n = 0; n < g->vtx.GetCount(); ++n) + { + gcenter += g->vtx[n]; + *p_bt_vtx++ = g->vtx[n].x; + *p_bt_vtx++ = g->vtx[n].y; + *p_bt_vtx++ = g->vtx[n].z; + } + + bullet_convex->name = name; + bullet_convex->center = (gcenter / (float)g->vtx.GetCount()); + bullet_convex->convex = new btConvexHullShape(bt_vtx.c_ptr(), g->vtx.GetCount(), 3 * sizeof(btScalar)); + convex_cache.Add(bullet_convex); + + return bullet_convex; +} +BulletMesh *BulletWorld::LoadMesh(const char *_name, const char *_suffix) +{ + String name(_name), suffix(_suffix); + + // Check cache. + ListForeachPtr(BulletMesh *, mesh, mesh_cache) + if ((mesh->name == name) && (mesh->suffix == suffix)) + { + __LOG_V__ << "Reusing cached Bullet btMesh for " << _name << " (suffix: " << _suffix << ").\n"; + return mesh; + } + + // Load bullet mesh. + AutoPtr g(new Core::Geometry); + if (g.IsNull()) + return NULL; + + g->name = name; + if (!NML::LoadFromFile(*g, name)) + return NULL; + + if (!g->vtx.GetCount() || !g->pol.GetCount()) + __ERR__(__LOG_E__ << "No geometry data in '" << g->name << "' to build collision shape.\n", NULL) + + BulletMesh *bullet_mesh = new BulletMesh; + if (!bullet_mesh) + __ERR__(__LOG_E__ << "Failed to allocate bullet mesh.\n", NULL) + + int triangle_count = g->GetTriangleCount(); + + bullet_mesh->bt_vtx.Allocate(g->vtx.GetCount() * 3); + btScalar *p_bt_vtx = bullet_mesh->bt_vtx; + bullet_mesh->bt_idx.Allocate(triangle_count * 3); + int *p_bt_idx = bullet_mesh->bt_idx; + + Vector4 gcenter(0, 0, 0); + for (uint n = 0; n < g->vtx.GetCount(); ++n) + { + gcenter += g->vtx[n]; + *p_bt_vtx++ = g->vtx[n].x; + *p_bt_vtx++ = g->vtx[n].y; + *p_bt_vtx++ = g->vtx[n].z; + } + bullet_mesh->center = gcenter / (float)g->vtx.GetCount(); + + // Triangulate geometry on the fly, transfer material indices. + bullet_mesh->bt_mat.Allocate(g->material_table.GetCount()); + for (uint n = 0; n < g->material_table.GetCount(); ++n) + bullet_mesh->bt_mat[n] = g->material_table[n].name; + + bullet_mesh->bt_id_mat.Allocate(triangle_count); + ushort *p_bt_id_mat = bullet_mesh->bt_id_mat; + + for (uint n = 0; n < g->pol.GetCount(); ++n) + for (int p = 1; p < (g->pol[n].vtx_count - 1); ++p) + { + *p_bt_idx++ = g->pol[n].binding[0]; + *p_bt_idx++ = g->pol[n].binding[p]; + *p_bt_idx++ = g->pol[n].binding[p + 1]; + *p_bt_id_mat++ = g->pol[n].material; + } + + bullet_mesh->name = name; + bullet_mesh->suffix = suffix; + bullet_mesh->mesh_interface = new btTriangleIndexVertexArray(triangle_count, bullet_mesh->bt_idx, 3 * sizeof(int), g->vtx.GetCount(), bullet_mesh->bt_vtx, 3 * sizeof(btScalar)); + bullet_mesh->mesh = new btBvhTriangleMeshShape(bullet_mesh->mesh_interface, true); + + mesh_cache.Add(bullet_mesh); + + return bullet_mesh; +} +void BulletWorld::ClearConvexMeshCache() +{ + convex_cache.Clear(); + mesh_cache.Clear(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool BulletWorld::HasDebugger() const +{ return debug_draw.IsValid(); } +void BulletWorld::CreateDebugger(Renderer *renderer) +{ + debug_draw = renderer ? new BulletDebugDraw(*renderer) : NULL; + if (world) + world->setDebugDrawer(debug_draw); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static void bullet_pretick_callback(btDynamicsWorld *world, btScalar timeStep) +{ + BulletWorld *physic_world = (BulletWorld *)world->getWorldUserInfo(); + if (physic_world->GetWorldInterface()) + physic_world->GetWorldInterface()->PhysicStep(timeStep, true); +} +static void bullet_posttick_callback(btDynamicsWorld *world, btScalar timeStep) +{ + BulletWorld *physic_world = (BulletWorld *)world->getWorldUserInfo(); + if (physic_world->GetWorldInterface()) + physic_world->GetWorldInterface()->PhysicStep(timeStep, false); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletWorld::DrawDebug(Renderer &, Camera *c, RasterFont *f, bool xray_first_pass) +{ + if (BulletDebugDraw *dd = (BulletDebugDraw *)world->getDebugDrawer()) + { + dd->camera = c; + dd->raster_font = f; + dd->SetDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits | btIDebugDraw::DBG_DrawContactPoints); +// dd->SetDebugMode(btIDebugDraw::DBG_DrawAabb | btIDebugDraw::DBG_FastWireframe); + dd->SetXRayFirstPass(xray_first_pass); + + world->debugDrawWorld(); + dd->Flush(); + } +} +uint BulletWorld::GetCollisionPairCount() +{ return world->getDispatcher()->getNumManifolds(); } +bool BulletWorld::GetCollisionPair(uint n, CollisionPair &pair) +{ + btPersistentManifold *manifold = world->getDispatcher()->getInternalManifoldPointer()[n]; + if (!manifold || !manifold->getNumContacts()) // Manifolds are valid as long as the bodies overlap in the broadphase. + return false; + + pair.a = (PhysicItem *)((btRigidBody *)manifold->getBody0())->getUserPointer(); + pair.b = (PhysicItem *)((btRigidBody *)manifold->getBody1())->getUserPointer(); + + pair.contact_count = 0; + for (int i = 0; (i < manifold->getNumContacts()) && (i < 4); ++i) + { + btVector3 p = manifold->getContactPoint(i).getPositionWorldOnB(); + pair.contact[i].Set(p.x(), p.y(), p.z()); + btVector3 n = manifold->getContactPoint(i).m_normalWorldOnB; + pair.normal[i].Set(n.x(), n.y(), n.z()); + + pair.contact_count++; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool BulletWorld::Create() +{ + collision_config = new btDefaultCollisionConfiguration(); + +#if __ENABLE_BULLET_MULTITHREAD__ + thread_support_collision = new Win32ThreadSupport(Win32ThreadSupport::Win32ThreadConstructionInfo("Bullet Collision", processCollisionTask, createCollisionLocalStoreMemory, __BULLET_THREAD_COUNT__)); + dispatcher = new SpuGatheringCollisionDispatcher(thread_support_collision, __BULLET_THREAD_COUNT__, collision_config); +#else + dispatcher = new btCollisionDispatcher(collision_config); +#endif + + broadphase = new btDbvtBroadphase(); + broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(pair_callback = new btGhostPairCallback); + + solver = new btSequentialImpulseConstraintSolver; + world = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collision_config); + world->setInternalTickCallback(bullet_pretick_callback, (void *)this, true); + world->setInternalTickCallback(bullet_posttick_callback, (void *)this, false); + +// world->getSolverInfo().m_numIterations = 10; +// world->getDispatchInfo().m_enableSPU = true; + world->getSolverInfo().m_solverMode = SOLVER_SIMD + SOLVER_USE_WARMSTARTING;// + SOLVER_RANDMIZE_ORDER; +// world->getSolverInfo().m_splitImpulse = 1; +// world->getSolverInfo().m_splitImpulsePenetrationThreshold = 0.2; + + world->setDebugDrawer(debug_draw); + return true; +} +void BulletWorld::Delete() +{ + ClearConvexMeshCache(); + + collision_config = NULL; + dispatcher = NULL; + broadphase = NULL; + solver = NULL; + world = NULL; +#if __ENABLE_BULLET_MULTITHREAD__ + thread_support_collision = NULL; +#endif +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void BulletWorld::Step(const GS::Time &dt) +{ + ScopedBenchmark bench(bench_step); + +#if 1 + substep_dt -= dt.toSec(); + + int limit = 4; + while (substep_dt < 0) + { + world->stepSimulation(GetTimestep(), 0, GetTimestep()); + substep_dt += GetTimestep(); + + if (--limit <= 0) + { + substep_dt = 0; + break; + } + } +#else + world->stepSimulation(dt, 12, GetTimestep()); +#endif +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool BulletWorld::Raytrace(const Vector4 &s, const Vector4 &d, PhysicTrace &hit, int collision_mask, int shape_mask, float max_distance) +{ + struct ClosestRayResultWithTriangleIndexCallback : public btCollisionWorld::ClosestRayResultCallback + { + ClosestRayResultWithTriangleIndexCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld) : ClosestRayResultCallback(rayFromWorld, rayToWorld) {} + + int m_TriangleIndex; + int m_shapePart; + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace) + { + if (rayResult.m_localShapeInfo) + { + m_TriangleIndex = rayResult.m_localShapeInfo->m_triangleIndex; + m_shapePart = rayResult.m_localShapeInfo->m_shapePart; + } + else + { + m_TriangleIndex = -1; + m_shapePart = -1; + } + return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); + } + }; + + Vector4 e = s + d * (max_distance > 0 ? max_distance : 5000.f); + btVector3 from(s.x, s.y, s.z), to(e.x, e.y, e.z); + + ClosestRayResultWithTriangleIndexCallback trace(from, to); + trace.m_collisionFilterGroup = btBroadphaseProxy::AllFilter; + trace.m_collisionFilterMask = (short)collision_mask; + world->rayTest(from, to, trace); + if (!trace.hasHit()) + return false; + + hit.p.Set(trace.m_hitPointWorld.x(), trace.m_hitPointWorld.y(), trace.m_hitPointWorld.z()); + hit.n.Set(trace.m_hitNormalWorld.x(), trace.m_hitNormalWorld.y(), trace.m_hitNormalWorld.z()); + hit.i = (PhysicItem *)trace.m_collisionObject->getUserPointer(); + + if (BulletPhysicItem *bi = (BulletPhysicItem *)hit.i) + if ((trace.m_shapePart >= 0) && ((uint)trace.m_shapePart < bi->shapes.GetCount())) + if (BulletMesh *mesh = bi->shapes[trace.m_shapePart].mesh.c_ptr()) + if (uint(trace.m_TriangleIndex) < mesh->bt_id_mat.GetCount()) + hit.m = mesh->bt_mat[mesh->bt_id_mat[trace.m_TriangleIndex]]; + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static void *bulletAlloc(size_t s) { return MemAllocPhysics::Alloc(s, Alloc::Physics); } +static void bulletFree(void *p) { MemAllocPhysics::Delete(p, Alloc::Physics); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +BulletWorld::BulletWorld() +{ + btAlignedAllocSetCustom(bulletAlloc, bulletFree); + substep_dt = 0; +} +BulletWorld::~BulletWorld() +{ + Delete(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/pict_io_jpeglib/pict_jpeglib_codec.cpp b/include/modules/pict_io_jpeglib/pict_jpeglib_codec.cpp new file mode 100644 index 0000000..6417e68 --- /dev/null +++ b/include/modules/pict_io_jpeglib/pict_jpeglib_codec.cpp @@ -0,0 +1,152 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "pict_io_jpeglib/pict_jpeglib_codec.h" + #include "picture/pict.h" + #include "container/narray.h" + + using namespace GS; + + +#if 1 + +extern "C" +{ + int JpgLoad_ansic(void *buf, int len, char **output, unsigned int *width, unsigned int *height); + int JpgSave_ansic(char *dst, int dst_len, int *size, int qual, char *buf, unsigned int w, unsigned int h); + void JpgFree_ansic(char **p); +}; + +//------------------------------------------------------------------------------ +void FetchHCoef(char *bf, int w, int /*h*/, int x, int y, float *cf) +{ + bf += y * w * 3; + for ( int p = (x - 2); p < (x + 2); p++ ) + { + int op = p; + if ( op < 0 ) op = 0; + else if ( op >= w ) op = w - 1; + *cf++ = (float)((unsigned char)bf[op * 3]); + } +} +float Spline4Inter(float t, float *cf) +{ + float v = cf[1]+0.5f*t*(cf[2]-cf[0]+t*(cf[2]+cf[1]*(-2.0f)+cf[0]+t*((cf[2]-cf[1])*9.0f+(cf[0]-cf[3])*3.f+t*((cf[1]-cf[2])*15.f+(cf[3]-cf[0])*5.f+t*((cf[2]-cf[1])*6.f+(cf[0]-cf[3])*2.f))))); + if ( v < 0.f ) + v = 0.f; + else if ( v > 255.f ) + v = 255.f; + return v; +} +char *RgbResize(char *rgb, int ow, int oh, int w, int h) +{ + char *nr = new char[w * h * 3], *pr; + int x, y, c, v; + float hc[4], vc[4]; + float px, py, dx, dy; + + dx = (float)ow / (float)w; + dy = (float)oh / (float)h; + + py = 0.f; + pr = nr; + for ( y = 0; y < h; y++ ) + { + px = 0.f; + for ( x = 0; x < w; x++ ) + { + for ( c = 0; c < 3; c++ ) + { + float *pvc = vc; + for ( v = -2; v < 2; v++ ) + { + int sy = v + (int)py; + if ( sy < 0 ) sy = 0; + if ( sy >= oh ) sy = oh - 1; + FetchHCoef(rgb + c, ow, oh, (int)px, sy, hc); + *pvc++ = Spline4Inter(px - ((int)px), hc); + } + *pr++ = (unsigned char)Spline4Inter(py - ((int)py), vc); + } + px += dx; + } + py += dy; + } + return nr; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void JpeglibCppInterfaceFree(char **p) +{ JpgFree_ansic(p); } +int JpeglibCppInterfaceLoad(void *f, int l, char **o, unsigned int *w, unsigned int *h) +{ return JpgLoad_ansic(f, l, o, w, h); } +int JpeglibCppInterfaceSave(char *dst, int dst_len, int *size, int q, char *b, unsigned int w, unsigned int h) +{ return JpgSave_ansic(dst, dst_len, size, q, b, w, h); } +//------------------------------------------------------------------------------ + +#endif + +//------------------------------------------------------------------------------ +bool PictureJpeglibCodec::Load(IO::Handle &handle, Picture &picture) +{ + uchar header[2]; + handle.Rewind(); + if (handle.Read(header, 2) != 2) + return false; + if ((header[0] != 0xff) || (header[1] != 0xd8)) + return false; + + // SOI marker found, good to go. + size_t size = handle.GetSize(); + Array buffer((uint)size); + if (!buffer) + return false; + + handle.Rewind(); + handle.Read(buffer, size); + + uint width, height; + char *c_data = NULL; + + if (JpeglibCppInterfaceLoad(buffer, (int)size, &c_data, &width, &height)) + { + // Transfer C data to a C++ allocation. + picture.AllocAs(width, height); + if (uchar *data = picture.GetData()) + { + uchar *j_data = (uchar *)c_data; + for (uint h = 0; h < height; ++h) + for (uint w = 0; w < width; ++w) + { + data[0] = j_data[2]; + data[1] = j_data[1]; + data[2] = j_data[0]; + data[3] = j_data[3]; + j_data += 4; + data += 4; + } + } + + // Drop C data. + JpeglibCppInterfaceFree(&c_data); + } + return asbool(picture.GetData()); +} +bool PictureJpeglibCodec::Save(IO::Handle &handle, const Picture &picture) +{ + // FIXME this is stupid. + Array dst(5000000); + if (!dst) + return false; + + int size = 0; + if (!JpeglibCppInterfaceSave(&dst[0], (uint)dst.GetSize(), &size, 100, (char *)picture.GetData(), picture.GetWidth(), picture.GetHeight())) + return false; + + return handle.Write(dst, size) == (size_t)size; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/pict_io_stb/pict_stb_codec.cpp b/include/modules/pict_io_stb/pict_stb_codec.cpp new file mode 100644 index 0000000..08c0df9 --- /dev/null +++ b/include/modules/pict_io_stb/pict_stb_codec.cpp @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "pict_io_stb/pict_stb_codec.h" + #include "picture/pict.h" + #include "filesystem/io_handle.h" + #include "container/narray.h" + #include "memory/memory.h" + #include "log/log.h" + + #define STBI_NO_STDIO + #include "stb_image.h" + + using namespace GS; + + +//----------------------------------------------------------------------------- +static int n_stb_read_h(void *user, char *data, int size) +{ return ((IO::Handle *)user)->Read(data, size); } +static void n_stb_skip_h(void *user, unsigned n) +{ ((IO::Handle *)user)->Seek(n); } +static int n_stb_eof_h(void *user) +{ return ((IO::Handle *)user)->IsEOF() ? 1 : 0; } +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +bool PictureSTBCodec::Load(IO::Handle &handle, Picture &picture) +{ + handle.Rewind(); + + stbi_io_callbacks cb; + cb.read = &n_stb_read_h; + cb.skip = &n_stb_skip_h; + cb.eof = &n_stb_eof_h; + + /* + Swizzle and transfer to C++ allocation. + Watch the memory peak!... + */ + int comp, width, height; + if (char *c_data = (char *)stbi_load_from_callbacks(&cb, &handle, &width, &height, &comp, STBI_rgb_alpha)) + { + picture.AllocAs(width, height); + if (char *p_data = (char *)picture.GetData()) + Memory::Copy(p_data, c_data, width * height * 4); + stbi_image_free(c_data); + } + return asbool(picture.GetData()); +} +//----------------------------------------------------------------------------- diff --git a/include/modules/raytracer/raytracer_core.cpp b/include/modules/raytracer/raytracer_core.cpp new file mode 100644 index 0000000..794e9e7 --- /dev/null +++ b/include/modules/raytracer/raytracer_core.cpp @@ -0,0 +1,748 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "raytracer/raytracer_core.h" + #include "raytracer/raytracer_job.h" + #include "scene3d/mobject.h" + #include "scene3d/mlight.h" + #include "scene3d/mcamera.h" + #include "scene3d/scene.h" + #include "rand/rand.h" + #include "platform.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +float Raytracer::Fresnel(const Vector4 &v, const Vector4 &np, float eta) +{ + float const r0 = Math::Pow(1.0f - eta, 2.0f) / Math::Pow(1.0f + eta, 2.0f); + // Light vector and normal are assumed to be normalized. + return Types::Clamp (r0 + (1.0f - r0) * Math::Pow(1 - Types::Abs(v.Dot(np)), 5.0f), 0.0f, 1.0f); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Raytracer::ShadowFeel(const Vector4 &s, const Vector4 &d, float l, int r) +{ + float k_shadow = 1; + + if (configuration.trace_transparency) + { + if (!r) + return k_shadow; + + // Get closest hit. + Trace trace; + scene_shadow_tree.RaytraceScene(trace, s, d, l); + statistics.ray_count++; + statistics.tri_test += trace.tri_test; + + if (trace.has_i && (trace.i_t > 0)) + { + // Check opacity. + float opacity = SampleMaterialOpacity(trace); + + // Early exit on fully opaque hit. + if (opacity == 1) + return 0; + k_shadow = 1 - opacity; + + // Recurse. + Vector4 offset_pi = trace.s + trace.d * (trace.i_t + Units::Mm(1)); + k_shadow *= ShadowFeel(offset_pi, trace.d, l - Vector4::Dist(trace.s, offset_pi), --r); + } + } + else + { + // Any hit within range will do. + Trace trace(false); + scene_shadow_tree.RaytraceScene(trace, s, d, l); + + if (trace.has_i && (trace.i_t > 0)) + return 0; // Occluded. + } + + return k_shadow; +} +void Raytracer::ComputeRadiance(Trace &trace, Color &o, Bounce &bounce) +{ + bool use_fixed_function = trace.m->shader.IsEmpty(); + bool blend_additive = trace.m->blendop == Material::Blend_Add; + + // Evaluate material alpha. + float alpha; + if (use_fixed_function) + alpha = SampleMaterialOpacity(trace); + else alpha = SampleMaterialSink(trace, ShaderTree::SinkOpacity).x; + alpha *= trace.o->opacity; + + // Compute direct lighting, if the material does not care about the alpha test, or if the material cares about it and its alpha is up to the threshold. + if (!(trace.m->renderword & Material::Render_AlphaTest) || alpha > trace.m->athreshold) + { + // Evaluate material glossiness. + float glossiness; + if (use_fixed_function) + glossiness = trace.m->glossiness; + else glossiness = SampleMaterialSink(trace, ShaderTree::SinkGlossiness).x; + + // Evaluate light contribution. + Color l_diff(0, 0, 0), l_spec(0, 0, 0); + Vector4 offset_pi = trace.pi + trace.n * Units::Mm(1.f); + + for (uint n = 0; n < lgt.GetCount(); ++n) + if (S3D::MLight *l = lgt[n].l) + { + Core::Light *light = (Core::Light *)l; + float k_shadow = 1.f; + + if ((light->shadow != Core::Light::Shadow_None) && configuration.trace_shadow) + { + Vector4 d; + + switch (light->model) + { + default: + case Core::Light::Model_Point: + d = light->GetMatrix().GetRow(3) - offset_pi; + break; + + case Core::Light::Model_Linear: + d = light->GetMatrix().GetRow(2).Reversed() * light->clip_distance; + break; + } + + if (d.Dot(trace.n) > 0) + { + float l = d.Len(); + d /= l; + + k_shadow = ShadowFeel(offset_pi, d, l, configuration.trace_shadow_transparency_max_recursion); + if (!k_shadow) + continue; + } + } + + // Compute contribution. + float k_d, k_s; + if (light->SampleEnergy(trace.pi, trace.n, &k_d, &k_s, &trace.d, glossiness)) + { + l_diff += light->diffuse_color * light->diffuse_intensity * k_d * k_shadow; + l_spec += light->specular_color * light->specular_intensity * k_s * k_shadow; + } + } + + // Compute indirect lighting. + Color l_indirect(0, 0, 0), ambient(0, 0, 0); + + if (configuration.trace_gi && bounce.indirect) + { + bounce.indirect--; + + Spread &mc = monte_carlo[Random::Rand(32)]; + Matrix3 nm(Matrix3::FromOrthonormalBasis(trace.n)); + Color l; + + // divide by the number of bounce, to avoid full bounce each time. + int count_spread = mc.spread.GetCount(); + if (configuration.indirect_gi_bounce - bounce.indirect != 0) + count_spread /= configuration.indirect_gi_bounce - bounce.indirect + 1; + count_spread = Types::Max(count_spread, 1); + + for (int n = 0; n < count_spread; ++n) + { + Bounce ibounce; + + ibounce.indirect = bounce.indirect; + ibounce.reflection = 0; + ibounce.refraction = 0; + + Raytrace(RayGrid(offset_pi, mc.spread[n] * nm), l, ibounce); + l_indirect += l; + } + l_indirect /= (float)count_spread; + } + else + ambient = (configuration.gi_use_ambient || !configuration.trace_gi) ? scene->ambient_color * scene->ambient_intensity : Vector4(0.f, 0.f, 0.f); + + // Compute ambient occlusion. + float ambient_occlusion = 1.0f; + + if ((alpha >= 1.0f) && configuration.ao_activate) + { + Spread &mc = monte_carlo[Random::Rand(32)]; + Matrix3 nm(Matrix3::FromOrthonormalBasis(trace.n)); + + float countouch = 0.0f; + float lengthmax = configuration.ao_length; + float divlengthmaxsq = 1.0f / lengthmax; + + for (uint n = 0; n < mc.spread.GetCount(); ++n) + { + // Create the direction vector from the normal of the point with a bit of random. + Trace traceOcclusion; + Vector4 start(trace.pi + mc.spread[n] * nm * Units::Mm(1.f)); +/* + nVector DirVect(mc.spread[n] * nm); + scene_tree.RaytraceScene(traceOcclusion, start, DirVect, lengthmax); + + // check the raytrace pass if the alpha of the map and continue to raytrace then + float alphaOcclusion = 0.0f; + float current_length = 0.0f; + + while(alphaOcclusion < 1.0f && current_length < lengthmax && + traceOcclusion.has_i && (traceOcclusion.i_t > 0.0f)) + { + current_length += traceOcclusion.i_t; + + // Compute intersection point and fetch material. + traceOcclusion.pi = traceOcclusion.s + traceOcclusion.d * traceOcclusion.i_t; + traceOcclusion.m = traceOcclusion.g->material_table[traceOcclusion.g->pol[traceOcclusion.ip].material]; + + bool use_fixed_functionOcclusion = trace.m->shader_tree == NULL ? true : false; + + // Evaluate material alpha. + float TempAlphaOcclusion = 0.0f; + + if (use_fixed_functionOcclusion) + TempAlphaOcclusion = SampleMaterialOpacity(traceOcclusion); + else TempAlphaOcclusion = SampleMaterialSink(traceOcclusion, nShaderTree::SinkOpacity).x; + alphaOcclusion += TempAlphaOcclusion*traceOcclusion.o->opacity; + + if(alphaOcclusion < 1.0f && current_length < lengthmax) + scene_tree.RaytraceScene(traceOcclusion, traceOcclusion.pi + DirVect* Mm(1), DirVect, lengthmax - current_length); + } + + if(alphaOcclusion > 1.0f) + alphaOcclusion = 1.0f; + + if (alphaOcclusion > 0) + countouch += (1.0f - Types::Clamp(current_length * divlengthmaxsq, 0.0f, 1.0f))* alphaOcclusion; +*/ + scene_tree.RaytraceScene(traceOcclusion, start, mc.spread[n] * nm, lengthmax); + + if (traceOcclusion.has_i && (traceOcclusion.i_t > 0.0f)) + countouch += 1.0f - Types::Clamp(traceOcclusion.i_t * divlengthmaxsq, 0.0f, 1.0f); + } + + if (countouch > 0.0f) + ambient_occlusion = 1.0f - countouch / mc.spread.GetCount(); + ambient_occlusion = Types::Clamp(ambient_occlusion); + } + + // Sample attributes. + Color diffuse, specular, self; + + if (use_fixed_function) + { + // Gather attributes. + diffuse = SampleMaterialAttribute(trace, Channel_Diffuse); + specular = SampleMaterialAttribute(trace, Channel_Specular); + self = SampleMaterialAttribute(trace, Channel_SelfIllum); + + // Vertex color. + if (trace.m->GetChannelStage(Channel_Light)) + { + Color color = SampleMaterialAttribute(trace, Channel_Light); + diffuse *= color; + specular *= color; + } + else if (trace.m->renderword & Material::Render_VertexColor) + { + Color color = SampleGeometryAttribute(trace, GeometryVertexColor); + diffuse *= color; + specular *= color; + } + + // Environment mapping. + if (trace.m->GetChannelStage(Channel_Reflection)) + { + Color color = SampleMaterialAttribute(trace, Channel_Reflection); + switch (trace.m->GetChannelStage(Channel_Reflection)->op) + { + case Material::Operator_Multiply: + diffuse *= color; + break; + + case Material::Operator_Default: + case Material::Operator_Add: + diffuse += color; + break; + } + } + } + else + { + diffuse = SampleMaterialSink(trace, ShaderTree::SinkDiffuse); + specular = SampleMaterialSink(trace, ShaderTree::SinkSpecular); + self = SampleMaterialSink(trace, ShaderTree::SinkConstant); + } + + // Final color. + o = ((diffuse * (l_diff + l_indirect + ambient* ambient_occlusion)) + specular * l_spec + self) /** alpha*/; // Don't multiply the alpha, because there is real raytracing for the refraction after. + } + else + { + alpha = 0; + o.Set(0, 0, 0); + } + + // Apply fog. + if (scene->fog_far > 0) + { + float kfog = Types::Clamp((trace.td - scene->fog_near) / (scene->fog_far - scene->fog_near)); + o = o * (1.f - kfog) + scene->fog_color * kfog; + } + + // Trace reflected and transmitted rays as required. + float krefl = alpha; + + float eta = trace.m->irefraction; + if (trace.ir == trace.m->irefraction) + eta = 1.0f; + + if (((alpha < 1) || blend_additive) && bounce.refraction) + { + float n = trace.ir / eta; + + if (configuration.fresnel_activate) + krefl = Fresnel(trace.d, trace.n.FaceForward(trace.d), n); + + float c1 = -trace.n.FaceForward(trace.d).Dot(trace.d); + float w = n * Types::Abs(c1); + float c2 = Math::Sqrt(1 + (w - n) * (w + n)); + + Vector4 rtransmit = (trace.d * n) + trace.n.FaceForward(trace.d) * (w - c2); + rtransmit = rtransmit.Normalized(); + Vector4 offset_pi = trace.pi + rtransmit * Units::Mm(1.f); + + if (c2 < 0) + krefl = 1.0f; // Full reflection, we are inside the matter and by an angle where it is physically impossible (as Snell-Descartes law) to have refraction. + + if ((1.0f - krefl) > 0.0f) + { + bounce.refraction--; + + Color b; + float save_ir = trace.ir; + trace.ir = eta; + Raytrace(RayGrid(offset_pi, rtransmit), b, bounce, &trace); + trace.ir = save_ir; + + if (blend_additive) + o += b; + else o = o * krefl + b * (1 - krefl); + + bounce.refraction++; + } + } + + // Reflection. + float material_reflection = SampleMaterialSink(trace, ShaderTree::SinkReflection).x; + if (configuration.trace_reflection && material_reflection && bounce.reflection) + { + if (krefl > 0.0f) + { + bounce.reflection--; + + Vector4 nf = trace.n.FaceForward(trace.d).Normalized(); + float c1 = -nf.Dot(trace.d); + Vector4 rreflect = trace.d + (nf * 2.f * Types::Abs(c1)); + + Vector4 offset_pi = trace.pi + rreflect * Units::Mm(1.f) ; + + Color b; + float save_ir = trace.ir; + trace.ir = eta; + Raytrace(RayGrid(offset_pi, rreflect), b, bounce, &trace); + trace.ir = save_ir; + + o += b * (krefl * material_reflection); + + bounce.reflection++; + } + } + + // Note: Isn't doing this here getting rid of HDR informations? + o = o.Clamped(Vector4(0, 0, 0), Vector4(1, 1, 1)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Raytracer::PrimaryRay(const RayGrid &ray, Color &o) +{ + Bounce bounce; + bounce.indirect = configuration.indirect_gi_bounce; + bounce.reflection = configuration.trace_reflection_max_recursion; + bounce.refraction = configuration.trace_refraction_max_recursion; + Raytrace(ray, o, bounce); +} +void Raytracer::Raytrace(const RayGrid &ray, Color &o, Bounce &bounce, Trace *previous_trace) +{ + Trace trace; + + if (previous_trace) + { + trace.ir = previous_trace->ir; + trace.td = previous_trace->td; + } + + scene_tree.RaytraceScene(trace, ray.p[0], ray.d[0]); + statistics.ray_count++; + statistics.tri_test += trace.tri_test; + + // Shade result. + if (trace.has_i) + { + // Compute intersection point. + trace.pi = trace.s + trace.d * trace.i_t; + + // Compute intersection normal. + Vector4 normal_sink = SampleMaterialSink(trace, ShaderTree::SinkNormal); + trace.o->GetMatrix().ApplyRotation(&trace.n, &normal_sink); + trace.n.Normalize(); + if (trace.backface) + trace.n = trace.n.Reversed(); + + // Integrate the newly traveled distance. + trace.td += trace.i_t; + + // Gather radiance. + ComputeRadiance(trace, o, bounce); + } + else + o = scene->background_color; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Raytracer::Render(Picture &output, uint w, uint h) +{ + if (!w || !h) + return false; + + uint logical_h = h; + viewport.Set((float)w, (float)h); + + if (configuration.interlaced) + { + if (h & 1) + __ERR__(__LOG_E__ << "Interlaced frame height must be a multiple of 2.", false) + if (configuration.interlaced_trace_half_frame) + h /= 2; + } + + Camera *camera = scene->current_camera; + if (!camera) + return false; + + // Create destination picture. + output.AllocAs(w, h); + + // Allocate output hdr buffer. + Array hdr(w * h); + if (!hdr) + __ERR__(__LOG_E__<< "Failed to allocate floating point frame buffer.\n", false) + + // Reset statistics. + render_clock = scene->GetClock()->Getf(); + statistics.Reset(); + + // Progress structure. + Progress progress; + + progress.start_clock = Platform::Get().GetClock(); + progress.instance = this; + progress.progress = 0; + progress.buffer = hdr; + progress.w = 0; + progress.h = 0; + progress.done = false; + + // Create virtual screen. + Benchmark bench(true); + scene_tree.ResetStats(); + + Vector4 screen[4], wscreen[4]; + + float hw, hh, ar = ((camera->aspect_ratio == -1.f) ? 1.f : camera->aspect_ratio); + + if (camera->aspect_ratio_ref_yaxis) + { + hw = ((float)w / (float)logical_h) / ar; + hh = 1; + } + else + { + hw = 1; + hh = ((float)logical_h / ar) / (float)w; + } + + screen[0].Set(-hw, hh, camera->zoom_factor); + screen[1].Set(hw, hh, camera->zoom_factor); + screen[2].Set(hw, -hh, camera->zoom_factor); + screen[3].Set(-hw, -hh, camera->zoom_factor); + + camera->GetMatrix().Apply(wscreen, screen, 4); + + // Interpolate across world screen and trace. + Vector4 dt_l, pt_l, dt_r, pt_r; + + dt_l = (wscreen[3] - wscreen[0]) / (float)logical_h; + pt_l = wscreen[0]; + dt_r = (wscreen[2] - wscreen[1]) / (float)logical_h; + pt_r = wscreen[1]; + + // Interlace. + if (configuration.interlaced && configuration.interlaced_trace_half_frame) + { + if (!interlace_even) + { + pt_l += dt_l; + pt_r += dt_r; + } + dt_l *= 2.f; + dt_r *= 2.f; + } + + const Vector4 &s = camera->GetMatrix().GetRow(3); + + // Rendering. + abort = false; + progress.description = "Rendering (1/2)"; + + #define __JobTileSize 32 + + // Split rendering in tiles. + AutoList job_list; + ASync::JobGroup group; + + for (uint y = 0; y < h; y += __JobTileSize) + for (uint x = 0; x < w; x += __JobTileSize) + { + RaytraceJob *job = new RaytraceJob; + job_list.Add(job); + + job->core = this; + + job->start_height = y; + job->end_height = y + __JobTileSize < h ? y + __JobTileSize : h; + job->start_width = x; + job->end_width = x + __JobTileSize < w ? x + __JobTileSize : w; + + job->s = s; + job->dt_l = dt_l; job->pt_l = pt_l; + job->dt_r = dt_r; job->pt_r = pt_r; + + job->hdr = hdr; + job->pitch = w; + + Platform::Get().job_manager->EnqueueJob(job, &group); + } + + while (!Platform::Get().job_manager->JoinGroup(&group, false)) + if (hook) + { +// progress.progress = 1.f - (float)group.GetJobCount() / job_list.GetCount(); + hook->RaytracerProgress(progress); + } + + job_list.Clear(); +/* + // Split anti-aliasing in tiles. + progress.description = "Anti-aliasing (2/2)"; + + for (uint y = 1; y < (h - 1); y += __JobTileSize) + for (uint x = 1; x < (w - 1); x += __JobTileSize) + { + nAntialiasJob *job = new nAntialiasJob; + job_list.Add(job); + + job->core = this; + + job->start_height = y; + job->end_height = y + __JobTileSize < (h - 1) ? y + __JobTileSize : (h - 1); + job->start_width = x; + job->end_width = x + __JobTileSize < (w - 1) ? x + __JobTileSize : (w - 1); + + job->s = s; + job->dt_l = dt_l; job->pt_l = pt_l; + job->dt_r = dt_r; job->pt_r = pt_r; + + job->hdr = hdr; + job->pitch = w; + + Platform::Get().job_manager->EnqueueJob(job, &group); + } + + // Join anti-aliasing job group. + while (!Platform::Get().job_manager->JoinGroup(&group, false)) + if (hook) + { +// progress.progress = 1.f - (float)group.GetJobCount() / job_list.GetCount(); + hook->RaytracerProgress(progress); + } + + job_list.Clear(); +*/ + bench.Stop(); + __LOG__ << "Raytracing done. Took " << bench.GetMs() << " ms. Ray/s = " << (scene_tree.ray_count * 1000) / bench.GetMs() << "\n"; + + // HDR conversion to standard 32 bit RGBA. + #pragma omp parallel + { + #pragma omp for schedule(dynamic) nowait + for (uint v = 0; v < h; ++v) + { + uint *o_rgb = ((uint *)output.GetData()) + w * v; + Color *o_hdr = hdr + w * v; + + for (uint u = 0; u < w; ++u) + o_rgb[u] = + ((uint)(Types::Clamp(o_hdr[u].w) * 255) << 24) + + ((uint)(Types::Clamp(o_hdr[u].x) * 255) << 16) + + ((uint)(Types::Clamp(o_hdr[u].y) * 255) << 8) + + ((uint)(Types::Clamp(o_hdr[u].z) * 255)); + } + } +// ... + + // Backup current frame if interlaced and wait for the next half-frame. + if (configuration.interlaced) + { + if (interlace_half_frame.isValid()) + { + // If the frame is valid compose to output. + if ((interlace_half_frame.GetWidth() != w) || (interlace_half_frame.GetHeight() != h)) + __LOG_E__ << "Unexpected frame dimension change during interlaced sequence rendering.\n"; + + else + { + Picture half_frame(output); + + if (output.AllocAs(w, logical_h)) + { + // Select even and odd frames based on current parity. + Picture *even = interlace_even ? &half_frame : &interlace_half_frame, + *odd = interlace_even ? &interlace_half_frame : &half_frame; + + // Compose. + uint *p_even = (uint *)even->GetData(), + *p_odd = (uint *)odd->GetData(), + *p_output = (uint *)output.GetData(); + + if (configuration.interlaced_trace_half_frame) + for (uint v = 0; v < h; ++v) + { + Memory::Copy(p_output, p_even, w * 4); + p_even += w; + p_output += w; + + Memory::Copy(p_output, p_odd, w * 4); + p_odd += w; + p_output += w; + } + + else + { + if (interlace_even) + p_even += w; + else p_odd += w; + + for (uint v = 0; v < h; ++v) + { + Memory::Copy(p_output, p_even, w * 4); + p_even += w * 2; + p_output += w; + + Memory::Copy(p_output, p_odd, w * 4); + p_odd += w * 2; + p_output += w; + } + } + } + } + + // Drop buffer, it has been committed to output. + interlace_half_frame.Free(); + } + else + { + // Buffer the current output and drop it. No save is to be done yet. + interlace_half_frame.Clone(output); + output.Free(); + } + } + + // Done, switch interlace parity. + interlace_even = !interlace_even; + viewport.Set(1, 1); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Raytracer::StartInterlacedSequence() +{ + interlace_even = configuration.interlace_even; + interlace_half_frame.Free(); +} +void Raytracer::Abort() +{ abort = true; } +void Raytracer::SetConfiguration(const Configuration &config) +{ + configuration = config; + for (int n = 0; n < 32; ++n) + monte_carlo[n].Initialize(configuration.gi_sample, configuration.gi_sample, Units::Deg(configuration.ao_angle)); // 64 evaluations per ray. +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Raytracer::SetScene(const GS::S3D::Scene *s) +{ + if (!gf) + __ERR__(__LOG_E__ << "No graphic resource factory to set raytracer scene.\n", false) + + Free(); + + // Grab scene and shadow scene. + scene = s; + if (!scene_tree.SetScene(*gf, s) || !scene_shadow_tree.SetScene(*gf, s, true)) + return false; + + // Grab lights, reset caches. + SharedList lights; + s->GetItemListByType(lights); + + if (!lgt.Allocate(lights.GetCount())) + __ERR__(__LOG_E__ << "Failed to allocate raytracer light array.\n", false) + + uint lgt_count = 0; + ListForeachPtr(S3D::MLight *, l, lights) + { + lgt[lgt_count].l = l->isActive() ? l : NULL; + lgt[lgt_count].g = NULL; + lgt_count++; + } + return true; +} +void Raytracer::Free() +{ + scene_tree.Free(); + scene_shadow_tree.Free(); + + lgt.Free(); +} +//------------------------------------------------------------------------------ + +Raytracer::Raytracer(ResourceFactory *f) : gf(f) +{ + SetConfiguration(configuration); + viewport.Set(1, 1); + hook = NULL; +} diff --git a/include/modules/raytracer/raytracer_geometry.cpp b/include/modules/raytracer/raytracer_geometry.cpp new file mode 100644 index 0000000..6fc61ab --- /dev/null +++ b/include/modules/raytracer/raytracer_geometry.cpp @@ -0,0 +1,89 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "raytracer/raytracer_core.h" + #include "core/geometry.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +Vector4 Raytracer::SampleGeometryAttribute(const Trace &trace, GeometryAttribute attr) +{ + Vector4 sample; + + switch (attr) + { + case GeometryVertexColor: + if (trace.g->rgb) + sample = ( trace.g->rgb[trace.bi + 0] * trace.w + + trace.g->rgb[trace.bi + trace.it + 1] * trace.u + + trace.g->rgb[trace.bi + trace.it + 2] * trace.v ); + else + sample.Set(0.25f, 0.f, 0.f); + break; + + case GeometryNormal: + { + if ( + (trace.m->renderword & Material::Render_Smooth) || + (trace.m->renderword & Material::Render_NormalTangent) + ) + { + // Interpolated vertex normal. + sample = ( trace.g->vtx_normal[trace.bi + 0] * trace.w + + trace.g->vtx_normal[trace.bi + trace.it + 1] * trace.u + + trace.g->vtx_normal[trace.bi + trace.it + 2] * trace.v ).Normalized(); + + // Normal map support. + if (trace.m->GetChannelStage(Channel_Normal)) + { + if (trace.m->renderword & Material::Render_NormalTangent) + { + Vector4 T, B; + + if (trace.g->vtx_tangent) + { + // Interpolated tangent basis. + T = ( trace.g->vtx_tangent[trace.bi + 0].T * trace.w + + trace.g->vtx_tangent[trace.bi + trace.it + 1].T * trace.u + + trace.g->vtx_tangent[trace.bi + trace.it + 2].T * trace.v ).Normalized(); + B = ( trace.g->vtx_tangent[trace.bi + 0].B * trace.w + + trace.g->vtx_tangent[trace.bi + trace.it + 1].B * trace.u + + trace.g->vtx_tangent[trace.bi + trace.it + 2].B * trace.v ).Normalized(); + } + else + { + T.Set(1, 0, 0); + B.Set(0, 1, 0); + } + + // Build tangent frame. + Matrix3 tangent_matrix(T, B, sample); + Vector4 normal_sample(SampleMaterialAttribute(trace, Channel_Normal)), + tangent_normal(normal_sample.x * 2 - 1, normal_sample.y * 2 - 1, normal_sample.z * 2 - 1); + + sample = tangent_normal * tangent_matrix; + } + else + { + // World space. + Vector4 normal_sample(SampleMaterialAttribute(trace, Channel_Normal)), + tangent_normal(normal_sample.x * 2 - 1, normal_sample.z * 2 - 1, normal_sample.y * 2 - 1); + sample = tangent_normal; + } + } + } + else + sample = trace.g->pol_normal[trace.ip]; + } + break; + } + return sample; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/raytracer/raytracer_job.cpp b/include/modules/raytracer/raytracer_job.cpp new file mode 100644 index 0000000..1e1f91b --- /dev/null +++ b/include/modules/raytracer/raytracer_job.cpp @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "raytracer/raytracer_job.h" + #include "core/geometry.h" + #include "rand/rand.h" + + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +void RaytraceJob::Execute(uint) +{ + Vector4 pt_s = pt_l + dt_l * (float)start_height; + + for (int v = start_height; v < end_height; ++v) + { + Vector4 dt_s = ((pt_r + dt_r * (float)start_height) - (pt_l + dt_l * (float)start_height)) / (float)pitch; + for (int u = start_width; u < end_width; ++u) + { + Vector4 d = (pt_s + dt_s * (float)u - s).Normalized(); + core->PrimaryRay(RayGrid(s, d), hdr[v * pitch + u]); + } + pt_s += dt_l; + } +} +void AntialiasJob::Execute(uint) +{ + Configuration &config = core->GetConfiguration(); + + float aa_v_k = config.interlaced_trace_half_frame ? 0.5f : 1.f, + aa_threshold = config.aa_threshold, + aa_jitter = config.aa_jitter; + + int aa_sample = config.aa_sample; + + // When rendering half frame halve the AA kernel vertically. + for (int v = start_height; v < end_height; ++v) + for (int u = start_width; u < end_width; ++u) + { + Color *o_hdr = &hdr[v * pitch + u]; + + // Check threshold. + if ( + (Vector4::Dist2(o_hdr[0], o_hdr[-1]) < aa_threshold) && + (Vector4::Dist2(o_hdr[0], o_hdr[-pitch]) < aa_threshold) && + (Vector4::Dist2(o_hdr[0], o_hdr[1]) < aa_threshold) && + (Vector4::Dist2(o_hdr[0], o_hdr[pitch]) < aa_threshold) + ) + continue; + + // Multi-sample. + o_hdr[0].Set(0, 0, 0); + + for (int ms_v = 0; ms_v < aa_sample; ++ms_v) + { + // TODO pre-calculate jittered/non-jittered grids. + float ms_v_o = v + ((float)ms_v * aa_v_k) / aa_sample + (aa_jitter ? Random::FRand(0.125f / aa_sample) : 0); + + Vector4 dt_s = ((pt_r + dt_r * ms_v_o) - (pt_l + dt_l * ms_v_o)) / (float)pitch, + pt_s = pt_l + dt_l * ms_v_o; + + for (int ms_u = 0; ms_u < aa_sample; ++ms_u) + { + float ms_u_o = u + (float)ms_u / aa_sample + (aa_jitter ? Random::FRand(0.125f / aa_sample) : 0); + Vector4 d = (pt_s + dt_s * ms_u_o - s).Normalized(); + + Color out; + core->PrimaryRay(RayGrid(s, d), out); + o_hdr[0] += out.Clamped(0, 1); + } + } + o_hdr[0] /= (float)(aa_sample * aa_sample); + } +} +//------------------------------------------------------------------------------ diff --git a/include/modules/raytracer/raytracer_material.cpp b/include/modules/raytracer/raytracer_material.cpp new file mode 100644 index 0000000..497bb22 --- /dev/null +++ b/include/modules/raytracer/raytracer_material.cpp @@ -0,0 +1,181 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "raytracer/raytracer_core.h" + #include "core/camera.h" + #include "core/geometry.h" + #include "core/shader_block.h" + #include "scene3d/scene.h" + + using namespace GS::Core; + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +GS::Vector4 Raytracer::SampleMaterialSink(const Trace &trace, ShaderTree::ShaderSinkType sink) +{ + if (trace.st) + { + // Evaluate sink. + if (ShaderBlock *block = trace.st->sink[sink]) + { + ShaderBlockValue block_out; + if (EvaluateShaderBlock(trace, block, block_out)) + return block_out.v; + } + + // Default values. + switch (sink) + { + case ShaderTree::SinkNormal: return Vector4(0, 0, 1); + case ShaderTree::SinkDiffuse: return trace.m->diffuse; + case ShaderTree::SinkModulate: return Vector4(1, 1, 1); + case ShaderTree::SinkSpecular: return trace.m->specular; + case ShaderTree::SinkGlossiness: return Vector4(trace.m->glossiness, 0, 0); + case ShaderTree::SinkConstant: return Vector4(0, 0, 0); + case ShaderTree::SinkOpacity: return Vector4(1, 0, 0); + case ShaderTree::SinkReflection: return Vector4(trace.m->reflection, 0, 0); + } + } + return Vector4(1, 0, 0, 1); +} +GS::Vector4 Raytracer::SampleMaterialAttribute(const Trace &trace, MaterialChannel channel) +{ + Color sample(1, 1, 1); + if (!trace.m) + return sample; + + Material::TextureStage *stage = trace.m->GetChannelStage(channel); + + /* + Texture sampling. + @TODO This is insanely slow. + */ + if (stage && trace.g) + { + float sample_uv_u = 0, sample_uv_v = 0; + + switch (stage->uv_mode) + { + case Material::UV_SphericalEnvironment: + { + Vector4 w; + scene->current_camera->GetInverseMatrix().ApplyRotation(&w, &trace.n); + + // Find the Euler vector from the reflection normal. + Vector4 euler_vec = trace.d - (w * 2.0f * fabs((w*-1.0f).Dot(trace.d))); + euler_vec.Normalize(); + + // Euler to UV coordinate. +// float Y = (1.0f - euler_vec.y) * 0.5f; + + Vector4 XZ(euler_vec.x, euler_vec.z, 0.0); + XZ.Normalize(); + float DotX = /*nVector(1.0f, 0.0f, 0.0f).Dot(XZ)*/XZ.x; + + // Set from -1;1 to 0;1. + DotX = (1.0f - DotX) * 0.5f; + + float DotY = /*nVector(0.0f, 1.0f, 0.0f).Dot(XZ)*/XZ.y; + // Set -1 or 1. + DotY = (DotY >= 0 ? 1.0f :-1.0f); + + float value_angle = DotX * DotY; + // Set from -1;1 to 0;1. + value_angle = (1.0f - value_angle) * 0.5f; + + sample_uv_u = DotX; + sample_uv_v = value_angle; + } + break; + + case Material::UV_LSN: + { + // Derive UV coordinates from intersection normal. + Vector4 w; + scene->current_camera->GetInverseMatrix().ApplyRotation(&w, &trace.n); + + sample_uv_u = w.x * 0.5f + 0.5f; + sample_uv_v = w.y * 0.5f + 0.5f; + } + break; + + case Material::UV_FrontMap: + { + // Derive UV coordinated from view item projection matrix. + Vector4 s; + scene->current_camera->WorldToScreen(fRect(0, 0, viewport.x, viewport.y), trace.pi, s, false); + + float k_ar = viewport.y / viewport.x; + sample_uv_u = (s.x - 0.5f) * k_ar + 0.5f; + sample_uv_v = s.y; + } + break; + + case Material::UV_UV: + // Compute UV from geometry topology. + if (Vector2 *uv = (stage->uv_index < __UV_PER_GEOMETRY__) ? &trace.g->uv[stage->uv_index][0] : NULL) + { + Vector2 &uv0 = uv[trace.bi], &uv1 = uv[trace.bi + trace.it + 1], &uv2 = uv[trace.bi + trace.it + 2]; + sample_uv_u = trace.w * uv0.x + trace.u * uv1.x + trace.v * uv2.x, + sample_uv_v = trace.w * uv0.y + trace.u * uv1.y + trace.v * uv2.y; + } + break; + } + + // UV matrix. + Vector4 sample_uv = Vector4(sample_uv_u, sample_uv_v, 0.0) * stage->uv_matrix; + + // Handle wrapping. +/* + if (stage->wrap_u) + { + if (sample_uv.x < 0) + sample_uv.x = sample_uv.x - (int)sample_uv.x + 1; + else sample_uv.x = sample_uv.x - (int)sample_uv.x; + } + if (stage->wrap_v) + { + if (sample_uv.y < 0) + sample_uv.y = sample_uv.y - (int)sample_uv.y + 1; + else sample_uv.y = sample_uv.y - (int)sample_uv.y; + } +*/ + // FIXME performance bottleneck! + if (Picture *p = gf->LoadPicture(stage->t)) + p->SampleRGBA(sample_uv.x, sample_uv.y, sample); + } + else + switch (channel) + { + case Channel_Diffuse: + sample *= trace.m->diffuse; + break; + case Channel_Specular: + sample *= trace.m->specular; + break; + case Channel_SelfIllum: + sample *= trace.m->self; + break; + + default: break; + } + + return sample; +} +float Raytracer::SampleMaterialOpacity(const Trace &trace) +{ + float opacity = 1.f; + + if (trace.m->GetChannelStage(Channel_Opacity)) + { + Vector4 sample = SampleMaterialAttribute(trace, Channel_Opacity); + opacity = sample.w; + } + return opacity * trace.m->opacity; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/raytracer/raytracer_scene.cpp b/include/modules/raytracer/raytracer_scene.cpp new file mode 100644 index 0000000..7721db7 --- /dev/null +++ b/include/modules/raytracer/raytracer_scene.cpp @@ -0,0 +1,275 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "raytracer/raytracer_scene.h" + #include "scene3d/mobject.h" + #include "scene3d/mlight.h" + #include "scene3d/scene.h" + #include "scene3d/instance.h" + #include "scene3d/group.h" + #include "core/geometry_bih.h" + #include "metafile/nml_object.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +void SceneBIH::ResetStats() +{ + ray_count = 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SceneBIH::TraceLeaf(BIH::Node *leaf, float tmin, float tmax, BIH::Trace &trace, void *parm) +{ + Vector4 &s = trace.s, &d = trace.d; + Trace *s_trace = (Trace *)parm; + uint *leaf_indice = (uint *)leaf->p; + + for (uint n = 0; n < leaf->count; ++n) + { + Core::Object *o = obj[leaf_indice[n]].o; + IGeometryTree *tree = obj[leaf_indice[n]].tree; + + // Raytrace object in local space. + Vector4 local_s = s * o->GetInverseMatrix(), local_d; + o->GetInverseMatrix().ApplyRotation(&local_d, &d); + + GeometryTrace geo_trace; + tree->RaytraceGeometry(geo_trace, local_s, local_d, tmax); + + if (!geo_trace.has_i) + continue; + + // Integrate result. + if (!s_trace->has_i || (geo_trace.i_t < s_trace->i_t)) + { + /* + Note: Do not copy the complete geo_trace, we do not want + to duplicate trace stacks. + */ + *((GeometryTraceBase *)s_trace) = ((GeometryTraceBase &)geo_trace); + + s_trace->has_i = true; + + s_trace->o = o; + s_trace->tri_test += geo_trace.tri_test; + } + } +} +void SceneBIH::RaytraceScene(Trace &trace, const Vector4 &s, const Vector4 &d, float l) +{ + ray_count++; + + trace.s = s; + trace.d = d; + + BIH::Trace bih_trace; + Tree::Raytrace(bih_trace, s, d, l, (void *)&trace); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Geometry *SceneBIH::TranslateGeometry(Geometry *g) const +{ + if (obj && g) + for (uint n = 0; n < obj.GetCount(); ++n) + if (obj[n].g == g) + return obj[n].og; + return g; +} +void SceneBIH::AddObject(ResourceFactory &gf, S3D::MObject *o, uint &obj_count, MinMax *varray, bool shadow) +{ + if (!o->isActive()) + return; + if (o->geometry.IsEmpty() || !o->GetBaseItem()->opacity) + return; + if (o->mitem_flags.IsSet(S3D::MItem::Flag_IsHelper | S3D::MItem::Flag_EditorHidden | S3D::MItem::Flag_EditorLocked)) + return; + + // Grab object geometry. + Geometry *g = gf.LoadGeometry(o->geometry); + if (!g) + return; + + obj[obj_count].og = g; // Store original geometry to map back from skinned geometry. + if (!g->material_table.GetCount() || !g->pol.GetCount()) + return; + + if (shadow) + { + if (g->flag.IsSet(Geometry::FlagNullShadowProxy)) + return; + if (!g->shadow_proxy.IsEmpty()) + g = gf.LoadGeometry(g->shadow_proxy); + } + + // Perform skinning. + if (o->HasSkin() && g->skin) + { + Skin *skin = o->GetSkin(); + + // Serialize geometry. + using namespace NML; + + File file; + file.AddRoot(g->AsMetaTag()); + + Geometry *sg = new Geometry; + LoadFromFile(*sg, file); + + // Build required structures upfront. + sg->ComputeVertexNormal(); + sg->ComputeVertexTangent(); + + // Vertex skinning. + for (uint n = 0; n < sg->vtx.GetCount(); ++n) + { + Vector4 v(0, 0, 0); + for (int b = 0; b < 4; ++b) + { + if (!sg->skin[n].w[b]) + break; + v += (sg->vtx[n] * skin->bones_mtx[sg->skin[n].bone_index[b]]) * sg->skin[n].w[b]; + } + sg->vtx[n] = v; + } + + // Normal skinning. + Vector4 s, w; + int tt = 0; + for (uint p = 0; p < sg->pol.GetCount(); ++p) + for (uint n = 0; n < sg->pol[p].vtx_count; ++n) + { + s.Set(0, 0, 0); + for (int b = 0; b < 4; ++b) + { + int i = sg->pol[p].binding[n]; + if (!sg->skin[i].w[b]) + break; + skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_normal[tt]); + s += w * sg->skin[i].w[b]; + } + sg->vtx_normal[tt++] = s; + } + + // Tangent base skinning. + Vector4 _b, _t; + tt = 0; + for (uint p = 0; p < sg->pol.GetCount(); ++p) + for (uint n = 0; n < sg->pol[p].vtx_count; ++n) + { + _b.Set(0, 0, 0); + _t.Set(0, 0, 0); + for (int b = 0; b < 4; ++b) + { + int i = sg->pol[p].binding[n]; + if (!sg->skin[i].w[b]) + break; + + skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_tangent[tt].B); + _b += w * sg->skin[i].w[b]; + skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_tangent[tt].T); + _t += w * sg->skin[i].w[b]; + } + sg->vtx_tangent[tt].B = _b; + sg->vtx_tangent[tt].T = _t; + tt++; + } + + // Use as the base geometry. + // but first copy the material from the base material + sg->material_table.Allocate(g->material_table.GetCount()); + for (uint k = 0; k < g->material_table.GetCount(); ++k) + sg->material_table[k] = g->material_table[k]; + + g = sg; + } + + // Prepare geometry. + IGeometryTree *tree = new GeometryBIHTree; + tree->BuildFromGeometry(gf, g); + + // Build minmax for the transformed geometry. + varray[obj_count] = g->ComputeMinMax(&o->GetMatrix()); + + obj[obj_count].g = g; + obj[obj_count].tree = tree; + obj[obj_count++].o = o; +} +bool SceneBIH::SetScene(ResourceFactory &gf, const S3D::Scene *s, bool shadow) +{ + Free(); + + using namespace S3D; + + SharedList objects; + s->GetItemListByType(objects); + SharedList instances; + s->GetItemListByType(instances); + + // Grab the scene content. + uint obj_count = 0; + ListForeachPtr(MObject *, o, objects) + if (!o->geometry.IsEmpty()) + obj_count++; + + // Count the instance objects. + ListForeachPtr(Instance *, i, instances) + { + if (!i->instance_scene) + { + if (!(i->instance_scene = new Scene(s->GetVM()))) + continue; + + i->instance_scene->FromMetaFileStoreGroup(i->template_path, &i->instance_group, SceneIOObject | SceneIOLight); + if (i->instance_group != NULL) + i->instance_group->SetRootItem(i); + } + + if (i->instance_group) + ListForeachPtr(MItem *, ig, i->instance_group->GetItemList()) + if (ig->GetItemType() == Type_Object && !((MObject *)ig)->geometry.IsEmpty()) + obj_count++; + } + + if (!obj_count) + return true; + + if (!obj.Allocate(obj_count)) + __ERR__(__LOG_E__ << "Failed to grab scene to raytracer.\n", false) + + // Build scene tree and object trees. + Array varray(obj_count); + if (!varray) + __ERR__(__LOG_E__ << "Failed to allocate volume array to build scene tree.\n", false) + + obj_count = 0; + + ListForeachPtr(MObject *, o, objects) + AddObject(gf, o, obj_count, varray, shadow); + + // Add the instance objects. + ListForeachPtr(Instance *, i, instances) + if (i->instance_group) + ListForeachPtr(MItem *, ig, i->instance_group->GetItemList()) + if (ig->GetItemType() == Type_Object && !((MObject *)ig)->geometry.IsEmpty()) + AddObject(gf, ((MObject *)ig), obj_count, varray, shadow); + + // Build tree. + if (!Build(obj_count, varray)) + return false; + return true; +} +void SceneBIH::Free() +{ + obj.Free(); + Tree::Free(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/raytracer/raytracer_spread.cpp b/include/modules/raytracer/raytracer_spread.cpp new file mode 100644 index 0000000..ddefbb2 --- /dev/null +++ b/include/modules/raytracer/raytracer_spread.cpp @@ -0,0 +1,51 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "raytracer/raytracer_spread.h" + #include "math/matrix3.h" + #include "rand/rand.h" + #include "memory/memory.h" + #include "log/log.h" + + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +bool Spread::Initialize(uint u_count, uint v_count, float max_spread) +{ + Free(); + + if (!spread.Allocate(u_count * v_count)) + __ERR__(__LOG_E__ << "failed to allocate vector spread.\n", false) + + float s_v = max_spread / (v_count + 2), a_v = s_v; + + uint count = 0; + for (uint v = 0; v < v_count; ++v) + { + float strat_v = a_v + Random::FRand(s_v); // Stratified sampling. + + float s_u = Units::Deg(360.f) / u_count, a_u = Units::Deg(0.f); + for (uint u = 0; u < u_count; ++u) + { + float strat_u = a_u + Random::FRand(s_u); // Stratified sampling. + + Vector4 tmp(sin(strat_v), 0, cos(strat_v)); + Matrix3 rtz(Matrix3::RotationMatrixZAxis(strat_u)); + rtz.Apply(&spread[count++], &tmp); + + a_u += s_u; + } + a_v += s_v; + } + return true; +} +void Spread::Free() +{ + spread.Free(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/raytracer/shader_tree_cpu.cpp b/include/modules/raytracer/shader_tree_cpu.cpp new file mode 100644 index 0000000..6160d7a --- /dev/null +++ b/include/modules/raytracer/shader_tree_cpu.cpp @@ -0,0 +1,296 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "raytracer/raytracer_core.h" + #include "core/shader_block.h" + #include "core/geometry.h" + #include "core/object.h" + + using namespace GS::Core; + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +bool Raytracer::EvaluateShaderBlock(const Trace &trace, const ShaderBlock *block, ShaderBlockValue &out) +{ + ShaderBlockValue in[4]; // No more than 4 inputs supported. + + // Validity check. + if (!block) + return true; + + // Evaluate inputs. + for (uint n = 0; n < block->GetInputCount(); ++n) + if (!EvaluateShaderBlock(trace, block->GetInput(n), in[n])) + return false; + + // Evaluate block. + switch (block->type) + { + case ShaderBlock::TypeGeometryVertex: + out.Set(trace.pi * trace.o->GetInverseMatrix()); + break; + + case ShaderBlock::TypeGeometryNormal: + if (Vector4 *nrm = trace.g->vtx_normal) + { + Vector4 &nm0 = nrm[trace.bi], + &nm1 = nrm[trace.bi + trace.it + 1], + &nm2 = nrm[trace.bi + trace.it + 2]; + + out.Set(nm0 * trace.w + nm1 * trace.u + nm2 * trace.v); + } + break; + + case ShaderBlock::TypeGeometryVertexColor: + if (Vector4 *rgb = trace.g->rgb) + { + Vector4 &cl0 = rgb[trace.bi], + &cl1 = rgb[trace.bi + trace.it + 1], + &cl2 = rgb[trace.bi + trace.it + 2]; + + out.Set(cl0 * trace.w + cl1 * trace.u + cl2 * trace.v); + } + break; + + case ShaderBlock::TypeGeometryUV: + { + GeometryUVShaderBlock *b = (GeometryUVShaderBlock *)block; + + if (Vector2 *uv = trace.g->uv[b->channel]) + { + Vector2 &uv0 = uv[trace.bi], + &uv1 = uv[trace.bi + trace.it + 1], + &uv2 = uv[trace.bi + trace.it + 2]; + + out.Set(Vector4(trace.w * uv0.x + trace.u * uv1.x + trace.v * uv2.x, trace.w * uv0.y + trace.u * uv1.y + trace.v * uv2.y, 0, 0)); + } + } + break; + + case ShaderBlock::TypeGeometrySkinning: + break; + case ShaderBlock::TypeGeometryTangentFrame: + { + Vector4 sample = ( trace.g->vtx_normal[trace.bi] * trace.w + + trace.g->vtx_normal[trace.bi + trace.it + 1] * trace.u + + trace.g->vtx_normal[trace.bi + trace.it + 2] * trace.v ).Normalized(); + + Vector4 T, B; + + if (trace.g->vtx_tangent) + { + // Interpolated tangent basis. + T = (trace.g->vtx_tangent[trace.bi + 0].T * trace.w + + trace.g->vtx_tangent[trace.bi + trace.it + 1].T * trace.u + + trace.g->vtx_tangent[trace.bi + trace.it + 2].T * trace.v ).Normalized(); + B = (trace.g->vtx_tangent[trace.bi + 0].B * trace.w + + trace.g->vtx_tangent[trace.bi + trace.it + 1].B * trace.u + + trace.g->vtx_tangent[trace.bi + trace.it + 2].B * trace.v ).Normalized(); + } + else + { + T.Set(1, 0, 0); + B.Set(0, 1, 0); + } + + // Build tangent frame. + Matrix3 tangent_matrix(T, B, sample); + out.Set(tangent_matrix); + } + break; + + case ShaderBlock::TypeTexture: + out.Set(((TextureShaderBlock *)block)->texture); + break; + + case ShaderBlock::TypeTextureSampler: + { + if (in[0].t) + { + Color sample; + if (Picture *p = gf->LoadPicture(in[0].t)) + p->SampleRGBA(in[1].v.x < 0 ? 1 + fmodf(in[1].v.x, 1) : fmodf(in[1].v.x, 1), in[1].v.y < 0 ? 1 + fmodf(in[1].v.y, 1) : fmodf(in[1].v.y, 1), sample); + out.Set(sample); + } + else + out.Set(Vector4(0, 0, 0)); + } + break; + + case ShaderBlock::TypeConstant: + { + ConstantShaderBlock *b = (ConstantShaderBlock *)block; + out.Set(Vector4(b->constant[0], b->constant[1], b->constant[2], b->constant[3])); + } + break; + + case ShaderBlock::TypeColor: + { + ColorShaderBlock *b = (ColorShaderBlock *)block; + out.Set(b->color); + } + break; + + case ShaderBlock::TypeMaterialParam: + { + MaterialParamShaderBlock *b = (MaterialParamShaderBlock *)block; + switch (b->param) + { + case MaterialParamShaderBlock::MaterialAmbient: + out.Set(trace.m->ambient); + break; + case MaterialParamShaderBlock::MaterialDiffuse: + out.Set(trace.m->diffuse); + break; + case MaterialParamShaderBlock::MaterialSpecular: + out.Set(trace.m->specular); + break; + case MaterialParamShaderBlock::MaterialSelf: + out.Set(trace.m->self); + break; + case MaterialParamShaderBlock::MaterialGlossiness: + out.Set(trace.m->glossiness); + break; + case MaterialParamShaderBlock::MaterialOpacity: + out.Set(trace.m->opacity); + break; + case MaterialParamShaderBlock::MaterialReflection: + out.Set(trace.m->reflection); + break; + } + } + break; + + case ShaderBlock::TypeScreenUV: + out.Set(Vector4(0.5f,0.5f,0.5f)); + break; + case ShaderBlock::TypeViewVector: + out.Set(trace.d); + break; + + case ShaderBlock::TypeNormalViewMatrix: + out.Set(Matrix3::FromOrthonormalBasis(trace.d).Transposed() * trace.o->GetRotationMatrix()); + break; + case ShaderBlock::TypeNormalMatrix: + out.Set(trace.o->GetRotationMatrix()); + break; + case ShaderBlock::TypeModelViewMatrix: + { + Matrix4 view_matrix = Matrix4::FromMatrix3(Matrix3::FromOrthonormalBasis(trace.d).Transposed()); + view_matrix.SetRow(3, trace.s.Reversed()); + out.Set(view_matrix * trace.o->GetMatrix()); + } + break; + case ShaderBlock::TypeModelMatrix: + out.Set(trace.o->GetMatrix()); + break; + + case ShaderBlock::TypeMix: out.Set(in[0].v * in[2].v.x + in[1].v * (1 - in[2].v.x)); break; + case ShaderBlock::TypeAdd: out.Set(in[0].v + in[1].v); break; + case ShaderBlock::TypeMul: + { + if (in[0].type == in[1].type) + switch (in[0].type) + { + case ShaderBlockValue::BlockValueVector: out.Set(in[0].v * in[1].v); break; + case ShaderBlockValue::BlockValueMatrix3: out.Set(in[0].m3 * in[1].m3); break; + case ShaderBlockValue::BlockValueMatrix4: out.Set(in[0].m4 * in[1].m4); break; + } + else + { + ShaderBlockValue *_a = &in[0], *_b = &in[1]; + if (_b->type < _a->type) + { ShaderBlockValue *tmp = _a; _a = _b; _b = tmp; } + + if (_a->type == ShaderBlockValue::BlockValueVector) + { + if (_b->type == ShaderBlockValue::BlockValueMatrix3) + out.Set(_a->v * _b->m3); + else if (_b->type == ShaderBlockValue::BlockValueMatrix4) + out.Set(_a->v * _b->m4); + } + } + } + break; + + case ShaderBlock::TypeSub: out.Set(in[0].v - in[1].v); break; + case ShaderBlock::TypeDiv: out.Set(in[0].v / in[1].v); break; + + case ShaderBlock::TypeDot: out.Set(in[0].v.Dot(in[1].v)); break; + case ShaderBlock::TypeCross: out.Set(in[0].v.Cross(in[1].v)); break; + + case ShaderBlock::TypeClamp: + out.Set(Vector4( + Types::Clamp(in[0].v.x, in[1].v.x, in[2].v.x), + Types::Clamp(in[0].v.y, in[1].v.y, in[2].v.y), + Types::Clamp(in[0].v.z, in[1].v.z, in[2].v.z), + Types::Clamp(in[0].v.w, in[1].v.w, in[2].v.w) ) ); + break; + + case ShaderBlock::TypeNormalize: out.Set(in[0].v.Normalized()); break; + + case ShaderBlock::TypeSwizzle: + { + SwizzleShaderBlock *b = (SwizzleShaderBlock *)block; + + Vector4 v(0, 0, 0); + for (int n = 0; n < 4; ++n) + if (b->swizzle[n] != SwizzleShaderBlock::SwizzleNone) + v[n] = in[0].v[b->swizzle[n] - SwizzleShaderBlock::SwizzleX]; + + out.Set(v); + } + break; + + case ShaderBlock::TypeBuild: + { + BuildShaderBlock *b = (BuildShaderBlock *)block; + + Vector4 v(0, 0, 0); + for (int n = 0; n < 4; ++n) + { + if (b->build[n] == BuildShaderBlock::BuildOne) + v[n] = 1; + else if (b->build[n] == BuildShaderBlock::BuildZero) + v[n] = 0; + else v[n] = in[n].v[b->build[n] - BuildShaderBlock::BuildX]; + } + + out.Set(v); + } + break; + + case ShaderBlock::TypeSin: out.Set(sin(in[0].v.x)); break; + case ShaderBlock::TypeCos: out.Set(cos(in[0].v.x)); break; + + case ShaderBlock::TypeUnpackColorToVector: + out.Set((in[0].v - Vector4(0.5, 0.5, 0.0)) * Vector4(2.0, 2.0, 1.0)); + break; + case ShaderBlock::TypePackVectorToColor: + out.Set((in[0].v + Vector4(1.0, 1.0, 0.0)) * Vector4(0.5, 0.5, 1.0)); + break; + + case ShaderBlock::TypeClock: + out.Set(render_clock); + break; + + case ShaderBlock::TypePow: + out.Set(float(pow(in[0].v.x, in[1].v.x))); + break; + + case ShaderBlock::TypeAbs: + if (in[0].type == ShaderBlockValue::BlockValueVector) + { + Vector4 o = in[0].v.Abs(); + out.Set(Vector4(o.x, o.y, o.z)); + } + break; + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/cobject/cobject.cpp b/include/modules/script_squirrel/cobject/cobject.cpp new file mode 100644 index 0000000..65a30de --- /dev/null +++ b/include/modules/script_squirrel/cobject/cobject.cpp @@ -0,0 +1,103 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/cobject/cobject.h" + #include "script_squirrel/engine_vm.h" + #include "raytracer/raytracer_core.h" + #include "automation/automation_source_group.h" + #include "scene3d/scene.h" + #include "scene3d/group.h" + #include "scene3d/memitter.h" + #include "scene3d/mcamera.h" + #include "scene3d/mobject.h" + #include "scene3d/mtrigger.h" + #include "scene3d/mlight.h" + #include "scene3d/instance.h" + #include "ui/ui_cursor.h" + #include "core/raster_font.h" + #include "input/input_device.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void CObject::Initialize(CObjectType t, void *o, bool m) +{ + Release(); + + type = t; + native = o; + managed = m; + + if (native) + switch (type) + { + case typetag_Picture: ((Picture *)native)->AddRef(); break; + case typetag_Texture: ((Render::Texture *)native)->AddRef(); break; + case typetag_Geometry: ((Render::Geometry *)native)->AddRef(); break; + case typetag_Material: ((Render::Material *)native)->AddRef(); break; + case typetag_InputDevice: ((Input::Device *)native)->AddRef(); break; + case typetag_AutomationSource: ((Automation::Source *)native)->AddRef(); break; + + default: break; + } +} +void CObject::Release() +{ + if (native == NULL) + return; + + switch (type) + { + case typetag_Picture: ((Picture *)native)->RemoveRef(); break; + case typetag_Texture: ((Render::Texture *)native)->RemoveRef(); break; + case typetag_Geometry: ((Render::Geometry *)native)->RemoveRef(); break; + case typetag_Material: ((Render::Material *)native)->RemoveRef(); break; + case typetag_InputDevice: ((Input::Device *)native)->RemoveRef(); break; + case typetag_AutomationSource: ((Automation::Source *)native)->RemoveRef(); break; + + default: break; + } + + if (managed) + switch (type) + { + case typetag_Metafile: delete ((NML::File *)native); break; + case typetag_Raytracer: delete ((Raytrace::Raytracer *)native); break; + case typetag_RasterFont: delete ((Render::RasterFont *)native); break; + case typetag_AutomationSourceGroup: delete ((Automation::SourceGroup *)native); break; + case typetag_Group: delete ((S3D::Group *)native); break; + case typetag_Scene3d: delete ((S3D::Scene *)native); break; + case typetag_UICursor: delete ((S2D::Cursor *)native); break; + + default: + __LOG_E__ << "Type " << CObjectTypeToString(type) << " should not be managed by the VM.\n"; + break; + } + + native = NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +CObject::CObject(EngineVM *v, CObjectType t, void *o, bool managed) : vm(v) +{ + list_item = vm->cobjects.Add(this); + + native = NULL; + Initialize(t, o, managed); +} +CObject::~CObject() +{ + if (list_item) + { + vm->cobjects.Remove(list_item); +// g_flog << "Native object alive count: " << vm->cobjects.GetCount() << "\n"; + } + Release(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/cobject/cobject_impl.cpp b/include/modules/script_squirrel/cobject/cobject_impl.cpp new file mode 100644 index 0000000..811d941 --- /dev/null +++ b/include/modules/script_squirrel/cobject/cobject_impl.cpp @@ -0,0 +1,154 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/cobject/cobject_decl.h" + #include "script_squirrel/cobject/cobject.h" + #include "script_squirrel/squirrel_vm.h" + #include "log/log.h" + + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +bool CObject::GetBase(HSQUIRRELVM vm, int idx, void **o, CObjectType *types) +{ + // get object type + CObjectType type; + if (!GetType(vm, idx, type)) + return false; + + // cast to target type if compatible + for (int n = 0; types[n] != typetag_Undefined; ++n) + if (type == types[n]) + return Get(vm, idx, (void **)o); + + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static SQInteger CObject_release_hook(SQUserPointer p, SQInteger size) +{ + if (CObject *pv = (CObject *)p) + delete pv; + return 0; +} +bool push_CObject(HSQUIRRELVM vm, const CObject &quat) +{ + CObject *newquat = new CObject((EngineVM *)sq_getforeignptr(vm)); + *newquat = quat; + if (!CreateNativeClassInstance(vm, "CObject", newquat, CObject_release_hook)) + { + delete newquat; + return false; + } + return true; +} +::SquirrelObject new_CObject(HSQUIRRELVM vm, const CObject &quat) +{ + ::SquirrelObject ret(vm); + if (push_CObject(vm, quat)) + { + ret.AttachToStackObject(-1); + sq_pop(vm, 1); + } + return ret; +} +int construct_CObject(HSQUIRRELVM vm, CObject *p) +{ + sq_setinstanceup(vm, 1, p); + sq_setreleasehook(vm, 1, CObject_release_hook); + return 1; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +bool CObject::Push(HSQUIRRELVM v, void *_ptr, CObjectType _type, bool managed) +{ + CObject *o = new CObject((EngineVM *)sq_getforeignptr(v), _type, _ptr, managed); + + if (!CreateNativeClassInstance(v, "CObject", o, CObject_release_hook)) + { + __LOG_E__ << "Could not allocate native reference.\n"; + _safe_delete(o); + return false; + } + return true; +} +bool CObject::GetType(HSQUIRRELVM v, int idx, CObjectType &type) +{ + StackHandler sa(v); + + CObject *self; + if (SQ_FAILED(sq_getinstanceup(v, idx, (SQUserPointer*)&self, (SQUserPointer)&__CObject_decl))) + return false; + + __ASSERT__(self != NULL); + + type = self->type; + return true; +} +bool CObject::Get(HSQUIRRELVM v, int idx, void **p, CObjectType type) +{ + __ASSERT__(p != NULL); + + StackHandler sa(v); + + CObject *self; + if (SQ_FAILED(sq_getinstanceup(v, idx, (SQUserPointer*)&self, (SQUserPointer)&__CObject_decl))) + return false; + + __ASSERT__(self != NULL); + + if ((type != typetag_Undefined) && (self->type != type)) + { + sq_throwerror(v, String::Format("Native reference to '%s' expected, got '%s'", CObjectTypeToString(type), CObjectTypeToString(self->type))); + return false; + } + + p[0] = self->native; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(CObject, constructor) + return construct_CObject(v, new CObject((EngineVM *)sq_getforeignptr(v))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(CObject, _cmp) + _GetSelf(CObject, CObject); + _GetTypedParam(object, 2, CObject, CObject); + return sa.Return(asbool(self->native == object->native)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(CObject, type) + _GetSelf(CObject, CObject); + return sa.Return((int)self->type); +_END_IMPL +_MEMBER_FUNCTION_IMPL(CObject, isValid) + _GetSelf(CObject, CObject); + return sa.Return(asbool(self->native)); +_END_IMPL +_MEMBER_FUNCTION_IMPL(CObject, isNull) + _GetSelf(CObject, CObject); + return sa.Return(!asbool(self->native)); +_END_IMPL +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +_BEGIN_CLASS(CObject) + +_MEMBER_FUNCTION(CObject, constructor, -1, ".") +_MEMBER_FUNCTION(CObject, _cmp, 2, ".xx") + +_MEMBER_FUNCTION(CObject, isValid, 1, _SC(".")) +_MEMBER_FUNCTION(CObject, isNull, 1, _SC(".")) +_MEMBER_FUNCTION(CObject, type, 1, _SC(".")) + +_END_CLASS(CObject) +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/cobject/geometry_template_impl.cpp b/include/modules/script_squirrel/cobject/geometry_template_impl.cpp new file mode 100644 index 0000000..b77ad10 --- /dev/null +++ b/include/modules/script_squirrel/cobject/geometry_template_impl.cpp @@ -0,0 +1,206 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + +#ifndef __COBJECT_GEOMETRY_TEMPLATE_IMPL__ +#define __COBJECT_GEOMETRY_TEMPLATE_IMPL__ + + + #include "script_squirrel/cobject/geometry_template_decl.h" + #include "script_squirrel/cobject/cobject_decl.h" + #include "script_squirrel/cobject/vector_decl.h" + #include "script_squirrel/cobject/uv_decl.h" + #include "script_squirrel/cobject/cobject.h" + #include "core/geometry_template.h" + #include "core/resource_factories.h" + #include "core/render_resource_factory.h" + #include "core/render_data.h" + #include "core/renderer.h" + #include "core/engine.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +#define _GetGeometryTemplate(_VAR, _IDX) _GetTypedParam(_VAR, _IDX, GeometryTemplate, GeometryTemplate) +//------------------------------------------------------------------------------ + +_IMPL_NATIVE_CONSTRUCTION(GeometryTemplate, GeometryTemplate); + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(GeometryTemplate, constructor) + return construct_GeometryTemplate(v, new GeometryTemplate); +_END_IMPL +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(GeometryTemplate, clearMaterial) + _GetGeometryTemplate(t, 1) + t->ClearMaterials(); + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(GeometryTemplate, pushMaterial) + _GetGeometryTemplate(t, 1) + const SQChar *name = sa.GetString(2); + t->PushMaterial(name); + return 0; +_END_IMPL +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(GeometryTemplate, clear) + _GetGeometryTemplate(t, 1) + t->Clear(); + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(GeometryTemplate, beginPolygon) + _GetGeometryTemplate(t, 1) + t->BeginPolygon(); + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(GeometryTemplate, pushVertex) + _GetGeometryTemplate(t, 1) + _GetTypedParam(_v, 2, Vector4, Vector) + t->PushVertex(*_v); + return 0; +_END_IMPL +_MEMBER_FUNCTION_IMPL(GeometryTemplate, pushNormal) + _GetGeometryTemplate(t, 1) + _GetTypedParam(n, 2, Vector4, Vector) + t->PushNormal(*n); + return 0; +_END_IMPL +_MEMBER_FUNCTION_IMPL(GeometryTemplate, pushColor) + _GetGeometryTemplate(t, 1) + _GetTypedParam(c, 2, Vector4, Vector) + t->PushColor(Color(*c)); + return 0; +_END_IMPL +_MEMBER_FUNCTION_IMPL(GeometryTemplate, pushUV) + _GetGeometryTemplate(t, 1) + _GetTypedParam(uv, 3, Vector2, UV) + t->PushUV(sa.GetInt(2), *uv); + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(GeometryTemplate, endPolygon) + _GetGeometryTemplate(t, 1) + t->EndPolygon((ushort)sa.GetInt(2)); + return 0; +_END_IMPL +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(GeometryTemplate, setVertexMergeThreshold) + _GetGeometryTemplate(t, 1) + t->SetVertexMergeThreshold(sa.GetFloat(2)); + return 0; +_END_IMPL +_MEMBER_FUNCTION_IMPL(GeometryTemplate, instantiate) + _GetGeometryTemplate(t, 1) + _GetCObject(ResourceFactories, typetag_ResourceFactories, f, 2) + AutoPtr g(t->Instantiate(sa.GetString(3))); + Render::Geometry *r = f->render->NewGeometry(); + r->Create(*f->render, *g); + _ReturnCObject(r, typetag_Geometry) +_END_IMPL +//------------------------------------------------------------------------------ + + +//# Class: GeometryTemplate +_BEGIN_CLASS(GeometryTemplate) + +_MEMBER_FUNCTION(GeometryTemplate, constructor, 1, _SC(".")) + +//------------------------------------------------------------------------------ +//# Topic: Polygon creation +//------------------------------------------------------------------------------ + +/*# + Func: beginPolygon + Proto: void: + Desc: Begin declaration of a new polygon. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, beginPolygon, 1, _SC(".")) +/*# + Func: pushVertex + Proto: void:Vector + Desc: Push a vertex on the current polygon declaration. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, pushVertex, 2, _SC(".x")) +/*# + Func: pushNormal + Proto: void:Vector + Desc: Push a normal on the current polygon declaration. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, pushNormal, 2, _SC(".x")) +/*# + Func: pushColor + Proto: void:Vector + Desc: Push a color on the current polygon declaration. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, pushColor, 2, _SC(".x")) +/*# + Func: pushUV + Proto: void:int channel, UV + Desc: Push an UV on a channel of the current polygon declaration. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, pushUV, 3, _SC(".ix")) +/*# + Func: endPolygon + Proto: void:int material + Desc: End declaration of the current polygon and specify its material index. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, endPolygon, 2, _SC(".i")) + +//------------------------------------------------------------------------------ +//# Topic: Geometry creation +//------------------------------------------------------------------------------ + +/*# + Func: clear + Proto: void: + Desc: Clear current template definition, keep the current material table. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, clear, 1, _SC(".")) + +/*# + Func: instantiate + Proto: Geometry:Engine engine, string name + Desc: Instantiate the current template as a named geometry. + Note: If the geometry name is already found in the current engine cache, a + cached copy will be returned instead of a new instantiation. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, instantiate, 3, _SC(".xs")) + +/*# + Func: clearMaterial + Proto: void: + Desc: Push a material on the template material table. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, clearMaterial, 1, _SC(".")) +/*# + Func: pushMaterial + Proto: void:String path + Desc: Push a material path on the template material table. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, pushMaterial, 2, _SC(".s")) + +/*# + Func: setVertexMergeThreshold + Proto: void:float threshold + Desc: Set the vertex merging algorithm threshold. +#*/ +_MEMBER_FUNCTION(GeometryTemplate, setVertexMergeThreshold, 2, _SC(".n")) + +_END_CLASS(GeometryTemplate) + + +#endif // __COBJECT_GEOMETRY_TEMPLATE_IMPL__ diff --git a/include/modules/script_squirrel/cobject/matrix_impl.cpp b/include/modules/script_squirrel/cobject/matrix_impl.cpp new file mode 100644 index 0000000..e13719f --- /dev/null +++ b/include/modules/script_squirrel/cobject/matrix_impl.cpp @@ -0,0 +1,643 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "script_squirrel/cobject/matrix_decl.h" + #include "script_squirrel/cobject/vector_decl.h" + #include "math/matrix4.h" + #include "math/matrix3.h" + #include "math/quaternion.h" + #include "nstring/nstring.h" + #include "log/log.h" + + using namespace GS; + + +#ifndef _T +#define _T +#endif + +_DECL_CLASS(Matrix4) +_IMPL_NATIVE_CONSTRUCTION(Matrix4, Matrix4) + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix4, constructor) + Matrix4 temp; + int nparams = sa.GetParamCount(); + + switch (nparams) + { + case 1: temp.Set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); break; + case 5: + { + _GetTypedParam(_u, 2, Vector4, Vector); + _GetTypedParam(_v, 3, Vector4, Vector); + _GetTypedParam(_w, 4, Vector4, Vector); + _GetTypedParam(_x, 5, Vector4, Vector); + + if (_u && _v && _w && _x) + { temp.Set(_u->x, _u->y, _u->z, _u->w, _v->x, _v->y, _v->z, _v->w, _w->x, _w->y, _w->z, _w->w, _x->x, _x->y, _x->z, _x->w); } + else + return sa.ThrowError("Matrix4() invalid parameters"); + } + break; + + case 17: + temp.Set( + sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4), sa.GetFloat(5), + sa.GetFloat(6), sa.GetFloat(7), sa.GetFloat(8), sa.GetFloat(9), + sa.GetFloat(10), sa.GetFloat(11), sa.GetFloat(12), sa.GetFloat(13), + sa.GetFloat(14), sa.GetFloat(15), sa.GetFloat(16), sa.GetFloat(17) + ); + break; + + default: + return sa.ThrowError("Matrix4() wrong parameter count"); + } + return construct_Matrix4(v, new Matrix4(temp)); +_END_IMPL + +//------------------------------------------------------------------------------ +// The string class is used to speed up comparison as it uses a hash-based early +// rejection. +static String uc_m00("m00"), uc_m10("m10"), uc_m20("m20"), uc_m30("m30"), + uc_m01("m01"), uc_m11("m11"), uc_m21("m21"), uc_m31("m31"), + uc_m02("m02"), uc_m12("m12"), uc_m22("m22"), uc_m32("m32"), + uc_m03("m03"), uc_m13("m13"), uc_m23("m23"), uc_m33("m33"); + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix4, _set) + _GetSelf(Matrix4, Matrix4); + + switch (sa.GetType(2)) + { + case OT_STRING: + { + String idx(sa.GetString(2)); + + if (idx == uc_m00) return sa.Return(self->m[0][0] = sa.GetFloat(3)); + if (idx == uc_m10) return sa.Return(self->m[1][0] = sa.GetFloat(3)); + if (idx == uc_m20) return sa.Return(self->m[2][0] = sa.GetFloat(3)); + if (idx == uc_m30) return sa.Return(self->m[3][0] = sa.GetFloat(3)); + if (idx == uc_m01) return sa.Return(self->m[0][1] = sa.GetFloat(3)); + if (idx == uc_m11) return sa.Return(self->m[1][1] = sa.GetFloat(3)); + if (idx == uc_m21) return sa.Return(self->m[2][1] = sa.GetFloat(3)); + if (idx == uc_m31) return sa.Return(self->m[3][1] = sa.GetFloat(3)); + if (idx == uc_m02) return sa.Return(self->m[0][2] = sa.GetFloat(3)); + if (idx == uc_m12) return sa.Return(self->m[1][2] = sa.GetFloat(3)); + if (idx == uc_m22) return sa.Return(self->m[2][2] = sa.GetFloat(3)); + if (idx == uc_m32) return sa.Return(self->m[3][2] = sa.GetFloat(3)); + if (idx == uc_m03) return sa.Return(self->m[0][3] = sa.GetFloat(3)); + if (idx == uc_m13) return sa.Return(self->m[1][3] = sa.GetFloat(3)); + if (idx == uc_m23) return sa.Return(self->m[2][3] = sa.GetFloat(3)); + if (idx == uc_m33) return sa.Return(self->m[3][3] = sa.GetFloat(3)); + } + break; + } + return SQ_ERROR; +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix4, _get) + _GetSelf(Matrix4, Matrix4); + + switch (sa.GetType(2)) + { + case OT_STRING: + { + String idx(sa.GetString(2)); + + if (idx == uc_m00) return sa.Return(self->m[0][0]); + if (idx == uc_m10) return sa.Return(self->m[1][0]); + if (idx == uc_m20) return sa.Return(self->m[2][0]); + if (idx == uc_m30) return sa.Return(self->m[3][0]); + if (idx == uc_m01) return sa.Return(self->m[0][1]); + if (idx == uc_m11) return sa.Return(self->m[1][1]); + if (idx == uc_m21) return sa.Return(self->m[2][1]); + if (idx == uc_m31) return sa.Return(self->m[3][1]); + if (idx == uc_m02) return sa.Return(self->m[0][2]); + if (idx == uc_m12) return sa.Return(self->m[1][2]); + if (idx == uc_m22) return sa.Return(self->m[2][2]); + if (idx == uc_m32) return sa.Return(self->m[3][2]); + if (idx == uc_m03) return sa.Return(self->m[0][3]); + if (idx == uc_m13) return sa.Return(self->m[1][3]); + if (idx == uc_m23) return sa.Return(self->m[2][3]); + if (idx == uc_m33) return sa.Return(self->m[3][3]); + } + break; + } + return SQ_ERROR; +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix4, GetRow) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(sa.GetInt(2)))); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, SetRow) + _GetSelf(Matrix4, Matrix4); + _GetTypedParam(row, 3, Vector4, Vector) + self->SetRow(sa.GetInt(2), *row); + return 0; +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, GetColumn) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetColumn(sa.GetInt(2)))); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, SetColumn) + _GetSelf(Matrix4, Matrix4); + _GetTypedParam(col, 3, Vector4, Vector) + self->SetColumn(sa.GetInt(2), *col); + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Matrix4, GetFront) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(2))); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, GetBack) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(2).Reversed())); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, GetUp) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(1))); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, GetDown) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(1).Reversed())); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, GetRight) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(0))); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, GetLeft) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(0).Reversed())); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix4, GetPosition) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(3))); +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix4, _mul) + _GetSelf(Matrix4, Matrix4); + _GetTypedParam(mtx, 2, Matrix4, Matrix4) + _SA_RETURN_OBJECT(new_Matrix4(v, *self * *mtx)); +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix4, AsMatrix3) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Matrix3(v, Matrix3::FromMatrix4(*self))); +_END_IMPL +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix4, GetInverseMatrix) + _GetSelf(Matrix4, Matrix4); + _SA_RETURN_OBJECT(new_Matrix4(v, self->InversedFast())); +_END_IMPL +//----------------------------------------------------------------------------- +_MEMBER_FUNCTION_IMPL(Matrix4, Print) + _GetSelf(Matrix4, Matrix4); + const char *label = "Matrix"; + if (sa.GetParamCount() == 2) + label = sa.GetString(2); + __LOG__ << "Dumping matrix '" << label << "':\n"; + for (int n = 0; n < 4; ++n) + { + Vector4 v = self->GetRow(n); + __LOG__ << "Row " << n << ": { " << v.x << ", " << v.y << ", " << v.z << ", " << v.w << "}\n"; + } + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Matrix4, RotationFromMatrix3) + _GetSelf(Matrix4, Matrix4); + _GetTypedParam(mtx, 2, Matrix3, Matrix3) + self->m[0][0] = mtx->m[0][0]; self->m[1][0] = mtx->m[1][0]; self->m[2][0] = mtx->m[2][0]; + self->m[0][1] = mtx->m[0][1]; self->m[1][1] = mtx->m[1][1]; self->m[2][1] = mtx->m[2][1]; + self->m[0][2] = mtx->m[0][2]; self->m[1][2] = mtx->m[1][2]; self->m[2][2] = mtx->m[2][2]; + return 0; +_END_IMPL + +//------------------------------------------------------------------------------ +/*# + Topic: Matrix + Type: Matrix3 + Type: Matrix4 +#*/ + +/*# + Section: MatrixGeneric + Desc: Global functions +#*/ + /*# + Func: Matrix3 + Proto: Matrix3:float m00...m33 + Desc: Create a new 3x3 matrix. + Example: +// Construct a default unity matrix. +local a = Matrix3() +// Vector based constructor. +local b = Matrix3(v0, v1, v2) +// Float based constructor. +local c = Matrix3(m00, m10, m20, m01, m11, m21, m02, m12, m22) + #*/ + /*# + Func: Matrix4 + Proto: Matrix4:float m00...m44 + Desc: Create a new 4x4 matrix. + Example: +// Construct a default unity matrix. +local a = Matrix4() +// Vector based constructor. +local b = Matrix4(v0, v1, v2, v3) +// Float based constructor. +local c = Matrix3(m00, m10, m20, m30, m01, m11, m21, m31, m02, m12, m22, m32, m03, m13, m23, m33) + #*/ + /*# + Func: RotationMatrixX + Proto: Matrix3:float angle + Desc: Create a 3x3 rotation matrix around the X axis, angle is in degree. + Example: local m = RotationMatrixX(Deg(45)) + #*/ + /*# + Func: RotationMatrixY + Proto: Matrix3:float angle + Desc: Create a 3x3 rotation matrix around the Y axis, angle is in degree. + Example: local m = RotationMatrixY(Deg(45)) + #*/ + /*# + Func: RotationMatrixZ + Proto: Matrix3:float angle + Desc: Create a 3x3 rotation matrix around the Z axis, angle is in degree. + Example: local m = RotationMatrixZ(Deg(45)) + #*/ + /*# + Func: MatrixToEuler + Proto: Vector:Matrix3,RotationOrder + Desc: Convert a world space matrix to Euler angles. + #*/ + /*# + Func: EulerFromDirection + Proto: Vector:Vector direction + Desc: Convert a world space direction vector to an Euler angle triplet (x, y, z). + #*/ + /*# + Func: EulerFromDirectionAndUp + Proto: Vector:Vector direction,Vector up + Desc: Convert a world space direction and up vectors to an Euler angle triplet (x, y, z). + #*/ + /*# + Func: RotationMatrixFromDirection + Proto: Matrix3:Vector direction + Desc: Convert a world space direction vector to a 3x3 rotation matrix. + #*/ + /*# + Func: RotationMatrixFromDirectionAndUp + Proto: Matrix3:Vector direction,Vector up + Desc: Convert a world space direction and up vectors to a 3x3 rotation matrix. + #*/ + /*# + Func: TransformationMatrix + Proto: Matrix4:Vector position,Vector euler,Vector scale,Vector pivot + Desc: Create a position, rotation, scale, offset 4x4 matrix.
The offset is applied first, scale second, rotation third and finally position is applied. + #*/ + +/*# + Section: Matrix4Generic + Desc: Matrix 4x4 +#*/ +_BEGIN_CLASS(Matrix4) +_MEMBER_FUNCTION(Matrix4, constructor, -1, _T(". n|x n|x n|x n|x nnnn nnnn")) +_MEMBER_FUNCTION(Matrix4, _get, 2, _T("xs")) +_MEMBER_FUNCTION(Matrix4, _set, 3, _T("xsn")) +_MEMBER_FUNCTION(Matrix4, _mul, 2, _T("xx")) + + /*# + Func: GetRow + Proto: Vector:int index + Desc: Return a matrix row as a vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetRow, 2, _T("xi")) + /*# + Func: SetRow + Proto: void:int index, Vector row + Desc: Set a matrix row from a vector. + #*/ +_MEMBER_FUNCTION(Matrix4, SetRow, 3, _T("xix")) + /*# + Func: GetColumn + Proto: Vector:int index + Desc: Return a matrix column as a vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetColumn, 2, _T("xi")) + /*# + Func: SetColumn + Proto: void:int index, Vector column + Desc: Set a matrix column from a vector. + #*/ +_MEMBER_FUNCTION(Matrix4, SetColumn, 3, _T("xix")) + /*# + Func: AsMatrix3 + Proto: Matrix3: + Desc: Return matrix as a 3x3 matrix. + #*/ +_MEMBER_FUNCTION(Matrix4, AsMatrix3, 1, _T("x")) +/*# + Func: GetInverseMatrix + Proto: Matrix4: + Desc: Return inverse matrix. + #*/ +_MEMBER_FUNCTION(Matrix4, GetInverseMatrix, 1, _T("x")) + /*# + Func: Print + Proto: void: + Desc: Output matrix content to the engine log. + #*/ +_MEMBER_FUNCTION(Matrix4, Print, -1, _T("x")) + /*# + Func: RotationFromMatrix3 + Proto: void:Matrix3 orientation + Desc: Set the rotation part of a 4x4 transformation matrix from a 3x3 matrix. + #*/ +_MEMBER_FUNCTION(Matrix4, RotationFromMatrix3, 2, _T("xx")) + +/*# + Section: Matrix4Component + Desc: Transformation matrix component +#*/ + + /*# + Func: GetFront + Proto: Vector: + Desc: Return the transformation matrix front axis vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetFront, 1, _T("x")) + /*# + Func: GetBack + Proto: Vector: + Desc: Return the transformation matrix down axis vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetBack, 1, _T("x")) + /*# + Func: GetRight + Proto: Vector: + Desc: Return the transformation matrix right axis vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetRight, 1, _T("x")) + /*# + Func: GetLeft + Proto: Vector: + Desc: Return the transformation matrix left axis vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetLeft, 1, _T("x")) + /*# + Func: GetUp + Proto: Vector: + Desc: Return the transformation matrix up axis vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetUp, 1, _T("x")) + /*# + Func: GetDown + Proto: Vector: + Desc: Return the transformation matrix down axis vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetDown, 1, _T("x")) + /*# + Func: GetPosition + Proto: Vector: + Desc: Return the transformation matrix position vector. + #*/ +_MEMBER_FUNCTION(Matrix4, GetPosition, 1, _T("x")) + +_END_CLASS(Matrix4) + +//------------------------------------------------------------------------------ +_DECL_CLASS(Matrix3); +_IMPL_NATIVE_CONSTRUCTION(Matrix3, Matrix3); + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix3, constructor) + Matrix3 temp, *newv = NULL; + int nparams = sa.GetParamCount(); + + switch (nparams) + { + case 1: temp.Set(1, 0, 0, 0, 1, 0, 0, 0, 1); break; + case 4: + { + _GetTypedParam(_u, 2, Vector4, Vector); + _GetTypedParam(_v, 3, Vector4, Vector); + _GetTypedParam(_w, 4, Vector4, Vector); + + if (_u && _v && _w) + { temp.Set(*_u, *_v, *_w); } + else + return sa.ThrowError("Matrix3() invalid parameters"); + } + break; + + case 10: + temp.Set( + sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4), + sa.GetFloat(5), sa.GetFloat(6), sa.GetFloat(7), + sa.GetFloat(8), sa.GetFloat(9), sa.GetFloat(10) + ); + break; + + default: + return sa.ThrowError("Matrix3() wrong parameter count"); + } + + newv = new Matrix3(temp); + return construct_Matrix3(v, newv); +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix3, _set) + _GetSelf(Matrix3, Matrix3); + + switch (sa.GetType(2)) + { + case OT_STRING: + { + String idx(sa.GetString(2)); + + if (idx == uc_m00) return sa.Return(self->m[0][0] = sa.GetFloat(3)); + if (idx == uc_m10) return sa.Return(self->m[1][0] = sa.GetFloat(3)); + if (idx == uc_m20) return sa.Return(self->m[2][0] = sa.GetFloat(3)); + if (idx == uc_m01) return sa.Return(self->m[0][1] = sa.GetFloat(3)); + if (idx == uc_m11) return sa.Return(self->m[1][1] = sa.GetFloat(3)); + if (idx == uc_m21) return sa.Return(self->m[2][1] = sa.GetFloat(3)); + if (idx == uc_m02) return sa.Return(self->m[0][2] = sa.GetFloat(3)); + if (idx == uc_m12) return sa.Return(self->m[1][2] = sa.GetFloat(3)); + if (idx == uc_m22) return sa.Return(self->m[2][2] = sa.GetFloat(3)); + } + break; + } + return SQ_ERROR; +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix3, _get) + _GetSelf(Matrix3, Matrix3); + + switch (sa.GetType(2)) + { + case OT_STRING: + { + String idx(sa.GetString(2)); + + if (idx == uc_m00) return sa.Return(self->m[0][0]); + if (idx == uc_m10) return sa.Return(self->m[1][0]); + if (idx == uc_m20) return sa.Return(self->m[2][0]); + if (idx == uc_m01) return sa.Return(self->m[0][1]); + if (idx == uc_m11) return sa.Return(self->m[1][1]); + if (idx == uc_m21) return sa.Return(self->m[2][1]); + if (idx == uc_m02) return sa.Return(self->m[0][2]); + if (idx == uc_m12) return sa.Return(self->m[1][2]); + if (idx == uc_m22) return sa.Return(self->m[2][2]); + } + break; + } + return SQ_ERROR; +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix3, GetRow) + _GetSelf(Matrix3, Matrix3); + _SA_RETURN_OBJECT(new_Vector(v, self->GetRow(sa.GetInt(2)))); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix3, SetRow) + _GetSelf(Matrix3, Matrix3); + _GetTypedParam(row, 3, Vector4, Vector) + self->SetRow(sa.GetInt(2), *row); + return 0; +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix3, GetColumn) + _GetSelf(Matrix3, Matrix3); + _SA_RETURN_OBJECT(new_Vector(v, self->GetColumn(sa.GetInt(2)))); +_END_IMPL +_MEMBER_FUNCTION_IMPL(Matrix3, SetColumn) + _GetSelf(Matrix3, Matrix3); + _GetTypedParam(col, 3, Vector4, Vector) + self->SetColumn(sa.GetInt(2), *col); + return 0; +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix3, _mul) + _GetSelf(Matrix3, Matrix3); + _GetTypedParam(mtx, 2, Matrix3, Matrix3) + _SA_RETURN_OBJECT(new_Matrix3(v, *self * *mtx)); +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix3, AsMatrix4) + _GetSelf(Matrix3, Matrix3); + _SA_RETURN_OBJECT(new_Matrix4(v, Matrix4::FromMatrix3(*self))); +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Matrix3, FromOrthonormalBasis) +// _CHECK_SELF(Matrix3, Matrix3); + _GetTypedParam(_w, 2, Vector4, Vector) + Vector4 *_v = NULL; + switch (sa.GetParamCount()) + { + case 2: + break; + case 3: + { _GetTypedParam(__v, 3, Vector4, Vector) + _v = __v; } break; + default: + return sa.ThrowError("Matrix3::FromOrthonormalBasis() wrong parameter count"); + } + _SA_RETURN_OBJECT(new_Matrix3(v, Matrix3::FromOrthonormalBasis(*_w, _v))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Matrix3, SlerpTo) + _GetSelf(Matrix3, Matrix3); + _GetTypedParam(to, 3, Matrix3, Matrix3) + float t = sa.GetFloat(2); + Matrix3 out = Quaternion::Slerp(t, Quaternion::FromMatrix3(*self), Quaternion::FromMatrix3(*to)).AsMatrix3(); + _SA_RETURN_OBJECT(new_Matrix3(v, out)) +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Matrix3, AsEuler) + _GetSelf(Matrix3, Matrix3); + Math::rOrder rorder = Math::rOrder_Default; + if (sa.GetParamCount() == 2) + rorder = (Math::rOrder)sa.GetInt(2); + _SA_RETURN_OBJECT(new_Vector(v, self->AsEuler(rorder))); +_END_IMPL + +//------------------------------------------------------------------------------ +/*# + Section: Matrix3Generic + Desc: Matrix 3x3 +#*/ +_BEGIN_CLASS(Matrix3) +_MEMBER_FUNCTION(Matrix3, constructor, -1, _T(". n|x n|x n|x nnn nnn")) +_MEMBER_FUNCTION(Matrix3, _get, 2, _T("xs")) +_MEMBER_FUNCTION(Matrix3, _set, 3, _T("xsn")) +_MEMBER_FUNCTION(Matrix3, _mul, 2, _T("xx")) + /*# + Func: GetRow + Proto: Vector:int index + Desc: Return a matrix row as a vector. + #*/ +_MEMBER_FUNCTION(Matrix3, GetRow, 2, _T("xi")) + /*# + Func: SetRow + Proto: void:int index, Vector row + Desc: Set a matrix row from a vector. + #*/ +_MEMBER_FUNCTION(Matrix3, SetRow, 3, _T("xix")) + /*# + Func: GetColumn + Proto: Vector:int index + Desc: Return a matrix column as a vector. + #*/ +_MEMBER_FUNCTION(Matrix3, GetColumn, 2, _T("xi")) + /*# + Func: SetColumn + Proto: void:int index, Vector column + Desc: Set a matrix column from a vector. + #*/ +_MEMBER_FUNCTION(Matrix3, SetColumn, 3, _T("xix")) + /*# + Func: AsMatrix4 + Proto: Matrix4: + Desc: Return matrix as a 4x4 matrix. + #*/ +_MEMBER_FUNCTION(Matrix3, AsMatrix4, 1, _T("x")) + /*# + Func: FromOrthonormalBasis + Proto: Matrix3:Vector u,[Vector v] + Desc: Build an orientation matrix from one or two basis vectors. + #*/ +_MEMBER_FUNCTION(Matrix3, FromOrthonormalBasis, -2, _T(".xx")) + /*# + Func: SlerpTo + Proto: Matrix3:float t,Matrix3 to + Desc: Interpolate a 3x3 orientation matrix to another 3x3 orientation matrix using spherical linear interpolation. + Example: +local m_a = ItemGetRotationMatrix(item_a) +local m_b = ItemGetRotationMatrix(item_b) + +// m_c will store a rotation halfway between the rotation stored in the m_a and m_b matrices. +local m_c = m_a.SlerpTo(0.5, m_b) + #*/ +_MEMBER_FUNCTION(Matrix3, SlerpTo, 3, _T("xnx")) + /*# + Func: AsEuler + Proto: Vector:[RotationOrder method] + Desc: Return a 3x3 orientation matrix as an Euler triplet. + #*/ +_MEMBER_FUNCTION(Matrix3, AsEuler, -1, _T("xi")) +_END_CLASS(Matrix3) diff --git a/include/modules/script_squirrel/cobject/quaternion_impl.cpp b/include/modules/script_squirrel/cobject/quaternion_impl.cpp new file mode 100644 index 0000000..2c22ac4 --- /dev/null +++ b/include/modules/script_squirrel/cobject/quaternion_impl.cpp @@ -0,0 +1,328 @@ +/* ----------------------------------------------------------------------------- + nEngine - GSFramework + Copyright 2001-2012 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + #include "script_squirrel/cobject/quaternion_decl.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "script_squirrel/cobject/vector_decl.h" + #include "math/matrix3.h" + #include "math/quaternion.h" + #include "math/vector.h" + #include "nstring/nstring.h" + #include "log/log.h" + + using namespace GS; + + +_DECL_CLASS(Quaternion) +_IMPL_NATIVE_CONSTRUCTION(Quaternion, Quaternion) + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Quaternion, constructor) + Quaternion temp; + int nparams = sa.GetParamCount(); + + switch (nparams) + { + case 1: temp.Set(); break; + case 5: + temp.Set(sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4), sa.GetFloat(5)); + break; + + default: + return sa.ThrowError("Quaternion() wrong parameter count"); + } + return construct_Quaternion(v, new Quaternion(temp)); + +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Quaternion, _cloned) + _GetTypedParam(quat, 2, Quaternion, Quaternion); + return construct_Quaternion(v, new Quaternion(*quat)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, _set) + _GetSelf(Quaternion, Quaternion); + + const SQChar *s = sa.GetString(2); + int index = s ? s[0] : sa.GetInt(2); + + switch (index) + { + case 0: case 'x': + return sa.Return(self->x = sa.GetFloat(3)); + case 1: case 'y': + return sa.Return(self->y = sa.GetFloat(3)); + case 2: case 'z': + return sa.Return(self->z = sa.GetFloat(3)); + case 3: case 'w': + return sa.Return(self->w = sa.GetFloat(3)); + } + return SQ_ERROR; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, _get) + _GetSelf(Quaternion, Quaternion); + const SQChar *s = sa.GetString(2); + if (s && (s[1] != 0)) + return SQ_ERROR; + int index = s && (s[1] == 0) ? s[0] : sa.GetInt(2); + + switch (index) + { + case 0: case 'x': + return sa.Return(self->x); + case 1: case 'y': + return sa.Return(self->y); + case 2: case 'z': + return sa.Return(self->z); + case 3: case 'w': + return sa.Return(self->w); + } + return SQ_ERROR; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, _mul) + _GetSelf(Quaternion, Quaternion); + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { + // Quaternion * Quaternion. + _CHECK_INST_PARAM_RAW(quat, 2, Quaternion, Quaternion); + if (quat) + _SA_RETURN_OBJECT(new_Quaternion(v, *self * *quat)); + } + break; + + // Quaternion * Scalar + case OT_INTEGER: + _SA_RETURN_OBJECT(new_Quaternion(v, *self * (float)sa.GetInt(2))); + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Quaternion(v, *self * sa.GetFloat(2))); + } + return sa.ThrowError("Quaternion * operator: Invalid argument type.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, _div) + _GetSelf(Quaternion, Quaternion); + switch (sa.GetType(2)) + { + // Quaternion / Scalar + case OT_INTEGER: + _SA_RETURN_OBJECT(new_Quaternion(v, *self / (float)sa.GetInt(2))); + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Quaternion(v, *self / sa.GetFloat(2))); + } + return sa.ThrowError("Quaternion / operator: Invalid argument type.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, _add) + _GetSelf(Quaternion, Quaternion); + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { + // Quaternion + Quaternion. + _CHECK_INST_PARAM_RAW(quat, 2, Quaternion, Quaternion); + if (quat) + _SA_RETURN_OBJECT(new_Quaternion(v, *self + *quat)); + } + break; + + // Quaternion + Scalar + case OT_INTEGER: + _SA_RETURN_OBJECT(new_Quaternion(v, *self + (float)sa.GetInt(2))); + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Quaternion(v, *self + sa.GetFloat(2))); + } + return sa.ThrowError("Quaternion + operator: Invalid argument type.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, _sub) + _GetSelf(Quaternion, Quaternion); + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { + // Quaternion - Quaternion. + _CHECK_INST_PARAM_RAW(quat, 2, Quaternion, Quaternion); + if (quat) + _SA_RETURN_OBJECT(new_Quaternion(v, *self - *quat)); + } + break; + + // Quaternion - Scalar + case OT_INTEGER: + _SA_RETURN_OBJECT(new_Quaternion(v, *self - (float)sa.GetInt(2))); + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Quaternion(v, *self - sa.GetFloat(2))); + } + return sa.ThrowError("Quaternion - operator: Invalid argument type.\n"); +_END_IMPL + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Quaternion, Set) + _GetSelf(Quaternion, Quaternion); + switch (sa.GetParamCount()) + { + case 1: self->Set(); break; + case 2: self->Set(sa.GetFloat(2)); break; + case 3: self->Set(sa.GetFloat(2), sa.GetFloat(3)); break; + case 4: self->Set(sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4)); break; + case 5: self->Set(sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4), sa.GetFloat(5)); break; + default: + return sa.ThrowError("Quaternion Set() wrong parameters"); + } + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, Slerp) + _GetSelf(Quaternion, Quaternion); + float k = sa.GetFloat(2); + _GetTypedParam(quat, 3, Quaternion, Quaternion) + _SA_RETURN_OBJECT(new_Quaternion(v, Quaternion::Slerp(k, *self, *quat))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, Normalize) + _GetSelf(Quaternion, Quaternion); + _SA_RETURN_OBJECT(new_Quaternion(v, self->Normalize())); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, Inverse) + _GetSelf(Quaternion, Quaternion); + _SA_RETURN_OBJECT(new_Quaternion(v, self->Inverse())); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, Dot) + _GetSelf(Quaternion, Quaternion); + _GetTypedParam(quat, 2, Quaternion, Quaternion); + return sa.Return(self->Dot(*quat)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, AsMatrix3) + _GetSelf(Quaternion, Quaternion); + _SA_RETURN_OBJECT(new_Matrix3(v, self->AsMatrix3())); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, QuaternionFromAxisAngle) + _GetSelf(Quaternion, Quaternion); + _GetTypedParam(vec, 3, Vector4, Vector); + _SA_RETURN_OBJECT(new_Quaternion(v, Quaternion::FromAxisAngle(sa.GetFloat(2), vec->x, vec->y, vec->z))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, QuaternionFromMatrix3) + _GetSelf(Quaternion, Quaternion); + _GetTypedParam(mtx, 2, Matrix3, Matrix3); + _SA_RETURN_OBJECT(new_Quaternion(v, Quaternion::FromMatrix3(*mtx))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, QuaternionLookAt) + _GetSelf(Quaternion, Quaternion); + _GetTypedParam(vec, 2, Vector4, Vector); + _SA_RETURN_OBJECT(new_Quaternion(v, Quaternion::LookAt(*vec))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Quaternion, Print) + _GetSelf(Quaternion, Quaternion); + const char *label = "Quaternion"; + if (sa.GetParamCount() == 2) + label = sa.GetString(2); + __LOG__ << label << ": { x = " << self->x << ", y = " << self->y << ", z = " << self->z << ", w = " << self->w << "}\n"; + return 0; +_END_IMPL + +/*# + Topic: Quaternion + Type: Quaternion +#*/ + +/*# + Section: QuaternionGeneric + Desc: Generic +#*/ +_BEGIN_CLASS(Quaternion) + + /*# + Func: Quaternion + Proto: Quaternion:float x = 0,float y = 0,float z = 0,float w = 1 + Desc: Create a new quaternion. + Example: +local u = Quaternion() +local v = Quaternion(0, 0, 0, 1) + +u.Set(-1, 0, 0) + #*/ +_MEMBER_FUNCTION(Quaternion, constructor, -1, _T(".n|xnnn")) +_MEMBER_FUNCTION(Quaternion, _cloned, 2, _T(".x")) +_MEMBER_FUNCTION(Quaternion, _set, 2, _T("xs|n")) +_MEMBER_FUNCTION(Quaternion, _get, 2, _T("xs|n")) +_MEMBER_FUNCTION(Quaternion, _add, 2, _T("xx|n")) +_MEMBER_FUNCTION(Quaternion, _sub, 2, _T("xx|n")) +_MEMBER_FUNCTION(Quaternion, _mul, 2, _T("xx|n")) +_MEMBER_FUNCTION(Quaternion, _div, 2, _T("xn")) + + /*# + Func: Set + Proto: void:float x = 0,float y = 0,float z = 0,float w = 1 + Desc: Set quaternion values. + #*/ +_MEMBER_FUNCTION(Quaternion, Set, -1, _T("xnnnn")) + /*# + Func: Slerp + Proto: Quaternion:float,Quaternion + Desc: Returns a spherical linear interpolation. + #*/ +_MEMBER_FUNCTION(Quaternion, Slerp, 3, _T("xnx")) + /*# + Func: Normalize + Proto: Quaternion:void + Desc: Returns the normalized quaternion. + #*/ +_MEMBER_FUNCTION(Quaternion, Normalize, 1, _T("x")) + /*# + Func: Inverse + Proto: Quaternion:void + Desc: Returns the inverse quaternion. + #*/ +_MEMBER_FUNCTION(Quaternion, Inverse, 1, _T("x")) + /*# + Func: Dot + Proto: Quaternion:Quaternion + Desc: Returns the Dot product. + #*/ +_MEMBER_FUNCTION(Quaternion, Dot, 2, _T("xx")) + /*# + Func: AsMatrix3 + Proto: Matrix3:void + Desc: Returns the Matrix3 from the quaternion. + #*/ +_MEMBER_FUNCTION(Quaternion, AsMatrix3, 1, _T("x")) + /*# + Func: QuaternionFromAxisAngle + Proto: Quaternion:float angle,Vector axis + Desc: Returns a quaternion based on angle and axis. + #*/ +_MEMBER_FUNCTION(Quaternion, QuaternionFromAxisAngle, 3, _T(".nx")) + /*# + Func: QuaternionFromMatrix3 + Proto: Quaternion:Matrix3 + Desc: Returns a quaternion based on a Matrix3. + #*/ +_MEMBER_FUNCTION(Quaternion, QuaternionFromMatrix3, 2, _T(".x")) + /*# + Func: QuaternionLookAt + Proto: Quaternion:Vector direction + Desc: Returns a quaternion looking at direction. + #*/ +_MEMBER_FUNCTION(Quaternion, QuaternionLookAt, 2, _T(".x")) + /*# + Func: Print + Proto: void: + Desc: Dump this quaternion components (x,y,z,w) to the engine log. + #*/ +_MEMBER_FUNCTION(Quaternion, Print, -1, _T("x")) + +_END_CLASS(Quaternion) \ No newline at end of file diff --git a/include/modules/script_squirrel/cobject/squirrel_bindings_utils.cpp b/include/modules/script_squirrel/cobject/squirrel_bindings_utils.cpp new file mode 100644 index 0000000..d7200fc --- /dev/null +++ b/include/modules/script_squirrel/cobject/squirrel_bindings_utils.cpp @@ -0,0 +1,113 @@ +#include "squirrel.h" +#include "script_squirrel/cobject/squirrel_object.h" +#include "script_squirrel/cobject/squirrel_bindings_utils.h" + +bool CreateStaticNamespace(HSQUIRRELVM v,ScriptNamespaceDecl *sn) +{ + int n = 0; + sq_pushroottable(v); + sq_pushstring(v,sn->name,-1); + sq_newtable(v); + const ScriptClassMemberDecl *members = sn->members; + const ScriptClassMemberDecl *m = 0; + while(members[n].name) { + m = &members[n]; + sq_pushstring(v,m->name,-1); + sq_newclosure(v,m->func,0); + sq_setparamscheck(v,m->params,m->typemask); + sq_setnativeclosurename(v,-1,m->name); + sq_createslot(v,-3); + n++; + } + const ScriptConstantDecl *consts = sn->constants; + const ScriptConstantDecl *c = 0; + n = 0; + while(consts[n].name) { + c = &consts[n]; + sq_pushstring(v,c->name,-1); + switch(c->type) { + case OT_STRING: sq_pushstring(v,c->val.s,-1);break; + case OT_INTEGER: sq_pushinteger(v,c->val.i);break; + case OT_FLOAT: sq_pushfloat(v,c->val.f);break; + } + sq_createslot(v,-3); + n++; + } + if(sn->delegate) { + const ScriptClassMemberDecl *members = sn->delegate; + const ScriptClassMemberDecl *m = 0; + sq_newtable(v); + while(members[n].name) { + m = &members[n]; + sq_pushstring(v,m->name,-1); + sq_newclosure(v,m->func,0); + sq_setparamscheck(v,m->params,m->typemask); + sq_setnativeclosurename(v,-1,m->name); + sq_createslot(v,-3); + n++; + } + sq_setdelegate(v,-2); + } + sq_createslot(v,-3); + sq_pop(v,1); + + return true; +} + +bool CreateClass(HSQUIRRELVM v,SquirrelClassDecl *cd) +{ + int n = 0; + int oldtop = sq_gettop(v); + sq_pushroottable(v); + sq_pushstring(v,cd->name,-1); + if(cd->base) { + sq_pushstring(v,cd->base,-1); + if(SQ_FAILED(sq_get(v,-3))) { + sq_settop(v,oldtop); + return false; + } + } + if(SQ_FAILED(sq_newclass(v,cd->base?1:0))) { + sq_settop(v,oldtop); + return false; + } + sq_settypetag(v,-1,(SQUserPointer)cd); + const ScriptClassMemberDecl *members = cd->members; + const ScriptClassMemberDecl *m = 0; + while(members[n].name) { + m = &members[n]; + sq_pushstring(v,m->name,-1); + sq_newclosure(v,m->func,0); + sq_setparamscheck(v,m->params,m->typemask); + sq_setnativeclosurename(v,-1,m->name); + sq_createslot(v,-3); + n++; + } + sq_createslot(v,-3); + sq_pop(v,1); + return true; +} + +bool CreateNativeClassInstance(HSQUIRRELVM v,const SQChar *classname,SQUserPointer ud,SQRELEASEHOOK hook) +{ + int oldtop = sq_gettop(v); + sq_pushroottable(v); + sq_pushstring(v,classname,-1); + if(SQ_FAILED(sq_rawget(v,-2))){ + sq_settop(v,oldtop); + return false; + } + //sq_pushroottable(v); + if(SQ_FAILED(sq_createinstance(v,-1))) { + sq_settop(v,oldtop); + return false; + } + sq_remove(v,-3); //removes the root table + sq_remove(v,-2); //removes the the class + if(SQ_FAILED(sq_setinstanceup(v,-1,ud))) { + sq_settop(v,oldtop); + return false; + } + sq_setreleasehook(v,-1,hook); + return true; +} diff --git a/include/modules/script_squirrel/cobject/squirrel_object.cpp b/include/modules/script_squirrel/cobject/squirrel_object.cpp new file mode 100644 index 0000000..c34e107 --- /dev/null +++ b/include/modules/script_squirrel/cobject/squirrel_object.cpp @@ -0,0 +1,470 @@ +#include "squirrel.h" +#include "squirrel_object.h" +//#include "SquirrelVM.h" + +SquirrelObject::SquirrelObject(HSQUIRRELVM v) +{ + vm = v; + sq_resetobject(&_o); +} + +SquirrelObject::~SquirrelObject() +{ + if(vm) + sq_release(vm,&_o); +} + +SquirrelObject::SquirrelObject(const SquirrelObject &o) +{ + vm = o.vm; + _o = o._o; + sq_addref(vm,&_o); +} + +SquirrelObject::SquirrelObject(HSQOBJECT &o) +{ + _o = o; + sq_addref(vm,&_o); +} + +SquirrelObject SquirrelObject::Clone() +{ + SquirrelObject ret(vm); + if(GetType() == OT_TABLE || GetType() == OT_ARRAY) + { + sq_pushobject(vm,_o); + sq_clone(vm,-1); + ret.AttachToStackObject(-1); + sq_pop(vm,2); + } + return ret; +} + +SquirrelObject & SquirrelObject::operator =(const SquirrelObject &o) +{ + HSQOBJECT t; + t = o._o; + sq_addref(vm,&t); + sq_release(vm,&_o); + _o = t; + return *this; +} + +SquirrelObject & SquirrelObject::operator =(int n) +{ + sq_pushinteger(vm,n); + AttachToStackObject(-1); + sq_pop(vm,1); + return *this; +} + +void SquirrelObject::Append(const SquirrelObject &o) +{ + if(sq_isarray(_o)) { + sq_pushobject(vm,_o); + sq_pushobject(vm,o._o); + sq_arrayappend(vm,-2); + sq_pop(vm,1); + } +} + +void SquirrelObject::AttachToStackObject(int idx) +{ + HSQOBJECT t; + sq_getstackobj(vm,idx,&t); + sq_addref(vm,&t); + sq_release(vm,&_o); + _o = t; +} + +bool SquirrelObject::SetDelegate(SquirrelObject &obj) +{ + if(obj.GetType() == OT_TABLE || + obj.GetType() == OT_NULL) { + switch(_o._type) { + case OT_USERDATA: + case OT_TABLE: + sq_pushobject(vm,_o); + sq_pushobject(vm,obj._o); + if(SQ_SUCCEEDED(sq_setdelegate(vm,-2))) + return true; + break; + } + } + return false; +} + +SquirrelObject SquirrelObject::GetDelegate() +{ + SquirrelObject ret(vm); + if(_o._type == OT_TABLE || _o._type == OT_USERDATA) + { + sq_pushobject(vm,_o); + sq_getdelegate(vm,-1); + ret.AttachToStackObject(-1); + sq_pop(vm,2); + } + return ret; +} + +bool SquirrelObject::IsNull() const +{ + return sq_isnull(_o); +} + +bool SquirrelObject::IsNumeric() const +{ + return sq_isnumeric(_o) ? true : false; +} + +int SquirrelObject::Len() const +{ + int ret = 0; + if(sq_isarray(_o) || sq_istable(_o) || sq_isstring(_o)) { + sq_pushobject(vm,_o); + ret = sq_getsize(vm,-1); + sq_pop(vm,1); + } + return ret; +} + +#define _SETVALUE_INT_BEGIN \ + bool ret = false; \ + int top = sq_gettop(vm); \ + sq_pushobject(vm,_o); \ + sq_pushinteger(vm,key); + +#define _SETVALUE_INT_END \ + if(SQ_SUCCEEDED(sq_rawset(vm,-3))) { \ + ret = true; \ + } \ + sq_settop(vm,top); \ + return ret; + +bool SquirrelObject::SetValue(SQInteger key,const SquirrelObject &val) +{ + _SETVALUE_INT_BEGIN + sq_pushobject(vm,val._o); + _SETVALUE_INT_END +} + +bool SquirrelObject::SetValue(int key,int n) +{ + _SETVALUE_INT_BEGIN + sq_pushinteger(vm,n); + _SETVALUE_INT_END +} + +bool SquirrelObject::SetValue(int key,float f) +{ + _SETVALUE_INT_BEGIN + sq_pushfloat(vm,f); + _SETVALUE_INT_END +} + +bool SquirrelObject::SetValue(int key,const SQChar *s) +{ + _SETVALUE_INT_BEGIN + sq_pushstring(vm,s,-1); + _SETVALUE_INT_END +} + +bool SquirrelObject::SetValue(int key,bool b) +{ + _SETVALUE_INT_BEGIN + sq_pushbool(vm,b); + _SETVALUE_INT_END +} + +bool SquirrelObject::SetValue(const SquirrelObject &key,const SquirrelObject &val) +{ + bool ret = false; + int top = sq_gettop(vm); + sq_pushobject(vm,_o); + sq_pushobject(vm,key._o); + sq_pushobject(vm,val._o); + if(SQ_SUCCEEDED(sq_rawset(vm,-3))) { + ret = true; + } + sq_settop(vm,top); + return ret; +} + +#define _SETVALUE_STR_BEGIN \ + bool ret = false; \ + int top = sq_gettop(vm); \ + sq_pushobject(vm,_o); \ + sq_pushstring(vm,key,-1); + +#define _SETVALUE_STR_END \ + if(SQ_SUCCEEDED(sq_rawset(vm,-3))) { \ + ret = true; \ + } \ + sq_settop(vm,top); \ + return ret; + +bool SquirrelObject::SetValue(const SQChar *key,const SquirrelObject &val) +{ + _SETVALUE_STR_BEGIN + sq_pushobject(vm,val._o); + _SETVALUE_STR_END +} + +bool SquirrelObject::SetValue(const SQChar *key,int n) +{ + _SETVALUE_STR_BEGIN + sq_pushinteger(vm,n); + _SETVALUE_STR_END +} + +bool SquirrelObject::SetValue(const SQChar *key,float f) +{ + _SETVALUE_STR_BEGIN + sq_pushfloat(vm,f); + _SETVALUE_STR_END +} + +bool SquirrelObject::SetValue(const SQChar *key,const SQChar *s) +{ + _SETVALUE_STR_BEGIN + sq_pushstring(vm,s,-1); + _SETVALUE_STR_END +} + +bool SquirrelObject::SetValue(const SQChar *key,bool b) +{ + _SETVALUE_STR_BEGIN + sq_pushbool(vm,b); + _SETVALUE_STR_END +} + + +SQObjectType SquirrelObject::GetType() +{ + return _o._type; +} + +bool SquirrelObject::GetSlot(int key) const +{ + sq_pushobject(vm,_o); + sq_pushinteger(vm,key); + if(SQ_SUCCEEDED(sq_get(vm,-2))) { + return true; + } + + return false; +} + + +SquirrelObject SquirrelObject::GetValue(int key)const +{ + SquirrelObject ret(vm); + if(GetSlot(key)) { + ret.AttachToStackObject(-1); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret; +} + +float SquirrelObject::GetFloat(int key) const +{ + float ret = 0.0f; + if(GetSlot(key)) { + sq_getfloat(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret; +} + +int SquirrelObject::GetInt(int key) const +{ + SQInteger ret = 0; + if(GetSlot(key)) { + sq_getinteger(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return (int)ret; +} + +const SQChar *SquirrelObject::GetString(int key) const +{ + const SQChar *ret = 0; + if(GetSlot(key)) { + sq_getstring(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret; +} + +bool SquirrelObject::GetBool(int key) const +{ + SQBool ret = false; + if(GetSlot(key)) { + sq_getbool(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret?true:false; +} + +bool SquirrelObject::Exists(const SQChar *key) const +{ + bool ret = false; + if(GetSlot(key)) { + ret = true; + } + sq_pop(vm,1); + return ret; +} +//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +bool SquirrelObject::GetSlot(const SQChar *name) const +{ + sq_pushobject(vm,_o); + sq_pushstring(vm,name,-1); + if(SQ_SUCCEEDED(sq_get(vm,-2))) { + return true; + } + + return false; +} + +SquirrelObject SquirrelObject::GetValue(const SQChar *key)const +{ + SquirrelObject ret(vm); + if(GetSlot(key)) { + ret.AttachToStackObject(-1); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret; +} + +float SquirrelObject::GetFloat(const SQChar *key) const +{ + float ret = 0.0f; + if(GetSlot(key)) { + sq_getfloat(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret; +} + +int SquirrelObject::GetInt(const SQChar *key) const +{ + SQInteger ret = 0; + if(GetSlot(key)) { + sq_getinteger(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return (int)ret; +} + +const SQChar *SquirrelObject::GetString(const SQChar *key) const +{ + const SQChar *ret = 0; + if(GetSlot(key)) { + sq_getstring(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret; +} + +bool SquirrelObject::GetBool(const SQChar *key) const +{ + SQBool ret = false; + if(GetSlot(key)) { + sq_getbool(vm,-1,&ret); + sq_pop(vm,1); + } + sq_pop(vm,1); + return ret?true:false; +} + +SQUserPointer SquirrelObject::GetInstanceUP(SQUserPointer tag) const +{ + SQUserPointer up = 0; + sq_pushobject(vm,_o); + sq_getinstanceup(vm,-1,(SQUserPointer*)&up,(SQUserPointer)tag); + sq_pop(vm,1); + return up; +} + +bool SquirrelObject::SetInstanceUP(SQUserPointer up) +{ + if(!sq_isinstance(_o)) return false; + sq_pushobject(vm,_o); + sq_setinstanceup(vm,-1,up); + sq_pop(vm,1); + return true; +} + +SquirrelObject SquirrelObject::GetAttributes(const SQChar *key) +{ + SquirrelObject ret(vm); + int top = sq_gettop(vm); + sq_pushobject(vm,_o); + if(key) + sq_pushstring(vm,key,-1); + else + sq_pushnull(vm); + if(SQ_SUCCEEDED(sq_getattributes(vm,-2))) { + ret.AttachToStackObject(-1); + } + sq_settop(vm,top); + return ret; +} + +bool SquirrelObject::BeginIteration() +{ + if(!sq_istable(_o) && !sq_isarray(_o) && !sq_isclass(_o)) + return false; + sq_pushobject(vm,_o); + sq_pushnull(vm); + return true; +} + +bool SquirrelObject::Next(SquirrelObject &key,SquirrelObject &val) +{ + if(SQ_SUCCEEDED(sq_next(vm,-2))) { + key.AttachToStackObject(-2); + val.AttachToStackObject(-1); + sq_pop(vm,2); + return true; + } + return false; +} + +const SQChar* SquirrelObject::ToString() +{ + return sq_objtostring(&_o); +} + +SQInteger SquirrelObject::ToInteger() +{ + return sq_objtointeger(&_o); +} + +SQFloat SquirrelObject::ToFloat() +{ + return sq_objtofloat(&_o); +} + +bool SquirrelObject::ToBool() +{ + //<> + return _o._unVal.nInteger?true:false; +} + +void SquirrelObject::EndIteration() +{ + sq_pop(vm,2); +} diff --git a/include/modules/script_squirrel/cobject/uc_binding.cpp b/include/modules/script_squirrel/cobject/uc_binding.cpp new file mode 100644 index 0000000..6074c3b --- /dev/null +++ b/include/modules/script_squirrel/cobject/uc_binding.cpp @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/cobject/geometry_template_decl.h" + #include "script_squirrel/cobject/cobject_decl.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "script_squirrel/cobject/vector_decl.h" + #include "script_squirrel/cobject/uv_decl.h" + + +//------------------------------------------------------------------------------ +void RegisterUCBinding(HSQUIRRELVM vm) +{ + // Engine types wrapper object. + _INIT_CLASS(vm, CObject) + + // VM owned objects. + _INIT_CLASS(vm, GeometryTemplate) + + _INIT_CLASS(vm, Matrix3) + _INIT_CLASS(vm, Matrix4) + _INIT_CLASS(vm, Vector) + + _INIT_CLASS(vm, UV) +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/cobject/uv_impl.cpp b/include/modules/script_squirrel/cobject/uv_impl.cpp new file mode 100644 index 0000000..11fa195 --- /dev/null +++ b/include/modules/script_squirrel/cobject/uv_impl.cpp @@ -0,0 +1,122 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/cobject/uv_decl.h" + #include "script_squirrel/cobject/vector_decl.h" + + using namespace GS; + +#ifndef _T + #define _T +#endif + + +_IMPL_NATIVE_CONSTRUCTION(UV, GS::Vector2); + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(UV, constructor) + Vector2 temp; + int nparams = sa.GetParamCount(); + + switch (nparams) + { + case 1: temp.Set(0, 0); break; + case 2: + if (sa.GetType(2) == OT_INSTANCE) + { + _GetTypedParam(uv, 2, Vector2, UV); + if (uv) + temp = *uv; + else return sa.ThrowError("Invalid instance type"); + } + else temp.Set(sa.GetFloat(2), 0); + break; + case 3: temp.Set(sa.GetFloat(2), sa.GetFloat(3)); break; + + default: + return sa.ThrowError("Wrong parameter count"); + } + return construct_UV(v, new Vector2(temp)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(UV, _cloned) + _GetTypedParam(uv, 2, Vector2, UV); + return construct_UV(v, new Vector2(*uv)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(UV, _set) + _GetSelf(Vector2, UV); + + const SQChar *s = sa.GetString(2); + int index = s ? s[0] : sa.GetInt(2); + + switch (index) + { + case 0: case 'u': case 'x': + return sa.Return(self->x = sa.GetFloat(3)); + case 1: case 'v': case 'y': + return sa.Return(self->y = sa.GetFloat(3)); + } + return SQ_ERROR; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(UV, _get) + _GetSelf(Vector2, UV); + const SQChar *s = sa.GetString(2); + if (s && (s[1] != 0)) + return SQ_ERROR; + int index = s && (s[1] == 0) ? s[0] : sa.GetInt(2); + + switch (index) + { + case 0: case 'u': case 'x': + return sa.Return(self->x); + case 1: case 'v': case 'y': + return sa.Return(self->y); + } + return SQ_ERROR; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(UV, Set) + _GetSelf(Vector2, UV); + switch (sa.GetParamCount()) + { + case 1: self->Set(0, 0); break; + case 2: self->Set(sa.GetFloat(2), 0); break; + case 3: self->Set(sa.GetFloat(2), sa.GetFloat(3)); break; + default: + return sa.ThrowError("Wrong parameter count"); + } + return 0; +_END_IMPL +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/*# + Topic: UV + Type: UV +#*/ + +/*# + Section: UVGeneric + Desc: Generic +#*/ +_BEGIN_CLASS(UV) + +_MEMBER_FUNCTION(UV, constructor, -1, _T(".n|xn")) +_MEMBER_FUNCTION(UV, _cloned, 2, _T(".x")) +_MEMBER_FUNCTION(UV, _set, 3, _T("xs|n")) +_MEMBER_FUNCTION(UV, _get, 2, _T("xs|n")) + + /*# + Func: Set + Proto: void:float x = 0,float y = 0 + Desc: Set UV values. + #*/ +_MEMBER_FUNCTION(UV, Set, -1, _T("xnn")) + +_END_CLASS(UV) +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/cobject/vector_impl.cpp b/include/modules/script_squirrel/cobject/vector_impl.cpp new file mode 100644 index 0000000..29f17c3 --- /dev/null +++ b/include/modules/script_squirrel/cobject/vector_impl.cpp @@ -0,0 +1,533 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "script_squirrel/cobject/vector_decl.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "math/matrix4.h" + #include "math/matrix3.h" + #include "math/vector.h" + #include "log/log.h" + + using namespace GS; + + +#ifndef _T + #define _T +#endif + +_IMPL_NATIVE_CONSTRUCTION(Vector, Vector4); + +//------------------------------------------------------------------------------ +_MEMBER_FUNCTION_IMPL(Vector, constructor) + Vector4 temp; + int nparams = sa.GetParamCount(); + + switch (nparams) + { + case 1: temp.Set(); break; + case 2: + if (sa.GetType(2) == OT_INSTANCE) + { + _GetTypedParam(vec, 2, Vector4, Vector); + if (vec) + temp = *vec; + else return sa.ThrowError("Vector() invalid instance type"); + } + else + temp.Set(sa.GetFloat(2)); + break; + case 3: temp.Set(sa.GetFloat(2), sa.GetFloat(3)); break; + case 4: temp.Set(sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4)); break; + case 5: temp.Set(sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4), sa.GetFloat(5)); break; + + default: + return sa.ThrowError("Vector wrong parameters"); + } + return construct_Vector(v, new Vector4(temp)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, _cloned) + _GetTypedParam(vec, 2, Vector4, Vector); + return construct_Vector(v, new Vector4(*vec)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, _set) + _GetSelf(Vector4, Vector); + + const SQChar *s = sa.GetString(2); + int index = s ? s[0] : sa.GetInt(2); + + switch (index) + { + case 0: case 'x': case 'r': + return sa.Return(self->x = sa.GetFloat(3)); + case 1: case 'y': case 'g': + return sa.Return(self->y = sa.GetFloat(3)); + case 2: case 'z': case 'b': + return sa.Return(self->z = sa.GetFloat(3)); + case 3: case 'w': case 'a': + return sa.Return(self->w = sa.GetFloat(3)); + } + return SQ_ERROR; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, _get) + _GetSelf(Vector4, Vector); + const SQChar *s = sa.GetString(2); + if (s && (s[1] != 0)) + return SQ_ERROR; + int index = s && (s[1] == 0) ? s[0] : sa.GetInt(2); + + switch (index) + { + case 0: case 'x': case 'r': + return sa.Return(self->x); + case 1: case 'y': case 'g': + return sa.Return(self->y); + case 2: case 'z': case 'b': + return sa.Return(self->z); + case 3: case 'w': case 'a': + return sa.Return(self->w); + } + return SQ_ERROR; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, _add) + _GetSelf(Vector4, Vector); + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { _GetTypedParam(vec, 2, Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self + *vec)) } + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Vector(v, *self + sa.GetFloat(2))); + } + return sa.ThrowError("Vector + operator: Invalid argument type.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, _sub) + _GetSelf(Vector4, Vector); + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { _GetTypedParam(vec, 2, Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self - *vec)); } + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Vector(v, *self - sa.GetFloat(2))); + } + return sa.ThrowError("Vector - operator: Invalid argument type.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, _mul) + _GetSelf(Vector4, Vector); + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { + // Vector * Vector. + _CHECK_INST_PARAM_RAW(vec, 2, Vector4, Vector); + if (vec) + _SA_RETURN_OBJECT(new_Vector(v, *self * *vec)); + // Vector * Matrix3. + _CHECK_INST_PARAM_RAW(m3, 2, Matrix3, Matrix3); + if (m3) + _SA_RETURN_OBJECT(new_Vector(v, *self * *m3)); + // Vector * Matrix4. + _CHECK_INST_PARAM_RAW(m4, 2, Matrix4, Matrix4); + if (m4) + _SA_RETURN_OBJECT(new_Vector(v, *self * *m4)); + } + break; + + case OT_INTEGER: + _SA_RETURN_OBJECT(new_Vector(v, *self * (float)sa.GetInt(2))); + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Vector(v, *self * sa.GetFloat(2))); + } + return sa.ThrowError("Vector * operator: Invalid argument type.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector,_div) + _GetSelf(Vector4, Vector); + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { _GetTypedParam(vec, 2, Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self / *vec)); } + case OT_FLOAT: + _SA_RETURN_OBJECT(new_Vector(v, *self / sa.GetFloat(2))); + } + return sa.ThrowError("Vector / operator: Invalid argument type.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Set) + _GetSelf(Vector4, Vector); + switch (sa.GetParamCount()) + { + case 1: self->Set(); break; + case 2: self->Set(sa.GetFloat(2)); break; + case 3: self->Set(sa.GetFloat(2), sa.GetFloat(3)); break; + case 4: self->Set(sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4)); break; + case 5: self->Set(sa.GetFloat(2), sa.GetFloat(3), sa.GetFloat(4), sa.GetFloat(5)); break; + default: + return sa.ThrowError("Vector Set() wrong parameters"); + } + return 0; +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Dot) + _GetSelf(Vector4, Vector); + _GetTypedParam(vec, 2, Vector4, Vector); + return sa.Return(self->Dot(*vec)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Cross) + _GetSelf(Vector4, Vector); + _GetTypedParam(vec, 2, Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, self->Cross(*vec))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, AngleWithVector) + _GetSelf(Vector4, Vector); + _GetTypedParam(vec, 2, Vector4, Vector); + return sa.Return(acosf(Types::Clamp(self->Dot(*vec), -1.f, 1.f))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Reverse) + _GetSelf(Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, self->Reversed())); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Dist) + _GetSelf(Vector4, Vector); + _GetTypedParam(vec, 2, Vector4, Vector); + return sa.Return(Vector4::Dist(*self, *vec)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Dist2) + _GetSelf(Vector4, Vector); + _GetTypedParam(vec, 2, Vector4, Vector); + return sa.Return(Vector4::Dist2(*self, *vec)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Len) + _GetSelf(Vector4, Vector); + return sa.Return(self->Len()); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Len2) + _GetSelf(Vector4, Vector); + return sa.Return(self->Len2()); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, ClampMagnitude) + _GetSelf(Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, self->ClampedMagnitude(0, sa.GetFloat(2)))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, clamp) + _GetSelf(Vector4, Vector); + Vector4 mn, mx; + if (sa.GetType(2) == OT_INSTANCE) + { _GetTypedParam(_mn, 2, Vector4, Vector); mn = *_mn; } + else mn.Set(sa.GetFloat(2), sa.GetFloat(2), sa.GetFloat(2)); + if (sa.GetType(3) == OT_INSTANCE) + { _GetTypedParam(_mx, 3, Vector4, Vector); mx = *_mx; } + else mx.Set(sa.GetFloat(3), sa.GetFloat(3), sa.GetFloat(3)); + _SA_RETURN_OBJECT(new_Vector(v, self->Clamped(mn, mx))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, ApplyMatrix) + _GetSelf(Vector4, Vector); + _CHECK_INST_PARAM_RAW(m3, 2, Matrix3, Matrix3); + if (m3) _SA_RETURN_OBJECT(new_Vector(v, *self * *m3)); + _CHECK_INST_PARAM_RAW(m4, 2, Matrix4, Matrix4); + if (m4) _SA_RETURN_OBJECT(new_Vector(v, *self * *m4)); + return sa.ThrowError("Vector::ApplyMatrix(): Invalid parameter"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, ApplyRotationMatrix) + _GetSelf(Vector4, Vector); + _CHECK_INST_PARAM_RAW(m3, 2, Matrix3, Matrix3); + if (m3) _SA_RETURN_OBJECT(new_Vector(v, *self * *m3)); + _CHECK_INST_PARAM_RAW(m4, 2, Matrix4, Matrix4); + if (m4) _SA_RETURN_OBJECT(new_Vector(v, *self * Matrix3::FromMatrix4(*m4))); + return sa.ThrowError("Vector::ApplyRotationMatrix(): Invalid parameter"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Randomize) + if (sa.GetParamCount() == 2) + _SA_RETURN_OBJECT(new_Vector(v, Vector4::Random(0, sa.GetFloat(2)))); + _SA_RETURN_OBJECT(new_Vector(v, Vector4::Random(sa.GetFloat(2), sa.GetFloat(3)))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Normalize) + _GetSelf(Vector4, Vector); + if (sa.GetParamCount() == 1) + _SA_RETURN_OBJECT(new_Vector(v, self->Normalized())) + else _SA_RETURN_OBJECT(new_Vector(v, self->Normalized() * sa.GetFloat(2))) +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Lerp) + _GetSelf(Vector4, Vector); + float k = sa.GetFloat(2), ik = 1.f - k; + _GetTypedParam(vec, 3, Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self * k + *vec * ik)); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, _cmp) + _GetSelf(Vector4, Vector); + _GetTypedParam(vec, 2, Vector4, Vector); + return sa.Return((*self) == (*vec) ? true : false); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, IsEqual) + _GetSelf(Vector4, Vector); + _GetTypedParam(vec, 2, Vector4, Vector); + float d2 = 0.0001f; + switch (sa.GetParamCount()) + { + case 2: break; + case 3: d2 = sa.GetFloat(3); break; + default: return sa.ThrowError("Vector::IsEqual() wrong parameter count"); + } + d2 *= d2; + return sa.Return(Vector4::Dist2(*self, *vec) < d2 ? true : false); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Min) + _GetSelf(Vector4, Vector); + + if ((sa.GetParamCount() == 2) || (sa.GetParamCount() == 4)) + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { _GetTypedParam(vec, 2, Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, Vector4(self->x < vec->x ? self->x : vec->x, self->y < vec->y ? self->y : vec->y, self->z < vec->z ? self->z : vec->z))); } + case OT_FLOAT: + { float x = sa.GetFloat(2), y = sa.GetFloat(3), z = sa.GetFloat(4); + _SA_RETURN_OBJECT(new_Vector(v, Vector4(self->x < x ? self->x : x, self->y < y ? self->y : y, self->z < z ? self->z : z))); } + } + return sa.ThrowError("Vector Min(): Invalid parameter list.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Max) + _GetSelf(Vector4, Vector); + if ((sa.GetParamCount() == 2) || (sa.GetParamCount() == 4)) + switch (sa.GetType(2)) + { + case OT_INSTANCE: + { _GetTypedParam(vec, 2, Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, Vector4(self->x > vec->x ? self->x : vec->x, self->y > vec->y ? self->y : vec->y, self->z > vec->z ? self->z : vec->z))); } + case OT_FLOAT: + { float x = sa.GetFloat(2), y = sa.GetFloat(3), z = sa.GetFloat(4); + _SA_RETURN_OBJECT(new_Vector(v, Vector4(self->x > x ? self->x : x, self->y > y ? self->y : y, self->z > z ? self->z : z))); } + } + return sa.ThrowError("Vector Max(): Invalid parameter list.\n"); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Scale) + _GetSelf(Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self * sa.GetFloat(2))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, AddReal) + _GetSelf(Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self + Vector4(sa.GetFloat(2), sa.GetFloat(2), sa.GetFloat(2)))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, MulReal) + _GetSelf(Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self * Vector4(sa.GetFloat(2), sa.GetFloat(2), sa.GetFloat(2)))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, SubReal) + _GetSelf(Vector4, Vector); + _SA_RETURN_OBJECT(new_Vector(v, *self - Vector4(sa.GetFloat(2), sa.GetFloat(2), sa.GetFloat(2)))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, DivReal) + _GetSelf(Vector4, Vector); + const float ik = 1.f / sa.GetFloat(2); + _SA_RETURN_OBJECT(new_Vector(v, *self * Vector4(ik, ik, ik))); +_END_IMPL + +_MEMBER_FUNCTION_IMPL(Vector, Print) + _GetSelf(Vector4, Vector); + const char *label = "Vector"; + if (sa.GetParamCount() == 2) + label = sa.GetString(2); + __LOG__ << label << ": { " << self->x << ", " << self->y << ", " << self->z << ", " << self->w << "}\n"; + return 0; +_END_IMPL + +/*# + Topic: Vector + Type: Vector +#*/ + +/*# + Section: VectorGeneric + Desc: Generic +#*/ +_BEGIN_CLASS(Vector) + + /*# + Func: Vector + Proto: Vector:float x = 0,float y = 0,float z = 0,float w = 1 + Desc: Create a new vector. + Example: local v = Vector(1, 0, 0) + #*/ +_MEMBER_FUNCTION(Vector, constructor, -1, _T(".n|xnnn")) +_MEMBER_FUNCTION(Vector, _cloned, 2, _T(".x")) +_MEMBER_FUNCTION(Vector, _set, 3, _T("xs|n")) +_MEMBER_FUNCTION(Vector, _get, 2, _T("xs|n")) +_MEMBER_FUNCTION(Vector, _add, 2, _T("xx|n")) +_MEMBER_FUNCTION(Vector, _sub, 2, _T("xx|n")) +_MEMBER_FUNCTION(Vector, _mul, 2, _T("xx|n")) +_MEMBER_FUNCTION(Vector, _div, 2, _T("xx|n")) +_MEMBER_FUNCTION(Vector, _cmp, 2, _T("xx")) + + /*# + Func: Set + Proto: void:float x = 0,float y = 0,float z = 0,float w = 1 + Desc: Set vector values. + #*/ +_MEMBER_FUNCTION(Vector, Set, -1, _T("xnnnn")) + /*# + Func: ApplyMatrix + Proto: Vector:[Matrix4|Matrix3] matrix + Desc: Transform vector by a given matrix. + #*/ +_MEMBER_FUNCTION(Vector, ApplyMatrix, 2, _T("xx")) + /*# + Func: ApplyRotationMatrix + Proto: Vector:[Matrix4|Matrix3] matrix + Desc: Transform vector by the rotation part of a given matrix. + #*/ +_MEMBER_FUNCTION(Vector, ApplyRotationMatrix, 2, _T("xx")) + +_MEMBER_FUNCTION(Vector, AddReal, 2, _T("xn")) +_MEMBER_FUNCTION(Vector, MulReal, 2, _T("xn")) +_MEMBER_FUNCTION(Vector, SubReal, 2, _T("xn")) +_MEMBER_FUNCTION(Vector, DivReal, 2, _T("xn")) +_MEMBER_FUNCTION(Vector, Scale, 2, _T("xn")) + /*# + Func: Clamp + Proto: Vector:(Vector|float) min,(Vector|float) max + Desc: Individually clamp vector components to a given range. + #*/ +_MEMBER_FUNCTION(Vector, clamp, 3, _T("x x|n x|n")) + /*# + Func: ClampMagnitude + Proto: Vector:float len + Desc: Clamp vector magnitude to a specific length. + #*/ +_MEMBER_FUNCTION(Vector, ClampMagnitude, 2, _T("xn")) + /*# + Func: Reverse + Proto: Vector: + Desc: Return the reverse vector. + #*/ +_MEMBER_FUNCTION(Vector, Reverse, 1, _T("x")) + + /*# + Func: Min + Proto: Vector:[Vector|float x,float y, float z] min + Desc: Return the smallest value of the vector component or parameter for all the vector components. + #*/ +_MEMBER_FUNCTION(Vector, Min, -2, _T("xn|xnn")) + /*# + Func: Max + Proto: Vector:[Vector|float x,float y, float z] max + Desc: Return the largest value of the vector component or parameter for all the vector components. + #*/ +_MEMBER_FUNCTION(Vector, Max, -2, _T("xn|xnn")) + + /*# + Func: Dot + Proto: float:Vector v + Desc: Return the dot product between two vectors. + #*/ +_MEMBER_FUNCTION(Vector, Dot, 2, _T("xx")) + /*# + Func: Cross + Proto: Vector:Vector v + Desc: Return the cross product between two vectors. + #*/ +_MEMBER_FUNCTION(Vector, Cross, 2, _T("xx")) + /*# + Func: Len + Proto: float:Vector v + Desc: Return the length of this vector. + #*/ +_MEMBER_FUNCTION(Vector, Len, 1, _T("x")) + /*# + Func: Len2 + Proto: float:Vector v + Desc: Return the squared length of this vector. + #*/ +_MEMBER_FUNCTION(Vector, Len2, 1, _T("x")) + /*# + Func: AngleWithVector + Proto: float:Vector v + Desc: Return the angle between two vectors. + #*/ +_MEMBER_FUNCTION(Vector, AngleWithVector, 2, _T("xx")) + + /*# + Func: Normalize + Proto: Vector:float length = 1 + Desc: Return a normalized version of this vector scaled to a constant. + #*/ +_MEMBER_FUNCTION(Vector, Normalize, -1, _T("xn")) + /*# + Func: Dist + Proto: float:Vector v + Desc: Return the distance between two vectors. + #*/ +_MEMBER_FUNCTION(Vector, Dist, 2, _T("xx")) + /*# + Func: Dist2 + Proto: float:Vector v + Desc: Return the squared distance between two vectors. + #*/ +_MEMBER_FUNCTION(Vector, Dist2, 2, _T("xx")) + /*# + Func: Lerp + Proto: float:Vector v,float t + Desc: Return a linearly interpolated vector between two vectors. + #*/ +_MEMBER_FUNCTION(Vector, Lerp, 3, _T("xnx")) + /*# + Func: Randomize + Proto: Vector:Vector v,float min,float max + Desc: Return a random vector in a given range. + #*/ +_MEMBER_FUNCTION(Vector, Randomize, -2, _T(".nn")) + + /*# + Func: IsEqual + Proto: bool:Vector v,float epsilon = 0.0001 + Desc: Test vectors for equality with a given espilon tolerance. + #*/ +_MEMBER_FUNCTION(Vector, IsEqual, -2, _T("xxn")) + /*# + Func: Print + Proto: void: + Desc: Dump this vector components to the engine log. + #*/ +_MEMBER_FUNCTION(Vector, Print, -1, _T("x")) + +_END_CLASS(Vector) + +//----------------------------------------------- +void UCBind_RegisterVector(HSQUIRRELVM vm) +//----------------------------------------------- +{ + _INIT_CLASS(vm, Vector); +} diff --git a/include/modules/script_squirrel/engine_vm.cpp b/include/modules/script_squirrel/engine_vm.cpp new file mode 100644 index 0000000..e0a65a0 --- /dev/null +++ b/include/modules/script_squirrel/engine_vm.cpp @@ -0,0 +1,142 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/engine_vm.h" + #include "script_squirrel/cobject/cobject.h" + #include "script_squirrel/cobject/cobject_decl.h" + #include "script_squirrel/legacy/squirrel_binding.h" + #include "script/scripted_object.h" + #include "script/script_variant.h" + #include "log/log.h" + + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +bool EngineVM::Open() +{ + if (!SquirrelVM::Open()) + return false; + + #define __SQ_REGISTERINT(__NAME__, __V__) sq_pushstring(vm, __NAME__, -1); sq_pushinteger(vm, __V__); sq_newslot(vm, -3, true); + + sq_pushroottable(vm); + + __SQ_REGISTERINT("objectTypeUndefined", typetag_Undefined) + __SQ_REGISTERINT("objectTypeDeleted", typetag_Deleted) + + __SQ_REGISTERINT("objectTypeEngine", typetag_Engine) + __SQ_REGISTERINT("objectTypeResourceCache", typetag_ResourceSet) + __SQ_REGISTERINT("objectTypeProject", typetag_Project) + __SQ_REGISTERINT("objectTypeRenderer", typetag_Renderer) + __SQ_REGISTERINT("objectTypeRaytracer", typetag_Raytracer) + __SQ_REGISTERINT("objectTypeMixer", typetag_Mixer) + __SQ_REGISTERINT("objectTypeScene", typetag_Scene3d) + __SQ_REGISTERINT("objectTypeClock", typetag_Clock) + + __SQ_REGISTERINT("objectTypeFont", typetag_Font) + __SQ_REGISTERINT("objectTypeRasterFont", typetag_RasterFont) + __SQ_REGISTERINT("objectTypeUI", typetag_Scene2d) + __SQ_REGISTERINT("objectTypeUICursor", typetag_UICursor) + __SQ_REGISTERINT("objectTypeWindow", typetag_Window) + __SQ_REGISTERINT("objectTypeWidget", typetag_Widget) + __SQ_REGISTERINT("objectTypeSizerWidget", typetag_SizerWidget) + __SQ_REGISTERINT("objectTypeContainerWidget", typetag_ContainerWidget) + __SQ_REGISTERINT("objectTypeSpacerWidget", typetag_SpacerWidget) + __SQ_REGISTERINT("objectTypeCanvasWidget", typetag_CanvasWidget) + __SQ_REGISTERINT("objectTypeTextWidget", typetag_TextWidget) + __SQ_REGISTERINT("objectTypeBitmapWidget", typetag_BitmapWidget) + __SQ_REGISTERINT("objectTypeCheckWidget", typetag_CheckWidget) + __SQ_REGISTERINT("objectTypePicture", typetag_Picture) + + __SQ_REGISTERINT("objectTypeGroup", typetag_Group) + __SQ_REGISTERINT("objectTypeItem", typetag_Item) + __SQ_REGISTERINT("objectTypeCamera", typetag_Camera) + __SQ_REGISTERINT("objectTypeObject", typetag_Object) + __SQ_REGISTERINT("objectTypeLight", typetag_Light) + __SQ_REGISTERINT("objectTypeInstance", typetag_Instance) + __SQ_REGISTERINT("objectTypeMotion", typetag_Motion) + __SQ_REGISTERINT("objectTypeTrigger", typetag_Trigger) + __SQ_REGISTERINT("objectTypePath", typetag_Path) + + __SQ_REGISTERINT("objectTypeSound", typetag_Sound) + __SQ_REGISTERINT("objectTypeTexture", typetag_Texture) + __SQ_REGISTERINT("objectTypeGeometry", typetag_Geometry) + __SQ_REGISTERINT("objectTypeMaterial", typetag_Material) + __SQ_REGISTERINT("objectTypeColShape", typetag_ColShape) + __SQ_REGISTERINT("objectTypeConstraint", typetag_Constraint) + + __SQ_REGISTERINT("objectTypeMetafile", typetag_Metafile) + __SQ_REGISTERINT("objectTypeMetatag", typetag_Metatag) + + __SQ_REGISTERINT("objectTypeHidDevice", typetag_InputDevice) + + __SQ_REGISTERINT("objectTypeEditorPlugin", typetag_EditorPlugin) + + __SQ_REGISTERINT("objectTypeProjectScene", typetag_ProjectScene) + __SQ_REGISTERINT("objectTypeProjectLayer", typetag_ProjectLayer) + + __SQ_REGISTERINT("objectTypeAnimationSource", typetag_AutomationSource) + __SQ_REGISTERINT("objectTypeAnimationSourceGroup", typetag_AutomationSourceGroup) + + sq_pop(vm, 1); + + _INIT_CLASS(vm, CObject); + + RegisterAllSquirrelBinding(vm); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool EngineVM::PushVariant(const Variant &v) +{ + if (v.type == Variant::Type_UserObject) + return CObject::Push(vm, v.ptr, (CObjectType)v.typetag); + return SquirrelVM::PushVariant(v); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int EngineVM::InvalidateNativeReference(void *ptr) +{ + uint invalidated_count = 0; + ListForeachPtr(CObject *, o, cobjects) + if (o->native == ptr) + { + cobjects.Remove(o); + + o->list_item = NULL; + o->type = typetag_Deleted; + o->native = NULL; + + ++invalidated_count; + } + +// __LOG_E__ << "Invalidate native object " << nString::Format("0x%x", ptr) << " - reference found: " << count << ", CObject left: " << safe_ptr_list.GetCount() << ".\n"; + return invalidated_count; +} +void EngineVM::ReleaseAllNativeReferences() +{ + ListForeachPtr(CObject *, o, cobjects) + o->Release(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void EngineVM::Close() +{ + /* + [EJ] We have to drop all native object references now. If we don't, + native objects holding a reference to a script object will crash the VM + when they try to release it from their destructor (hence making a + reentrant call into the VM). + */ + ReleaseAllNativeReferences(); + + SquirrelVM::Close(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/engine_vm_debugger.cpp b/include/modules/script_squirrel/engine_vm_debugger.cpp new file mode 100644 index 0000000..1fa4a47 --- /dev/null +++ b/include/modules/script_squirrel/engine_vm_debugger.cpp @@ -0,0 +1,161 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/engine_vm_debugger.h" + #include "script_squirrel/cobject/vector_decl.h" + #include "script_squirrel/cobject/cobject.h" + #include "script_squirrel/engine_vm.h" + #include "core/sound.h" + #include "motion/motion.h" + #include "scene3d/group.h" + #include "scene3d/mobject.h" + #include "scene3d/mlight.h" + #include "scene3d/mcamera.h" + #include "scene3d/mtrigger.h" + #include "scene3d/scene.h" + #include "project/project.h" + #include "script/script_profiler.h" + #include "script/scripted_object.h" + #include "raytracer/raytracer_core.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +String SquirrelDebugger::FormatUserObjectParameter(CObjectType type) +{ + // Check for null safe ptr. + void *test; + CObject::Get(vm, -1, &test); + if (!test) + return "Null"; + + // Get type specific data. + switch (type) + { + case typetag_Group: + { + S3D::Group *group; + CObject::Get(vm, -1, (void **)&group, type); + return String::Format("(id='%s', items=%d, ...)", group->name.c_str(), group->GetItemList().GetCount()); + } + case typetag_Motion: + { + Core::Motion *motion; + CObject::Get(vm, -1, (void **)&motion, type); + return String::Format("(id='%s', channels=%d, length=%.2fs, ...)", motion->name.c_str(), motion->GetChannelList().GetCount(), motion->GetDuration().toSec()); + } + case typetag_Geometry: + { + Render::Geometry *geometry; + CObject::Get(vm, -1, (void **)&geometry, type); + return String::Format("(id='%s', vertex=%d, material=%d, ...)", geometry->name.c_str(), geometry->material_table.GetCount()); + } + case typetag_Picture: + { + Picture *picture; + CObject::Get(vm, -1, (void **)&picture, type); + return String::Format("(w=%dpx, h=%dpx, ...)", picture->GetWidth(), picture->GetHeight()); + } + case typetag_Texture: + { + Render::Texture *texture; + CObject::Get(vm, -1, (void **)&texture, type); + return String::Format("(id='%s', w=%dpx, h=%dpx, ...)", texture->name.c_str(), texture->GetWidth(), texture->GetHeight()); + } + case typetag_Sound: + { + Audio::Sound *sound; + CObject::Get(vm, -1, (void **)&sound, type); + return String::Format("(id='%s')", sound->name.c_str()); + } + case typetag_Object: + { + S3D::MObject *object; + CObject::Get(vm, -1, (void **)&object, type); + return String::Format("(id='%s', uid=%d, geometry='%s', ...)", object->name.c_str(), object->GetUid(), object->geometry.IsEmpty() ? "None" : object->geometry.c_str()); + } + case typetag_Light: + { + S3D::MLight *light; + CObject::Get(vm, -1, (void **)&light, type); + return String::Format("(id='%s', uid=%d, diffuse=%.2f, specular=%.2f, ...)", light->name.toUtf8(), light->GetUid(), light->diffuse_intensity, light->specular_intensity); + } + case typetag_Camera: + { + S3D::MCamera *camera; + CObject::Get(vm, -1, (void **)&camera, type); + return String::Format("(id='%s', uid=%d, fov=%.2f, ...)", camera->name.toUtf8(), camera->GetUid(), camera->GetFov()); + } + case typetag_Trigger: + { + S3D::MTrigger *trigger; + CObject::Get(vm, -1, (void **)&trigger, type); + return String::Format("(id='%s', uid=%d, ...)", trigger->name.toUtf8(), trigger->GetUid()); + } + case typetag_Scene3d: + { + S3D::Scene *scene; + CObject::Get(vm, -1, (void **)&scene, type); + return String::Format("(id='%s', items=%d, ...)", scene->name.toUtf8(), scene->GetItemList().GetCount()); + } + case typetag_Item: + { + S3D::MItem *item; + CObject::Get(vm, -1, (void **)&item, type); + return String::Format("(id='%s', uid=%d, scripted=%s, ...)", item->name.toUtf8(), item->GetUid(), item->scripted_object.IsValid() && item->scripted_object->GetUnitList().GetCount() ? "True" : "False"); + } + case typetag_Raytracer: + { + Raytrace::Raytracer *ray; + CObject::Get(vm, -1, (void **)&ray, type); + Raytrace::Configuration cfg = ray->GetConfiguration(); + return String::Format("(aa=%s, gi=%s, interlaced=%s, ...)", cfg.trace_aa ? "True" : "False", cfg.trace_gi ? "True" : "False", cfg.interlaced ? "True" : "False"); + } + case typetag_Material: + { + Render::Material *material; + CObject::Get(vm, -1, (void **)&material, type); + return String::Format("(id='%s', ...)", material->name.toUtf8()); + } + case typetag_Metafile: + { + NML::File *metafile; + CObject::Get(vm, -1, (void **)&metafile, type); + return String::Format("(path='%s', ...)", metafile->name.toUtf8()); + } + case typetag_Metatag: + { + NML::Tag *metatag; + CObject::Get(vm, -1, (void **)&metatag, type); + return String::Format("(id='%s', ...)", metatag->name.toUtf8()); + } + case typetag_ColShape: + { + S3D::PhysicShape *shape; + CObject::Get(vm, -1, (void **)&shape, type); + + String _type = "..."; + switch (shape->GetType()) + { + case S3D::PhysicShape::TypeBox: _type = "Box"; break; + case S3D::PhysicShape::TypeCone: _type = "Cone"; break; + case S3D::PhysicShape::TypeSphere: _type = "Sphere"; break; + case S3D::PhysicShape::TypeConvex: _type = "Convex"; break; + case S3D::PhysicShape::TypeMesh: _type = "Mesh"; break; + + default: break; + } + return String::Format("(type=%s, mass=%.2f, ...)", _type.toUtf8(), shape->mass); + } + default: break; + } + return String("..."); +} +//------------------------------------------------------------------------------ + +EngineDebugger::EngineDebugger(EngineVM &vm) : SquirrelDebugger(vm) {} \ No newline at end of file diff --git a/include/modules/script_squirrel/engine_vm_profiler.cpp b/include/modules/script_squirrel/engine_vm_profiler.cpp new file mode 100644 index 0000000..8a4d57e --- /dev/null +++ b/include/modules/script_squirrel/engine_vm_profiler.cpp @@ -0,0 +1,9 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/engine_vm_profiler.h" + + using namespace GS::Script; diff --git a/include/modules/script_squirrel/legacy/ai_binding.cpp b/include/modules/script_squirrel/legacy/ai_binding.cpp new file mode 100644 index 0000000..6db9116 --- /dev/null +++ b/include/modules/script_squirrel/legacy/ai_binding.cpp @@ -0,0 +1,23 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + + +//------------------------------------------- +void RegisterAIBinding(HSQUIRRELVM vm) +//------------------------------------------- +{ +/*# + Topic: AI + Type: Path +#*/ + +/*# + Section: AIPath + Desc: AI Path functions +#*/ +} diff --git a/include/modules/script_squirrel/legacy/animation_binding.cpp b/include/modules/script_squirrel/legacy/animation_binding.cpp new file mode 100644 index 0000000..91ada11 --- /dev/null +++ b/include/modules/script_squirrel/legacy/animation_binding.cpp @@ -0,0 +1,419 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "squirrel_binding.h" + #include "binding_helpers.h" + #include "motion/motion.h" + #include "automation/automation_source_group.h" + #include "automation/automation_player.h" + + using namespace GS; + using namespace GS::Script; + using namespace GS::Automation; + + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceSetLoopMode(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETINT(loop_mode) + __SQ_GETEND + source->SetLoopMode((Curve::LoopMode)loop_mode); + __SQ_RETURN +} +SQInteger AnimationSourceSetLoop(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETFLOAT(loop_start) + __SQ_GETFLOAT(loop_end) + __SQ_GETEND + source->SetLoop(Time::fromSec(loop_start), Time::fromSec(loop_end)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceGetClock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(source, Source, typetag_AutomationSource) + __SQ_RETURNFLOAT(source->time.toSec()) +} +SQInteger AnimationSourceSetClock(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETFLOAT(time) + __SQ_GETEND + source->time = Time::fromSec(time); + __SQ_RETURN +} +SQInteger AnimationSourceGetClockScale(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(source, Source, typetag_AutomationSource) + __SQ_RETURNFLOAT(source->time_scale) +} +SQInteger AnimationSourceSetClockScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETFLOAT(scale) + __SQ_GETEND + source->time_scale = scale; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceIsRelative(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(source, Source, typetag_AutomationSource) + __SQ_RETURNBOOL(source->relative); +} +SQInteger AnimationSourceSetRelative(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETBOOL(relative) + __SQ_GETEND + source->relative = asbool(relative); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceSetWeight(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETFLOAT(weight) + __SQ_GETFLOAT(blend) + __SQ_GETEND + source->SetWeight(weight, blend); + __SQ_RETURN +} +SQInteger AnimationSourceStop(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETFLOAT(blend) + __SQ_GETEND + source->Dispose(blend); + __SQ_RETURN +} +SQInteger AnimationSourceIsDone(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(source, Source, typetag_AutomationSource) + __SQ_RETURNBOOL(source->IsDone()); +} +//------------------------------------------------------------------------------ + +// Group + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceGroupGetSourceCount(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_RETURNINT(group->source_list.GetCount()) +} +SQInteger AnimationSourceGroupGetSource(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETINT(index) + __SQ_GETEND + __SQ_RETURNSAFEPTR(group->source_list[index], typetag_AutomationSource) +} +SQInteger AnimationSourceGroupAddSource(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETSAFEPTR(source, Source, typetag_AutomationSource) + __SQ_GETEND + group->source_list.Add(source); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceGroupSetLoopMode(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETINT(loop_mode) + __SQ_GETEND + group->SetLoopMode((Curve::LoopMode)loop_mode); + __SQ_RETURN +} +SQInteger AnimationSourceGroupSetLoop(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETFLOAT(loop_start) + __SQ_GETFLOAT(loop_end) + __SQ_GETEND + group->SetLoop(Time::fromSec(loop_start), Time::fromSec(loop_end)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceGroupGetClock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + if (group->source_list.GetCount() == 0) + return sq_throwerror(vm, "No animation source in group"); + __SQ_RETURNFLOAT(group->source_list[0]->time.toSec()) +} +SQInteger AnimationSourceGroupSetClock(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETFLOAT(time) + __SQ_GETEND + group->SetTime(Time::fromSec(time)); + __SQ_RETURN +} +SQInteger AnimationSourceGroupGetClockScale(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + if (group->source_list.GetCount() == 0) + return sq_throwerror(vm, "No animation source in group"); + __SQ_RETURNFLOAT(group->source_list[0]->time_scale) +} +SQInteger AnimationSourceGroupSetClockScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETFLOAT(scale) + __SQ_GETEND + group->SetTimeScale(scale); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceGroupSetRelative(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETBOOL(relative) + __SQ_GETEND + group->SetRelative(asbool(relative)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger AnimationSourceGroupSetWeight(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETFLOAT(weight) + __SQ_GETFLOAT(blend) + __SQ_GETEND + group->SetWeight(weight, blend); + __SQ_RETURN +} +SQInteger AnimationSourceGroupStop(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_GETFLOAT(blend) + __SQ_GETEND + group->Dispose(blend); + __SQ_RETURN +} +SQInteger AnimationSourceGroupIsDone(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, SourceGroup, typetag_AutomationSourceGroup) + __SQ_RETURNBOOL(group->IsDone()); +} +//------------------------------------------------------------------------------ + +//-------------------------------------------------- +void RegisterAnimationBinding(HSQUIRRELVM vm) +//-------------------------------------------------- +{ +/*# + Topic: Animation + Type: AnimationSourceGroup + Type: AnimationSource +#*/ + +/*# + Section: Animation Source + Desc: Provides control over an animation source. +#*/ + /*# + Func: AnimationSourceSetLoopMode + Proto: void:AnimationSource, AnimationLoopMode mode + Desc: Set animation source loop mode. + #*/ + sq_register(vm, AnimationSourceSetLoopMode, "AnimationSourceSetLoopMode", _SC(".xi")); + /*# + Func: AnimationSourceSetLoop + Proto: void:AnimationSource, float loop_start, float loop_end + Desc: Set animation source loop point. + #*/ + sq_register(vm, AnimationSourceSetLoop, "AnimationSourceSetLoop", _SC(".xnn")); + /*# + Func: AnimationSourceGetClock + Proto: float:AnimationSource + Desc: Get animation source clock. + #*/ + sq_register(vm, AnimationSourceGetClock, "AnimationSourceGetClock", _SC(".x")); + /*# + Func: AnimationSourceSetClock + Proto: void:AnimationSource, float clock + Desc: Set animation source clock. + #*/ + sq_register(vm, AnimationSourceSetClock, "AnimationSourceSetClock", _SC(".xn")); + /*# + Func: AnimationSourceGetClockScale + Proto: float:AnimationSource + Desc: Get animation source clock scale. + #*/ + sq_register(vm, AnimationSourceGetClockScale, "AnimationSourceGetClockScale", _SC(".x")); + /*# + Func: AnimationSourceSetClockScale + Proto: void:AnimationSource, float clock_scale + Desc: Set animation source clock scale. + #*/ + sq_register(vm, AnimationSourceSetClockScale, "AnimationSourceSetClockScale", _SC(".xn")); + /*# + Func: AnimationSourceSetWeight + Proto: void:AnimationSource, float weight, float blend + Desc: Set animation source weight and weight blend duration. + #*/ + sq_register(vm, AnimationSourceSetWeight, "AnimationSourceSetWeight", _SC(".xnn")); + /*# + Func: AnimationSourceIsRelative + Proto: bool:AnimationSource + Desc: Return the animation source evaluation mode.. + #*/ + sq_register(vm, AnimationSourceIsRelative, "AnimationSourceIsRelative", _SC(".x")); + /*# + Func: AnimationSourceSetRelative + Proto: void:AnimationSource, bool relative + Desc: Set animation source evaluation mode to relative instead of absolute.
Relative source offsets the value they modify instead of replacing it. + #*/ + sq_register(vm, AnimationSourceSetRelative, "AnimationSourceSetRelative", _SC(".xb")); + /*# + Func: AnimationSourceStop + Proto: void:AnimationSource, float blend + Desc: Stop an animation source. The motion weight can be brought down to 0 over a given blend duration before the source is stopped. + #*/ + sq_register(vm, AnimationSourceStop, "AnimationSourceStop", _SC(".xn")); + /*# + Func: AnimationSourceIsDone + Proto: bool:AnimationSource + Desc: Returns true if this animation source is done playing. + #*/ + sq_register(vm, AnimationSourceIsDone, "AnimationSourceIsDone", _SC(".x")); + +/*# + Section: Animation Source Group + Desc: Provides control over a group of animation sources. +#*/ + /*# + Func: AnimationSourceGroupGetSourceCount + Proto: int:AnimationSourceGroup + Desc: Return the number of animation sources in this group. + #*/ + sq_register(vm, AnimationSourceGroupGetSourceCount, "AnimationSourceGroupGetSourceCount", _SC(".x")); + /*# + Func: AnimationSourceGroupGetSource + Proto: AnimationSource:AnimationSourceGroup, int index + Desc: Return an animation source from the group. + #*/ + sq_register(vm, AnimationSourceGroupGetSource, "AnimationSourceGroupGetSource", _SC(".xi")); + /*# + Func: AnimationSourceGroupAddSource + Proto: void:AnimationSourceGroup, AnimationSource + Desc: Add an animation source to the group. + #*/ + sq_register(vm, AnimationSourceGroupAddSource, "AnimationSourceGroupAddSource", _SC(".xx")); + /*# + Func: AnimationSourceGroupSetLoopMode + Proto: void:AnimationSourceGroup, AnimationLoopMode mode + Desc: Set animation source group loop mode. + #*/ + sq_register(vm, AnimationSourceGroupSetLoopMode, "AnimationSourceGroupSetLoopMode", _SC(".xi")); + /*# + Func: AnimationSourceGroupSetLoop + Proto: void:AnimationSourceGroup, float loop_start, float loop_end + Desc: Set animation source group loop point. + #*/ + sq_register(vm, AnimationSourceGroupSetLoop, "AnimationSourceGroupSetLoop", _SC(".xnn")); + + /*# + Func: AnimationSourceGroupGetClock + Proto: float:AnimationSourceGroup + Desc: Get animation source group clock. + #*/ + sq_register(vm, AnimationSourceGroupGetClock, "AnimationSourceGroupGetClock", _SC(".x")); + /*# + Func: AnimationSourceGroupSetClock + Proto: void:AnimationSourceGroup, float clock + Desc: Set animation source group clock. + #*/ + sq_register(vm, AnimationSourceGroupSetClock, "AnimationSourceGroupSetClock", _SC(".xn")); + + /*# + Func: AnimationSourceGroupGetClockScale + Proto: float:AnimationSourceGroup + Desc: Get animation source group clock scale. + #*/ + sq_register(vm, AnimationSourceGroupGetClockScale, "AnimationSourceGroupGetClockScale", _SC(".x")); + /*# + Func: AnimationSourceGroupSetClockScale + Proto: void:AnimationSourceGroup, float clock_scale + Desc: Set animation source group clock scale. + #*/ + sq_register(vm, AnimationSourceGroupSetClockScale, "AnimationSourceGroupSetClockScale", _SC(".xn")); + + /*# + Func: AnimationSourceGroupSetWeight + Proto: void:AnimationSourceGroup, float weight, float blend + Desc: Set animation source group weight and weight blend duration. + #*/ + sq_register(vm, AnimationSourceGroupSetWeight, "AnimationSourceGroupSetWeight", _SC(".xnn")); + /*# + Func: AnimationSourceGroupSetRelative + Proto: void:AnimationSourceGroup, bool relative + Desc: Set animation source evaluation mode to relative instead of absolute.
Relative source offsets the value they modify instead of replacing it. + #*/ + sq_register(vm, AnimationSourceGroupSetRelative, "AnimationSourceGroupSetRelative", _SC(".xb")); + /*# + Func: AnimationSourceGroupStop + Proto: void:AnimationSourceGroup, float blend + Desc: Stop an animation source group. The motion weight can be brought down to 0 over a given blend duration before the source group is stopped. + #*/ + sq_register(vm, AnimationSourceGroupStop, "AnimationSourceGroupStop", _SC(".xn")); + /*# + Func: AnimationSourceGroupIsDone + Proto: bool:AnimationSourceGroup + Desc: Returns true if this animation source group is done playing. + #*/ + sq_register(vm, AnimationSourceGroupIsDone, "AnimationSourceGroupIsDone", _SC(".x")); + + // Push defines. + sq_pushroottable(vm); + + /*# + Enum: AnimationLoopMode + Values: AnimationConstant,AnimationRepeat,AnimationReset,AnimationOffsetRepeat,AnimationOscillate + #*/ + sq_pushstring(vm, "AnimationConstant", -1); sq_pushinteger(vm, Curve::Constant); sq_newslot(vm, -3, true); + sq_pushstring(vm, "AnimationRepeat", -1); sq_pushinteger(vm, Curve::Repeat); sq_newslot(vm, -3, true); + sq_pushstring(vm, "AnimationReset", -1); sq_pushinteger(vm, Curve::Reset); sq_newslot(vm, -3, true); + sq_pushstring(vm, "AnimationOffsetRepeat", -1); sq_pushinteger(vm, Curve::OffsetAndRepeat); sq_newslot(vm, -3, true); + sq_pushstring(vm, "AnimationOscillate", -1); sq_pushinteger(vm, Curve::Oscillate); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/camera_binding.cpp b/include/modules/script_squirrel/legacy/camera_binding.cpp new file mode 100644 index 0000000..b71e99b --- /dev/null +++ b/include/modules/script_squirrel/legacy/camera_binding.cpp @@ -0,0 +1,421 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "scene3d/scene.h" + #include "scene3d/mobject.h" + #include "scene3d/mcamera.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "core/renderer.h" + #include "math/vector.h" + + using namespace GS; + using namespace GS::S3D; + using namespace GS::Script; + + +static CObjectType camera_derived_types[] = { typetag_Item, typetag_Camera, typetag_Undefined }; +static CObjectType object_derived_types[] = { typetag_Item, typetag_Object, typetag_Undefined }; + +//------------------------------------------------------------------------------ +SQInteger CameraGetItem(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(cam, MCamera, typetag_Camera) + __SQ_RETURNSAFEPTR((MItem *)cam, typetag_Item) +} +SQInteger CameraGetFov(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types)) + __SQ_RETURNFLOAT(c->GetFov()) +} +SQInteger CameraSetFov(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETFLOAT(f) + __SQ_GETEND + c->SetFov(f); + __SQ_RETURN +} +SQInteger CameraGetZoomFactor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types)) + __SQ_RETURNFLOAT(c->zoom_factor) +} +SQInteger CameraSetZoomFactor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETFLOAT(z) + __SQ_GETEND + c->SetZoomFactor(z); + __SQ_RETURN +} +SQInteger CameraSetFStop(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETFLOAT(f) + __SQ_GETEND + c->registry.CreateKey("PostProcess:Dof:FStop", f); + __SQ_RETURN +} +SQInteger CameraSetFocalDistance(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETFLOAT(f) + __SQ_GETEND + c->registry.CreateKey("PostProcess:Dof:FDist", f); + __SQ_RETURN +} +SQInteger CameraGetVisibleItems(HSQUIRRELVM vm) { + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETEND + + sq_newarray(vm, 0); + Vector4 cameraPos = c->GetMatrix().GetRow(3); + Vector4 cameraForward = c->GetMatrix().GetRow(2); // Camera's forward vector + + ListForeachPtr(MItem *, item, scene->GetItemList()) { + if (item->GetItemType() == Type_Object) { + if (MObject *o = (MObject *)item) { + if (o->render_data.IsValid() && o->render_data->geometry.IsValid()) { + Vector4 objectPos = o->GetMatrix().GetRow(3); + Vector4 toObject = objectPos - cameraPos; + + // Skip this object if it's too far + float distance = toObject.Len(); + if (distance > 500) { + continue; + } + + // Check if object is in front of the camera + float dot = toObject.x * cameraForward.x + toObject.y * cameraForward.y + toObject.z * cameraForward.z; + if (dot > 0) { + // Perform frustum culling + Frustum::Visibility vis = c->frustum.ClassifyMinMax(o->render_data->geometry->minmax, &o->GetMatrix()); + if (vis != Frustum::Outside) { + CObject::Push(vm, (void *)item, typetag_Item); + sq_arrayappend(vm, -2); + } + } + } + } + } + } + return 1; +} +/* +SQInteger CameraComputeProjectionMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETFRECT(viewport) + __SQ_GETEND + Matrix4 projection_matrix; + c->ComputeProjectionMatrix(viewport, projection_matrix); + __SQ_RETURNMATRIX4(projection_matrix) +} +*/ +SQInteger CameraSetAspectRatio(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETFLOAT(v) + __SQ_GETEND + c->aspect_ratio = v; + __SQ_RETURN +} +SQInteger CameraGetAspectRatio(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types)) + __SQ_RETURNFLOAT(c->aspect_ratio) +} +SQInteger CameraSetAspectRatioRefAxis(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETBOOL(v) + __SQ_GETEND + c->aspect_ratio_ref_yaxis = asbool(v); + __SQ_RETURN +} +SQInteger CameraSetClipping(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETFLOAT(n) + __SQ_GETFLOAT(f) + __SQ_GETEND + c->z_near = n; + c->z_far = f; + __SQ_RETURN +} + +SQInteger CameraGetZNear(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETEND + __SQ_RETURNFLOAT(c->z_near) +} + +SQInteger CameraGetZFar(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETEND + __SQ_RETURNFLOAT(c->z_far) +} + + +SQInteger CameraCullObject(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETCOBJECTBASE(o, MObject, object_derived_types) + __SQ_GETEND + + Frustum::Visibility vis = Frustum::Outside; + if (o->render_data.IsValid() && o->render_data->geometry.IsValid()) + vis = c->frustum.ClassifyMinMax(o->render_data->geometry->minmax, &o->GetMatrix()); + + __SQ_RETURNINT(int(vis)) +} +SQInteger CameraCullPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETEND + __SQ_RETURNINT(int(c->frustum.ClassifySet(1, &p))) +} + +SQInteger CameraGetFrustumVertices(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETEND + + const Vector4* vtx = c->frustum.GetVertices(); + + sq_newarray(vm, 0); + + for (int i = 0; i < 8; ++i) + { + PushVector(vm, vtx[i], false); + sq_arrayappend(vm, -2); + } + + return 1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger CameraWorldToScreen(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETVECTOR(world) + __SQ_GETEND + Vector4 screen; + if (!c->WorldToScreen(renderer->GetViewport(), world, screen)) + screen.Set(-1, -1, -1, -1); + __SQ_RETURNVECTOR(screen) +} +SQInteger CameraScreenToWorld(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + __SQ_RETURNVECTOR(c->ScreenToWorld(renderer->GetViewport(), x, y)) +} +SQInteger CameraScreenToWorldPlane(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETCOBJECTBASE(c, MCamera, camera_derived_types) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETFLOAT(z) + __SQ_GETEND + __SQ_RETURNVECTOR(c->ScreenToWorld(renderer->GetViewport(), x, y, z)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------- +void RegisterCameraBinding(HSQUIRRELVM vm) +//------------------------------------------------------- +{ +/*# + Topic: Camera + Type: Camera + Related: Item +#*/ + +/*# + Section: CameraGeneric + Desc: Generic functions +#*/ + /*# + Func: CameraGetItem + Proto: Item:Camera + Example: local camera_item = CameraGetItem(camera) + Desc: Return camera item. + #*/ + sq_register(vm, CameraGetItem, "CameraGetItem", _SC(".x")); + +/*# + Section: CameraAR + Desc: Aspect ratio functions. +#*/ + /*# + Func: CameraSetAspectRatio + Proto: void:Camera,float aspect_ratio + Desc: Set camera aspect ratio. + #*/ + sq_register(vm, CameraSetAspectRatio, "CameraSetAspectRatio", _SC(".xn")); + /*# + Func: CameraGetAspectRatio + Proto: float:Camera + Desc: Get camera aspect ratio. + #*/ + sq_register(vm, CameraGetAspectRatio, "CameraGetAspectRatio", _SC(".x")); + /*# + Func: CameraSetAspectRatioRefAxis + Proto: void:Camera,bool use_Y_axis + Desc: Set camera aspect ratio correction to be done on the vertical screen axis (Y) instead of the horizontal axis (X). + #*/ + sq_register(vm, CameraSetAspectRatioRefAxis, "CameraSetAspectRatioRefAxis", _SC(".xb")); + +/*# + Section: CameraViewport + Desc: Viewport functions +#*/ + /*# + Func: CameraCullObject + Proto: VisibilityFlags:Camera camera_to_cull_against,Object object_to_cull + Desc: Cull an object against the camera frustum. Returns a visibility flag mask. + #*/ + sq_register(vm, CameraCullObject, "CameraCullObject", _SC(".xx")); + /*# + Func: CameraCullPosition + Proto: VisibilityFlags:Camera camera_to_cull_against,Vector world_position + Desc: Cull a position in world space against the camera frustum. Returns a visibility flag mask. + #*/ + sq_register(vm, CameraCullPosition, "CameraCullPosition", _SC(".xx")); + + sq_register(vm, CameraGetFrustumVertices, "CameraGetFrustumVertices", _SC(".x")); + sq_register(vm, CameraGetZNear, "CameraGetZNear", _SC(".x")); + sq_register(vm, CameraGetZFar, "CameraGetZFar", _SC(".x")); + + /*# + Func: CameraGetFov + Proto: float:Camera + Desc: Get camera fov in radian. + #*/ + sq_register(vm, CameraGetFov, "CameraGetFov", _SC(".x")); + /*# + Func: CameraSetFov + Proto: void:Camera,float fov_in_radian + Example: CameraSetFov(camera, Deg(60)) + Desc: Get camera fov in radian. + #*/ + sq_register(vm, CameraSetFov, "CameraSetFov", _SC(".xn")); + + /*# + Func: CameraGetZoomFactor + Proto: float:Camera + Desc: Get camera zoom. + #*/ + sq_register(vm, CameraGetZoomFactor, "CameraGetZoomFactor", _SC(".x")); + /*# + Func: CameraSetZoomFactor + Proto: void:Camera,float zoom_factor + Example: CameraSetZoomFactor(camera, 3.2) + Desc: Set camera zoom. + #*/ + sq_register(vm, CameraSetZoomFactor, "CameraSetZoomFactor", _SC(".xn")); + + + /*# + Func: CameraSetFocalDistance + Proto: void:Camera,float distance_in_meters + Example: +// Set focus 10 meters from camera. Objects closer or father than 10 meters will appear out of focus. +CameraSetFocalDistance(camera, Mtr(10)) + Desc: Set camera focal distance, set to 0 or less to disable depth of field on the camera. + #*/ + sq_register(vm, CameraSetFocalDistance, "CameraSetFocalDistance", _SC(".xn")); + /*# + Func: CameraSetFStop + Proto: void:Camera,float fstop_in_meters + Example: CameraSetFStop(camera, Mtr(4)) + Desc: Set camera f-stop, set to 0 or less to disable depth of field on the camera. + #*/ + sq_register(vm, CameraSetFStop, "CameraSetFStop", _SC(".xn")); + /*# + Func: CameraSetClipping + Proto: void:camera,float near, float far + Example: CameraSetClipping(camera, Cm(1), Mtr(100)) + Desc: Set camera near and far clipping planes. + #*/ + sq_register(vm, CameraSetClipping, "CameraSetClipping", _SC(".xnn")); + /*# + Func: CameraWorldToScreen + Proto: vector:Camera,Renderer,Vector world_position + Example: +// Project world position {10,5,1} on the screen. +local p2d = CameraWorldToScreen(camera, g_render, Vector(10, 5, 1)) + Desc: Transform a world space position to a normalized screen space position, in the range { [0;1], [0;1] }. + #*/ + sq_register(vm, CameraWorldToScreen, "CameraWorldToScreen", _SC(".xxx")); + /*# + Func: CameraScreenToWorld + Proto: vector:Camera,Renderer,float x,float y + Example: +// Transform the middle of the screen to a 3d world position 1 meter away from the camera. +local wp = CameraScreenToWorld(camera, g_render, 0.5, 0.5) + Desc: Transform a normalized screen space position to a world space position.
+ The screen space position is the result of a projection on the Z=1 imaginary plane, situated 1 meter in front of the camera. + See: CameraScreenToWorldPlane + #*/ + sq_register(vm, CameraScreenToWorld, "CameraScreenToWorld", _SC(".xxnn")); + /*# + Func: CameraScreenToWorldPlane + Proto: vector:Camera,Renderer,float x,float y,float plane_distance_in_meters + Desc: Transform a normalized screen space position to a world space position.
+ The screen space position is the result of a projection on an imaginary plane situated in front of the camera. + #*/ + sq_register(vm, CameraScreenToWorldPlane, "CameraScreenToWorldPlane", _SC(".xxnnn")); + + sq_pushroottable(vm); + + /*# + Enum: VisibilityFlags + Desc: Reported by the visibility functions, visibility can be total, partial or null. + Values: VisibilityOutside,VisibilityClipped,VisibilityInside + #*/ + sq_pushstring(vm, "VisibilityOutside", -1); sq_pushinteger(vm, Frustum::Outside); sq_newslot(vm, -3, true); + sq_pushstring(vm, "VisibilityClipped", -1); sq_pushinteger(vm, Frustum::Clipped); sq_newslot(vm, -3, true); + sq_pushstring(vm, "VisibilityInside", -1); sq_pushinteger(vm, Frustum::Inside); sq_newslot(vm, -3, true); + /*# + Func: CameraGetVisibleItems + Proto: array:Camera,Scene3d + Desc: Get all visible items in the camera frustum. + #*/ + sq_register(vm, CameraGetVisibleItems, "CameraGetVisibleItems", _SC(".xx")); + + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/clock_binding.cpp b/include/modules/script_squirrel/legacy/clock_binding.cpp new file mode 100644 index 0000000..ff99bd8 --- /dev/null +++ b/include/modules/script_squirrel/legacy/clock_binding.cpp @@ -0,0 +1,73 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "core/clock.h" + #include + + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger ClockReset(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(clock, GS::Core::Clock, typetag_Clock) + clock->Reset(); + __SQ_RETURN +} +SQInteger ClockGetCounter(HSQUIRRELVM vm) +{ + // Get frequency + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + __SQ_RETURNINT(counter.QuadPart) +} +SQInteger ClockGetFrequency(HSQUIRRELVM vm) +{ + // Get frequency + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + __SQ_RETURNINT(frequency.QuadPart) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterClockBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Clock + Type: Clock +#*/ + +/*# + Section: ClockGeneral + Desc: General functions +#*/ + /*# + Func: ClockReset + Proto: void:Clock + Desc: Reset a clock object. + #*/ + sq_register(vm, ClockReset, "ClockReset", _SC(".x")); + + /*# + Func: ClockGetCounter + Proto: int:Clock + Desc: Get the counter of a clock object. + #*/ + sq_register(vm, ClockGetCounter, "ClockGetCounter", _SC(".x")); + + /*# + Func: ClockGetFrequency + Proto: int:Clock + Desc: Get the frequency of a clock object. + #*/ + sq_register(vm, ClockGetFrequency, "ClockGetFrequency", _SC(".x")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/collision_binding.cpp b/include/modules/script_squirrel/legacy/collision_binding.cpp new file mode 100644 index 0000000..5b58510 --- /dev/null +++ b/include/modules/script_squirrel/legacy/collision_binding.cpp @@ -0,0 +1,541 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "scene3d/mitem.h" + #include "binding_helpers.h" + + using namespace GS; + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +#define __SQ_TEST_ITEM_PHYSIC if (!item->physic_item) return sq_throwerror(vm, "No physic interface."); + +SQInteger ItemSetSelfMask(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETINT(mask) + __SQ_GETEND + __SQ_TEST_ITEM_PHYSIC + item->physic_item->SetSelfMask(mask); + __SQ_RETURN +} +SQInteger ItemCollisionActivate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETBOOL(active) + __SQ_GETEND + __SQ_TEST_ITEM_PHYSIC + item->physic_item->SetActive(asbool(active)); + __SQ_RETURN +} +SQInteger ItemSetCollisionMask(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETINT(mask) + __SQ_GETEND + __SQ_TEST_ITEM_PHYSIC + item->physic_item->SetCollisionMask(mask); + __SQ_RETURN +} +SQInteger ItemGetShapeFromIndex(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETINT(idx) + __SQ_GETEND + __SQ_TEST_ITEM_PHYSIC + if (idx < (SQInteger)item->physic_item_desc.shape_list.GetCount()) + __SQ_RETURNSAFEPTR(item->physic_item_desc.shape_list[idx], typetag_ColShape) + __SQ_RETURNNULL +} +SQInteger ItemAddCollisionShape(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(item, MItem, typetag_Item) + __SQ_TEST_ITEM_PHYSIC + PhysicShape *shape = new PhysicShape; + if (!shape) + return sq_throwerror(vm, "Failed to allocate collision shape."); + item->physic_item_desc.shape_list.Add(shape); + __SQ_RETURNSAFEPTR(shape, typetag_ColShape) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ShapeSetMesh(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETSTRING(path) + bool r = path ? shape->Set(PhysicShape::TypeMesh, path) : false; + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger ShapeSetConvex(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETSTRING(path) + bool r = path ? shape->Set(PhysicShape::TypeConvex, path) : false; + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger ShapeSetSphere(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETFLOAT(radius) + __SQ_GETEND + __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeSphere, Vector4(radius, 0, 0))) +} +SQInteger ShapeSetBox(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETVECTOR(scale) + __SQ_GETEND + __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeBox, scale)) +} +SQInteger ShapeSetCapsule(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETFLOAT(radius) + __SQ_GETFLOAT(length) + __SQ_GETEND + __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeCapsule, Vector4(radius, length, 0.0))) +} +SQInteger ShapeSetCylinder(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETFLOAT(radius) + __SQ_GETFLOAT(length) + __SQ_GETEND + __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeCylinder, Vector4(radius, length, 0.0))) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ShapeGetItem(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_RETURNSAFEPTR(NULL, typetag_Item); +} +SQInteger ShapeGetPosition(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_RETURNVECTOR(shape->position) +} +SQInteger ShapeSetPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETVECTOR(p) + __SQ_GETEND + shape->position = p; + __SQ_RETURN +} +SQInteger ShapeGetRotation(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_RETURNVECTOR(shape->rotation) +} +SQInteger ShapeSetRotation(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETVECTOR(e) + __SQ_GETEND + shape->rotation = e; + __SQ_RETURN +} +SQInteger ShapeSetRestitution(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETFLOAT(r) + __SQ_GETEND + shape->restitution = r; + __SQ_RETURN +} +SQInteger ShapeSetFriction(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETFLOAT(df) + __SQ_GETFLOAT(sf) + __SQ_GETEND + shape->dynamic_friction = df; + shape->static_friction = sf; + __SQ_RETURN +} +SQInteger ShapeGetMass(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_RETURNFLOAT(shape->mass) +} +SQInteger ShapeSetMass(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) + __SQ_GETFLOAT(mass) + __SQ_GETEND + shape->mass = mass; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +// //poly poly intersection +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Gather up one-dimensional extents of the projection of the polygon +// onto this axis. +void gatherPolygonProjectionExtents(GS::Array poly, GS::Vector4 v, float &outMin, float &outMax) +{ + // Initialize extents to a single point, the first vertex + outMin = outMax = v.Dot(poly[0]); + + // Now scan all the rest, growing extents to include them + for (uint i = 1; i < poly.GetCount(); ++i) { + float d = v.Dot(poly[i]); + if (d < outMin) + outMin = d; + else if (d > outMax) + outMax = d; + } +} +// Helper routine: test if two convex polygons overlap, using only the edges of +// the first polygon (polygon "a") to build the list of candidate separating axes. +bool findSeparatingAxis(GS::Array poly_a, GS::Array poly_b) +{ + // Iterate over all the edges + uint prev = poly_a.GetCount() - 1; + for (uint cur = 0; cur < poly_a.GetCount(); ++cur) + { + // Get edge vector. (Assume operator- is overloaded) + GS::Vector4 edge = poly_a[cur] - poly_a[prev]; + edge.y = 0; + edge.Normalize(); + + // Rotate vector 90 degrees (doesn't matter which way) to get + // candidate separating axis. + GS::Vector4 v(edge.z, 0, -edge.x); + + // Gather extents of both polygons projected onto this axis + float result_poly_a_min, result_poly_a_max; + gatherPolygonProjectionExtents(poly_a, v, result_poly_a_min, result_poly_a_max); + float result_poly_b_min, result_poly_b_max; + gatherPolygonProjectionExtents(poly_b, v, result_poly_b_min, result_poly_b_max); + + // Is this a separating axis? + if (result_poly_a_max < result_poly_b_min) return true; + if (result_poly_b_max < result_poly_a_min) return true; + + // Next edge, please + prev = cur; + } + + // Failed to find a separating axis + return false; +} + +// Here is our high level entry point. It tests whether two polygons intersect. The +// polygons must be convex, and they must not be degenerate. +bool convexPolygonOverlap(GS::Array poly_a, GS::Array poly_b) //poly[a, b, c, d] +{ + // First, use all of A's edges to get candidate separating axes + if (findSeparatingAxis(poly_a, poly_b)) + return false; + + // Now swap roles, and use B's edges + if (findSeparatingAxis(poly_b, poly_a)) + return false; + + // No separating axis found. They must overlap + return true; +} + +SQInteger convexPolygonOverlapBind(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + + GS::Array poly_a(4); + sq_pushnull(vm);//null iterator + for (int i = 0; i < 4; ++i) + { + sq_next(vm, __SQ_STACKPOS - 1); + GetVector(vm, -1, poly_a[i]); + sq_pop(vm, 2); + } + sq_pop(vm, 1); //pops the null iterator + + __SQ_GETUPDATESTACK + GS::Array poly_b(4); + sq_pushnull(vm);//null iterator + for (int i = 0; i < 4; ++i) + { + sq_next(vm, __SQ_STACKPOS - 1); + GetVector(vm, -1, poly_b[i]); + sq_pop(vm, 2); + } + sq_pop(vm, 1); //pops the null iterator + + __SQ_GETEND + + __SQ_RETURNBOOL(convexPolygonOverlap(poly_a, poly_b)); +} + +//------------------------------------------------------------ +bool PointInPoly2D(GS::Vector4 point, GS::Array poly) // poly = [Vector(), Vector(), Vector(), Vector()] +//------------------------------------------------------------ +{ + bool oddNodes = false; + float x2 = poly[3].x; + float z2 = poly[3].z; + float x1, z1; + + // vertex a + x1 = poly[0].x; + z1 = poly[0].z; + if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { + if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) + oddNodes = !oddNodes; + } + + x2 = x1; + z2 = z1; + + // vertex b + x1 = poly[1].x; + z1 = poly[1].z; + if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { + if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) + oddNodes = !oddNodes; + } + + x2 = x1; + z2 = z1; + + // vertex c + x1 = poly[2].x; + z1 = poly[2].z; + if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { + if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) + oddNodes = !oddNodes; + } + + x2 = x1; + z2 = z1; + + // vertex d + x1 = poly[3].x; + z1 = poly[3].z; + if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { + if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) + oddNodes = !oddNodes; + } + + return oddNodes; +} + +SQInteger PointInPoly2DBind(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + + __SQ_GETVECTOR(p); + + GS::Array poly_a(4); + sq_pushnull(vm);//null iterator + for (int i = 0; i < 4; ++i) + { + sq_next(vm, __SQ_STACKPOS - 1); + GetVector(vm, -1, poly_a[i]); + sq_pop(vm, 2); + } + sq_pop(vm, 1); //pops the null iterator + + __SQ_GETUPDATESTACK + __SQ_GETEND + + __SQ_RETURNBOOL(PointInPoly2D(p, poly_a)); +} + + +//---------------------------------------------------------- +void RegisterCollisionBinding(HSQUIRRELVM vm) +//---------------------------------------------------------- +{ + /*# + Func: convexPolygonOverlapBind + Proto: void:array polyA, array polyB + Desc: return if the 2 poly overlap + #*/ + sq_register(vm, convexPolygonOverlapBind, "convexPolygonOverlapBind", _SC(".aa")); + /*# + Func: convexPolygonOverlapBind + Proto: void:Vector p, array polyA + Desc: return if the 2 poly overlap + #*/ + sq_register(vm, PointInPoly2DBind, "PointInPoly2DBind", _SC(".xa")); +/*# + Topic: Collision + Type: ColShape +#*/ +/*# + Section: CollisionShapeType + Desc: Collision Shape Type functions +#*/ + /*# + Func: ShapeSetMesh + Proto: bool:ColShape shape,string path + Desc: Set the shape as a collision mesh. + #*/ + sq_register(vm, ShapeSetMesh, "ShapeSetMesh", _SC(".xs")); + /*# + Func: ShapeSetConvex + Proto: bool:ColShape shape,string path + Desc: Set the shape as a convex collision. + #*/ + sq_register(vm, ShapeSetConvex, "ShapeSetConvex", _SC(".xs")); + /*# + Func: ShapeSetSphere + Proto: bool:ColShape shape,float radius + Desc: Set the shape as a sphere. + #*/ + sq_register(vm, ShapeSetSphere, "ShapeSetSphere", _SC(".xn")); + /*# + Func: ShapeSetBox + Proto: bool:ColShape shape,Vector dimensions + Desc: Set the shape as a box collision shape. + #*/ + sq_register(vm, ShapeSetBox, "ShapeSetBox", _SC(".xx")); + /*# + Func: ShapeSetCapsule + Proto: bool:ColShape shape,float radius,float length + Desc: Set the shape as a Z-oriented capsule collision shape. + #*/ + sq_register(vm, ShapeSetCapsule, "ShapeSetCapsule", _SC(".xnn")); + /*# + Func: ShapeSetCylinder + Proto: bool:ColShape shape,float radius,float length + Desc: Set the shape as a Z-oriented cylinder collision shape. + #*/ + sq_register(vm, ShapeSetCylinder, "ShapeSetCylinder", _SC(".xnn")); + +/*# + Section: CollisionShape + Desc: Collision Shape functions +#*/ + /*# + Func: ShapeSetPosition + Proto: void:ColShape shape,Vector position + Desc: Set the collision shape position in item space. + #*/ + sq_register(vm, ShapeSetPosition, "ShapeSetPosition", _SC(".xx")); + /*# + Func: ShapeGetPosition + Proto: Vector:ColShape shape + Desc: Get the collision shape position in item space. + #*/ + sq_register(vm, ShapeGetPosition, "ShapeGetPosition", _SC(".x")); + /*# + Func: ShapeSetRotation + Proto: void:ColShape shape,Vector position + Desc: Set the collision shape position from a Euler triplet in item space. + #*/ + sq_register(vm, ShapeSetRotation, "ShapeSetRotation", _SC(".xx")); + /*# + Func: ShapeGetRotation + Proto: Vector:ColShape shape + Desc: Get the collision shape rotation as an Euler triplet in item space. + #*/ + sq_register(vm, ShapeGetRotation, "ShapeGetRotation", _SC(".x")); + + /*# + Func: ShapeSetMass + Proto: void:ColShape shape,float mass + Desc: Set the collision shape mass. Do not forget to update the item collision setup to update changes. + #*/ + sq_register(vm, ShapeSetMass, "ShapeSetMass", _SC(".xn")); + /*# + Func: ShapeGetMass + Proto: float:ColShape shape + Desc: Get the collision shape mass. + #*/ + sq_register(vm, ShapeGetMass, "ShapeGetMass", _SC(".x")); + /*# + Func: ShapeSetFriction + Proto: void:ColShape shape,float dynamic_friction,float static_friction + Desc: Set collision shape dynamic and static friction. + #*/ + sq_register(vm, ShapeSetFriction, "ShapeSetFriction", _SC(".xnn")); + /*# + Func: ShapeSetRestitution + Proto: void:ColShape shape,float restitution + Desc: Set collision shape restitution (1 for a perfect elastic collision). + #*/ + sq_register(vm, ShapeSetRestitution, "ShapeSetRestitution", _SC(".xn")); + /*# + Func: ShapeGetItem + Proto: Item:ColShape shape + Desc: Get the item this collision shape belongs to. + #*/ + sq_register(vm, ShapeGetItem, "ShapeGetItem", _SC(".x")); + +/*# + Section: CollisionItem + Desc: Item functions +#*/ + /*# + Func: ItemAddCollisionShape + Proto: ColShape:Item + Desc: Add a new collision shape to item. + #*/ + sq_register(vm, ItemAddCollisionShape, "ItemAddCollisionShape", _SC(".x")); + /*# + Func: ItemCollisionActivate + Proto: void:Item,bool active + Desc: Activate or deactivate item collision. + #*/ + sq_register(vm, ItemCollisionActivate, "ItemCollisionActivate", _SC(".xb")); + /*# + Func: ItemSetSelfMask + Proto: void:Item,int self_mask + Desc: Set item self mask, this mask is a bit field. + #*/ + sq_register(vm, ItemSetSelfMask, "ItemSetSelfMask", _SC(".xi")); + /*# + Func: ItemSetCollisionMask + Proto: void:Item,int collision_mask + Desc: Set item collision mask, this mask is a bit field. + #*/ + sq_register(vm, ItemSetCollisionMask, "ItemSetCollisionMask", _SC(".xi")); + /*# + Func: ItemGetShapeFromIndex + Proto: ColShape:item,int index + Desc: Get item collision shape from index. + #*/ + sq_register(vm, ItemGetShapeFromIndex, "ItemGetShapeFromIndex", _SC(".xi")); + + // Push defines. + sq_pushroottable(vm); + + /*# + Enum: ShapeMask + Desc: Shape mask to filter out certain type of shape from intersection tests. + Values: CollisionTraceMesh,CollisionTraceSphere,CollisionTraceCuboid,CollisionTraceAll + #*/ + sq_pushstring(vm, "CollisionTraceMesh", -1); sq_pushinteger(vm, -1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "CollisionTraceSphere", -1); sq_pushinteger(vm, -1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "CollisionTraceCuboid", -1); sq_pushinteger(vm, -1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "CollisionTraceAll", -1); sq_pushinteger(vm, ~0); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/emitter_binding.cpp b/include/modules/script_squirrel/legacy/emitter_binding.cpp new file mode 100644 index 0000000..5b44d8b --- /dev/null +++ b/include/modules/script_squirrel/legacy/emitter_binding.cpp @@ -0,0 +1,112 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "scene3d/scene.h" + #include "scene3d/memitter.h" + #include "core/engine.h" + #include "core/graphic_resource_factory.h" + + using namespace GS::Core; + using namespace GS::S3D; + using namespace GS::Script; + + +SQInteger EmitterSetParticleModel(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(e, MEmitter, typetag_Emitter) + __SQ_GETSAFEPTR(model, ParticleModel, typetag_ParticleModel) + __SQ_GETEND + if (e->render_data.IsNull()) + return sq_throwerror(vm, "Emitter has no render data, you need to call ItemRenderSetup() first."); + e->render_data->particle_model = model; + __SQ_RETURN +} + +SQInteger EmitterSetBirthRateScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(e, MEmitter, typetag_Emitter) + __SQ_GETFLOAT(scale) + __SQ_GETEND + e->birth_rate_scale = scale; + __SQ_RETURN +} +SQInteger EmitterSetBirthSizeScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(e, MEmitter, typetag_Emitter) + __SQ_GETFLOAT(scale) + __SQ_GETEND + e->birth_size_scale = scale; + __SQ_RETURN +} +SQInteger EmitterSetBirthSpeedScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(e, MEmitter, typetag_Emitter) + __SQ_GETFLOAT(scale) + __SQ_GETEND + e->birth_speed_scale = scale; + __SQ_RETURN +} +SQInteger EmitterSetBirthOpacityScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(e, MEmitter, typetag_Emitter) + __SQ_GETFLOAT(scale) + __SQ_GETEND + e->birth_opacity_scale = scale; + __SQ_RETURN +} + +//-------------------------------------------------------- +void RegisterEmitterBinding(HSQUIRRELVM vm) +//-------------------------------------------------------- +{ +/*# + Topic: Emitter + Type: Emitter + Type: ParticleModel +#*/ + +/*# + Section: EmitterSettings + Desc: Emitter functions +#*/ + /*# + Func: EmitterSetParticleModel + Proto: void:Emitter,ParticleModel + Desc: Set the emitter particle model. + #*/ + sq_register(vm, EmitterSetParticleModel, "EmitterSetParticleModel", _SC(".xx")); + + /*# + Func: EmitterSetBirthRateScale + Proto: void:Emitter,float scale + Desc: Set the emitter birth rate scale. + #*/ + sq_register(vm, EmitterSetBirthRateScale, "EmitterSetBirthRateScale", _SC(".xn")); + /*# + Func: EmitterSetBirthSizeScale + Proto: void:Emitter,float scale + Desc: Set the emitter birth size scale. + #*/ + sq_register(vm, EmitterSetBirthSizeScale, "EmitterSetBirthSizeScale", _SC(".xn")); + /*# + Func: EmitterSetBirthSpeedScale + Proto: void:Emitter,float scale + Desc: Set the emitter birth speed scale. + #*/ + sq_register(vm, EmitterSetBirthSpeedScale, "EmitterSetBirthSpeedScale", _SC(".xn")); + /*# + Func: EmitterSetBirthOpacityScale + Proto: void:Emitter,float scale + Desc: Set the emitter birth opacity scale. + #*/ + sq_register(vm, EmitterSetBirthOpacityScale, "EmitterSetBirthOpacityScale", _SC(".xn")); +} diff --git a/include/modules/script_squirrel/legacy/font_binding.cpp b/include/modules/script_squirrel/legacy/font_binding.cpp new file mode 100644 index 0000000..d811a38 --- /dev/null +++ b/include/modules/script_squirrel/legacy/font_binding.cpp @@ -0,0 +1,103 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "squirrel_binding.h" + #include "binding_helpers.h" + #include "font/font_renderer.h" + + using namespace GS; + using namespace GS::Script; + + +void IterateTextParameters(HSQUIRRELVM vm, int idx, TextState &state); + +//------------------------------------------------------------------------------ +SQInteger FontSetFallback(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(font, FontEx, typetag_Font) + __SQ_GETSAFEPTR(fbck, FontEx, typetag_Font) + __SQ_GETEND + font->fallback = fbck; + __SQ_RETURN +} +SQInteger FontSetParametersOffset(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(font, FontEx, typetag_Font) + __SQ_GETFLOAT(size) + __SQ_GETFLOAT(tracking) + __SQ_GETFLOAT(leading) + __SQ_GETEND + font->size_multiplier = size; + font->tracking_offset = tracking; + font->leading_offset = leading; + __SQ_RETURN +} +SQInteger FontComputeRect(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETRECT(clip_rect) + __SQ_GETSTRING(text) + __SQ_GETSAFEPTR(font, FontEx, typetag_Font) + + TextState state; + IterateTextParameters(vm, __sq_stackpos, state); + __SQ_GETUPDATESTACK + + state.font = font; + iRect out_rect = FontRenderer::Format(text, state, clip_rect); + + __SQ_GETEND + __SQ_RETURNRECT(out_rect) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterFontBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Font + Type: Font + Desc: A truetype font that can be used to render to a picture object. + Related: Picture,Project +#*/ +/*# + Section: FontGeneral + Desc: Font Settings +#*/ + /*# + Func: FontSetParametersOffset + Proto: void:Font,float size_multiplier,float tracking_offset,float leading_offset + Desc: Set font-specific properties offset. This function is usually used to normalize font characteristics when porting an application to a different locale. + #*/ + sq_register(vm, FontSetParametersOffset, "FontSetParametersOffset", _SC(".xnnn")); + sq_register(vm, FontSetParametersOffset, "UIFontSetParametersOffset", _SC(".xnnn")); + /*# + Func: FontSetFallback + Proto: void:Font font,Font fallback + Desc: Set a font to query when a glyph is missing from this font. + #*/ + sq_register(vm, FontSetFallback, "FontSetFallback", _SC(".xx")); + sq_register(vm, FontSetFallback, "UIFontSetFallback", _SC(".xx")); + /*# + Func: FontComputeRect + Proto: rect:rect clip_rect,string text,Font font,table param + Desc: Compute the bounding rect of a formatted text string, does not perform any graphic output. +
+ The following table keys are available:
+
    +
  • 'color': Hexadecimal RGBA (eg. Red: xff0000ff) +
  • 'align': TextAlign +
  • 'format': TextFormat +
  • 'tracking': Integer value specifying an extra space between glyphs. +
  • 'heading': Integer value specifying an extra space between lines. +
+ #*/ + sq_register(vm, FontComputeRect, "FontComputeRect", _SC(".xsxt")); + sq_register(vm, FontComputeRect, "UIFontComputeRect", _SC(".xsxt")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/geometry_binding.cpp b/include/modules/script_squirrel/legacy/geometry_binding.cpp new file mode 100644 index 0000000..296327f --- /dev/null +++ b/include/modules/script_squirrel/legacy/geometry_binding.cpp @@ -0,0 +1,537 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "core/render_data.h" + #include "core/geometry.h" + #include "core/iso_surface.h" + #include "core/resource_factories.h" + #include "core/graphic_resource_factory.h" + #include "metafile/nml_object.h" + #include "gpu/gpu_material.h" + + using namespace GS; + using namespace GS::Render; + using namespace GS::Script; + +//------------------------------------------------------------------------------ +SQInteger GeometrySaveOnItself(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETSAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETEND + + // get the geo from core + GS::Core::Geometry * core_geo = f->graphic->LoadGeometry(g->name); + + core_geo->flag = g->flag; + core_geo->lod_distance = g->lod_distance; + + if(g->lod_proxy.IsValid()) + core_geo->lod_proxy = g->lod_proxy->name; + else + core_geo->lod_proxy = ""; + + if(g->shadow_proxy.IsValid()) + core_geo->shadow_proxy = g->shadow_proxy->name; + else + core_geo->shadow_proxy = ""; + + bool r = NML::SaveToFile(*core_geo, core_geo->name); + + __SQ_RETURN +} +//------------------------------------------------------------------------------ +SQInteger GeometryGetShadowProxyNull(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNBOOL(g->flag.IsSet(Core::Geometry::FlagNullShadowProxy)) +} +//------------------------------------------------------------------------------ +SQInteger GeometrySetShadowProxyNull(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETBOOL(ShadowProxyNull) + __SQ_GETEND + g->flag.Raise(Core::Geometry::FlagNullShadowProxy, asbool(ShadowProxyNull)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ +SQInteger GeometryGetLodNull(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNBOOL(g->flag.IsSet(Core::Geometry::FlagNullLodProxy)) +} +//------------------------------------------------------------------------------ +SQInteger GeometrySetLodNull(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETBOOL(LodNull) + __SQ_GETEND + g->flag.Raise(Core::Geometry::FlagNullLodProxy, asbool(LodNull)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ +SQInteger GeometryGetLodDistance(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNFLOAT(g->lod_distance) +} +//------------------------------------------------------------------------------ +SQInteger GeometrySetLodDistance(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETFLOAT(n) + __SQ_GETEND + g->lod_distance = n; + __SQ_RETURN + +} +//------------------------------------------------------------------------------ +SQInteger GeometryGetLod(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNSAFEPTR(g->lod_proxy.c_ptr(), typetag_Geometry) + +} +//------------------------------------------------------------------------------ +SQInteger GeometrySetLod(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETSAFEPTRALLOWNULL(geo_Lod, GS::Render::Geometry, typetag_Geometry) + __SQ_GETEND + g->lod_proxy = geo_Lod ? geo_Lod : NULL; + __SQ_RETURN + +} +//------------------------------------------------------------------------------ +SQInteger GeometryGetShadowProxy(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNSAFEPTR(g->shadow_proxy.c_ptr(), typetag_Geometry) + +} +//------------------------------------------------------------------------------ +SQInteger GeometrySetShadowProxy(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETSAFEPTRALLOWNULL(geo_shadow_proxy, GS::Render::Geometry, typetag_Geometry) + __SQ_GETEND + g->shadow_proxy = geo_shadow_proxy? geo_shadow_proxy : NULL; + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +SQInteger GeometryGetName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNSTRING(g->name) +} +SQInteger GeometryGetMinMax(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNMINMAX(g->minmax) +} +SQInteger GeometrySetHidden(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETBOOL(hidden) + __SQ_GETEND + g->flag.Raise(Core::Geometry::FlagHidden, asbool(hidden)); + __SQ_RETURN +} +SQInteger GeometryOptimize(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURN +} +SQInteger GeometryComputeIsoSurface(HSQUIRRELVM vm) +{ + sq_pop(vm, 4); +/* + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(Item, nMItem, typetag_Item) + __SQ_GETINT(nb_metaball) + + if ((nb_metaball > 0) && (Item->GetItemType() == Type_Object)) + { + // get the geometry, or if it doesn't have it create one + nSharedPtr g; + if(((nMObject *)Item)->GetGeometry().IsNull()) + { + g = new nGeometry(Item->GetScene().GetEngine()); + ((nMObject *)Item)->SetGeometry(g.c_ptr()); + } + else + g = ((nMObject *)Item)->GetGeometry(); + + nVector* pos_metaball = new nVector[nb_metaball]; + + // get the list of metaball + sq_pushnull(vm);//null iterator + for(int i=0; i MaxGrid.x) MaxGrid.x = pos_metaball[i].x+value_metaball[i]; + if (pos_metaball[i].y+value_metaball[i] > MaxGrid.y) MaxGrid.y = pos_metaball[i].y+value_metaball[i]; + if (pos_metaball[i].z+value_metaball[i] > MaxGrid.z) MaxGrid.z = pos_metaball[i].z+value_metaball[i]; + if (pos_metaball[i].x-value_metaball[i] < MinGrid.x) MinGrid.x = pos_metaball[i].x-value_metaball[i]; + if (pos_metaball[i].y-value_metaball[i] < MinGrid.y) MinGrid.y = pos_metaball[i].y-value_metaball[i]; + if (pos_metaball[i].z-value_metaball[i] < MinGrid.z) MinGrid.z = pos_metaball[i].z-value_metaball[i]; + } + + nIsosurface isosurface(g->GetEngine()); + isosurface.Init(MinGrid, MaxGrid-MinGrid, nVector(90, 90, 90)); + + g->Free(); + isosurface.Triangularize(g.c_ptr(), nb_metaball, pos_metaball, value_metaball); + g->material_table.Allocate(1); + + nMaterial *m = g->material_table[0] = new nMaterial(g->GetEngine()); + m->renderword |= nMaterial::Render_Smooth; + // m->shader_map = m->AsShaderMap(); + //g->ComputeVertexToPolygon(); + // // Update ISO + g->render_data = g->GetEngine().GetRenderer().SetupGeometry(g.c_ptr()); + + _safe_delete_array(value_metaball); + _safe_delete_array(pos_metaball); + } +*/ + __SQ_RETURN +} +SQInteger GeometrySetup(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __LOG_V__ << "GeometrySetup() STUB\n"; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger GeometryGetMaterialList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + sq_newarray(vm, 0); + + for (uint n = 0; n < g->material_table.GetCount(); ++n) + { + CObject::Push(vm, (void *)g->material_table[n].c_ptr(), typetag_Material); + sq_arrayappend(vm, -2); + } + return 1; +} +SQInteger GeometryGetMaterialCount(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + __SQ_RETURNINT(g->material_table.GetCount()) +} +SQInteger GeometryGetMaterial(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETSTRING(name) + + Material *m = NULL; + for (uint n = 0; n < g->material_table.GetCount(); ++n) + if (g->material_table[n]->name == name) + { + m = g->material_table[n]; + break; + } + + __SQ_GETEND + __SQ_RETURNSAFEPTR(m, typetag_Material) +} +SQInteger GeometryGetMaterialFromIndex(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETINT(index) + __SQ_GETEND + __SQ_RETURNSAFEPTR(g->material_table[(int)index].c_ptr(), typetag_Material) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger GeometrySetMaterial(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(g, Geometry, typetag_Geometry) + __SQ_GETINT(index) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETEND + __SQ_RETURNBOOL(g->SetMaterial(uint(index), m)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger GeometryCloneMaterials(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(g, Geometry, typetag_Geometry) + + __LOG_W__ << "[SQ] GeometryCloneMaterials: Cloning all materials for geometry '" << g->name << "'...\n"; + + uint mat_count = g->material_table.GetCount(); + __LOG_W__ << "[SQ] GeometryCloneMaterials: Found " << mat_count << " materials.\n"; + + for (uint i = 0; i < mat_count; ++i) + { + Material *original = g->material_table[i].c_ptr(); + if (!original) + { + __LOG_W__ << "[SQ] GeometryCloneMaterials: Material " << i << " is NULL, skipping.\n"; + continue; + } + + __LOG_W__ << "[SQ] GeometryCloneMaterials: Cloning material " << i << " ('" << original->name << "')...\n"; + + // Cast to GPU::Material + GPU::Material *gpu_mat = dynamic_cast(original); + if (!gpu_mat) + { + __LOG_W__ << "[SQ] GeometryCloneMaterials: Material " << i << " is not GPU::Material, skipping.\n"; + continue; + } + + // Clone manually (same as MaterialClone) + try + { + GPU::Renderer &rend = gpu_mat->renderer; + Material *cloned = new GPU::Material(rend); + + // Copy properties + cloned->name = gpu_mat->name + "_clone"; + *((Core::BasicMaterial *)cloned) = *((Core::BasicMaterial *)gpu_mat); + ((GPU::Material*)cloned)->shader = gpu_mat->shader; + + // Copy texture table + for (uint n = 0; n < Core::Material::max_texture_stage; ++n) + { + cloned->texture_table[n] = gpu_mat->texture_table[n]; + } + + // Assign cloned material back to geometry + g->SetMaterial(i, cloned); + + __LOG_W__ << "[SQ] GeometryCloneMaterials: Material " << i << " cloned successfully.\n"; + } + catch (...) + { + __LOG_E__ << "[SQ] GeometryCloneMaterials: Exception while cloning material " << i << "!\n"; + } + } + + __LOG_W__ << "[SQ] GeometryCloneMaterials: Done!\n"; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------- +void RegisterGeometryBinding(HSQUIRRELVM vm) +//------------------------------------------------- +{ +/*# + Topic: Geometry + Type: Geometry +#*/ + +/*# + Section: GeometryGeneric + Desc: Generic functions +#*/ + + /*# + Func: GeometryGetLod + Proto: Geometry:Geometry geo + Desc: Get geometry get geometry LOD. + #*/ + sq_register(vm, GeometryGetLod, "GeometryGetLod", _SC(".x")); + /*# + Func: GeometrySetLod + Proto: void:Geometry geo, Geometry geo_LOD + Desc: Set geometry LOD. + #*/ + sq_register(vm, GeometrySetLod, "GeometrySetLod", _SC(".xx")); + + /*# + Func: GeometryGetShadowProxy + Proto: Geometry:Geometry geo + Desc: Get geometry get geometry Shadow proxy. + #*/ + sq_register(vm, GeometryGetShadowProxy, "GeometryGetShadowProxy", _SC(".x")); + /*# + Func: GeometrySetShadowProxy + Proto: void:Geometry geo, Geometry show_proxy + Desc: Set geometry shadow proxy + #*/ + sq_register(vm, GeometrySetShadowProxy, "GeometrySetShadowProxy", _SC(".xx")); + + /*# + Func: GeometryGetLodDistance + Proto: float:Geometry geo + Desc: Get geometry Lod distance. + #*/ + sq_register(vm, GeometryGetLodDistance, "GeometryGetLodDistance", _SC(".x")); + /*# + Func: GeometrySetLodDistance + Proto: void:Geometry geo, float Lod distance + Desc: Set geometry Lod distance + #*/ + sq_register(vm, GeometrySetLodDistance, "GeometrySetLodDistance", _SC(".xn")); + + /*# + Func: GeometryGetLodNull + Proto: bool:Geometry geo + Desc: Get geometry Lod Null. + #*/ + sq_register(vm, GeometryGetLodNull, "GeometryGetLodNull", _SC(".x")); + /*# + Func: GeometrySetLodNull + Proto: void:Geometry geo, bool LodNull + Desc: Set geometry Lod Null + #*/ + sq_register(vm, GeometrySetLodNull, "GeometrySetLodNull", _SC(".xb")); + /*# + Func: GeometryGetShadowProxyNull + Proto: bool:Geometry geo + Desc: Get geometry ShadowProxy Null. + #*/ + sq_register(vm, GeometryGetShadowProxyNull, "GeometryGetShadowProxyNull", _SC(".x")); + /*# + Func: GeometrySetShadowProxyNull + Proto: void:Geometry geo, bool ShadowProxyNull + Desc: Set geometry ShadowProxy Null + #*/ + sq_register(vm, GeometrySetShadowProxyNull, "GeometrySetShadowProxyNull", _SC(".xb")); + + /*# + Func: GeometrySaveOnItself + Proto: void:Geometry geo, g_factory + Desc: Save the geometry on it's own nmg. + #*/ + sq_register(vm, GeometrySaveOnItself, "GeometrySaveOnItself", _SC(".xx")); + + + /*# + Func: GeometryGetName + Proto: string:Geometry geo + Desc: Get geometry name. + #*/ + sq_register(vm, GeometryGetName, "GeometryGetName", _SC(".x")); + /*# + Func: GeometrySetHidden + Proto: void:Geometry geo,bool hidden + Desc: Hide or show geometry, items referring to this geometry will still be updated. + #*/ + sq_register(vm, GeometrySetHidden, "GeometrySetHidden", _SC(".xb")); + /*# + Func: GeometryOptimize + Proto: void:Geometry geo + Desc: Optimize geometry for realtime rendering. + #*/ + sq_register(vm, GeometryOptimize, "GeometryOptimize", _SC(".x")); + /*# + Func: GeometryComputeIsoSurface + Proto: void:Item item, int nb_metaball,array pos_metaball,array value_metaball + Desc: Create an iso surface to the geometry with the array of metaball. + #*/ + sq_register(vm, GeometryComputeIsoSurface, "GeometryComputeIsoSurface", _SC(".xiaa")); + /*# + Func: GeometrySetup + Proto: void:Geometry geo + Desc: Setup geometry in the renderer. + #*/ + sq_register(vm, GeometrySetup, "GeometrySetup", _SC(".x")); + +/*# + Section: GeometryTopology + Desc: Topology functions +#*/ + + /*# + Func: GeometryGetMinMax + Proto: MinMax:Geometry geo + Desc: Get geometry minmax. + #*/ + sq_register(vm, GeometryGetMinMax, "GeometryGetMinMax", _SC(".x")); + +/*# + Section: GeometryMaterial + Desc: Material functions +#*/ + + /*# + Func: GeometryGetMaterialList + Proto: array:Geometry geo + Desc: Return a list of all materials in a geometry. + #*/ + sq_register(vm, GeometryGetMaterialList, "GeometryGetMaterialList", _SC(".x")); + /*# + Func: GeometryGetMaterialCount + Proto: int:Geometry geo + Desc: Get geometry material count. + #*/ + sq_register(vm, GeometryGetMaterialCount, "GeometryGetMaterialCount", _SC(".x")); + /*# + Func: GeometryGetMaterial + Proto: Material:Geometry geo,string name + Desc: Get material from name. + #*/ + sq_register(vm, GeometryGetMaterial, "GeometryGetMaterial", _SC(".xs")); + /*# + Func: GeometrySetMaterial + Proto: bool:Geometry geo,int index,Material material + Desc: Replace a material in the geometry material table. + #*/ + sq_register(vm, GeometrySetMaterial, "GeometrySetMaterial", _SC(".xix")); + /*# + Func: GeometryCloneMaterials + Proto: void:Geometry geo + Desc: Clone all materials in the geometry. Each material becomes an independent copy. + Note: This allows you to modify materials for one geometry without affecting others that share the same loaded geometry file. + Example: GeometryCloneMaterials(geo) + #*/ + sq_register(vm, GeometryCloneMaterials, "GeometryCloneMaterials", _SC(".x")); + /*# + Func: GeometryGetMaterialFromIndex + Proto: Material:Geometry geo,int index + Desc: Get material from index. + #*/ + sq_register(vm, GeometryGetMaterialFromIndex, "GeometryGetMaterialFromIndex", _SC(".xi")); +} diff --git a/include/modules/script_squirrel/legacy/group_binding.cpp b/include/modules/script_squirrel/legacy/group_binding.cpp new file mode 100644 index 0000000..6123277 --- /dev/null +++ b/include/modules/script_squirrel/legacy/group_binding.cpp @@ -0,0 +1,310 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "scene3d/group.h" + #include "automation/automation_source_group.h" + #include "math/matrix4.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +SQInteger GroupSetInvisible(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETBOOL(value) + __SQ_GETEND + group->SetInvisible(value ? true : false); + __SQ_RETURN +} + +extern SQInteger GetMatrix4(HSQUIRRELVM vm, int idx, GS::Matrix4 &mtx); + +SQInteger GroupOffsetMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETMATRIX4(m) + __SQ_GETEND + group->Offset(m); + __SQ_RETURN +} + +SQInteger GroupFindItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSTRING(item_id) + __SQ_GETEND + MItem *item = group->Item(item_id); + __SQ_RETURNSAFEPTR(item, typetag_Item) +} + +SQInteger GroupSetRootItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSAFEPTR(root, MItem, typetag_Item) + __SQ_GETEND + group->SetRootItem(root); + __SQ_RETURN +} + +SQInteger GroupGetRootItem(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, Group, typetag_Group) + __SQ_RETURNSAFEPTR(group->GetRootItem(), typetag_Item) +} + +SQInteger GroupItemIsMember(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETEND + __SQ_RETURNBOOL(group->IsMember(item)) +} +SQInteger GroupAddItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETEND + group->Add(item); + __SQ_RETURN +} +SQInteger GroupRemoveItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETEND + group->Remove(item); + __SQ_RETURN +} +SQInteger GroupSetName(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSTRING(_name) + group->name = _name; + __SQ_GETEND + __SQ_RETURN +} +SQInteger GroupGetName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, Group, typetag_Group) + __SQ_RETURNSTRING(group->name) +} + +SQInteger GroupSetup(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, Group, typetag_Group) + group->Setup(); + __SQ_RETURN +} + +SQInteger GroupSetupScript(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, Group, typetag_Group) + __LOG_V__ << "GroupSetupScript: STUB\n"; + __SQ_RETURN +} + +SQInteger GroupRenderSetup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSAFEPTR(rf, GS::Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETEND + group->RenderSetup(rf); + __SQ_RETURN +} + +SQInteger GroupReset(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(group, Group, typetag_Group) + group->Reset(); + __SQ_RETURN +} + +SQInteger GroupSetMotion(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETSTRING(name) + __SQ_GETFLOAT(blend) + GS::Automation::SourceGroup *anim_group = NULL; + group->SetMotion(name, &anim_group, blend); + __SQ_GETEND + __SQ_RETURNMANAGEDSAFEPTR(anim_group, typetag_AutomationSourceGroup) +} + +//-------------------------------------------------- +SQInteger GroupGetItemList(HSQUIRRELVM vm) +//-------------------------------------------------- +{ + __SQ_GETSINGLESAFEPTR(group, Group, typetag_Group) + sq_newarray(vm, 0); + ListForeachPtr(MItem *, i, group->GetItemList()) + { + CObject::Push(vm, (void *)i, typetag_Item); + sq_arrayappend(vm, -2); + } + return 1; +} + +//---------------------------------------------- +void RegisterGroupBinding(HSQUIRRELVM vm) +//---------------------------------------------- +{ +/*# + Topic: Group + Desc: A group holds a reference to several scene items. + It is often used to keep track of instantiated 'block scene' items and resources inside a larger scene. + Type: Group + Related: Scene, Item +#*/ + +/*# + Section: GroupManagement + Desc: Management +#*/ + /*# + Func: GroupSetup + Proto: void:Group group + Desc: Setup all members of a group. + See: ItemSetup + #*/ + sq_register(vm, GroupSetup, "GroupSetup", _SC(".x")); + /*# + Func: GroupSetup + Proto: void:Group group + Desc: Setup all members of a group. + See: ItemSetup + #*/ + sq_register(vm, GroupSetup, "GroupSetup", _SC(".x")); + /*# + Func: GroupSetupScript + Proto: void:Group group + Desc: Setup the script object of all members of a group. + See: ItemSetupScript + #*/ + sq_register(vm, GroupSetupScript, "GroupSetupScript", _SC(".x")); + /*# + Func: GroupReset + Proto: void:Group group + Desc: Reset all members of a group. + See: ItemReset + #*/ + sq_register(vm, GroupReset, "GroupReset", _SC(".x")); + /*# + Func: GroupRenderSetup + Proto: void:Group group,ResourceFactory factory + Desc: Setup rendering data for all members of a group. + Example: GroupRenderSetup(group, g_factory) + See: ItemRenderSetup + #*/ + sq_register(vm, GroupRenderSetup, "GroupRenderSetup", _SC(".xx")); + + /*# + Func: GroupGetItemList + Proto: Array:Group group + Desc: Return the group item list. + Example: +function ListGroupItemNames(group) +{ + local group_name = GroupGetName(group) + + local items = GroupGetItemList(group) + foreach (item in items) + print("Item " + ItemGetName(item) + " is a member of group" + group_name + ".") +} + #*/ + sq_register(vm, GroupGetItemList, "GroupGetItemList", _SC(".x")); + + /*# + Func: GroupGetRootItem + Proto: Item:Group group + Desc: Return the root item of a group. + #*/ + sq_register(vm, GroupGetRootItem, "GroupGetRootItem", _SC(".x")); + /*# + Func: GroupSetRootItem + Proto: void:Group group,Item root_item + Desc: Set the root item of a group. All members of a group are linked to its root item if it has one. + #*/ + sq_register(vm, GroupSetRootItem, "GroupSetRootItem", _SC(".xx")); + /*# + Func: GroupSetInvisible + Proto: void:Group group,bool set_invisible + Desc: Hide all members of a group. + #*/ + sq_register(vm, GroupSetInvisible, "GroupSetInvisible", _SC(".xb")); + /*# + Func: GroupFindItem + Proto: item:Group group,string name_to_find + Desc: Find an item in a group from its name. + #*/ + sq_register(vm, GroupFindItem, "GroupFindItem", _SC(".xs")); + /*# + Func: GroupItemIsMember + Proto: bool:Group group,Item item_to_test + Desc: Returns true if item the belongs to the group, false otherwise. + #*/ + sq_register(vm, GroupItemIsMember, "GroupItemIsMember", _SC(".xx")); + /*# + Func: GroupAddItem + Proto: void:Group group,Item item_to_add + Desc: Add an item to a group. + #*/ + sq_register(vm, GroupAddItem, "GroupAddItem", _SC(".xx")); + /*# + Func: GroupRemoveItem + Proto: void:Group group,Item item_to_remove + Desc: Remove an item from a group. + #*/ + sq_register(vm, GroupRemoveItem, "GroupRemoveItem", _SC(".xx")); + /*# + Func: GroupSetName + Proto: void:Group group,string name + Desc: Set the name of a group. + #*/ + sq_register(vm, GroupSetName, "GroupSetName", _SC(".xs")); + /*# + Func: GroupGetName + Proto: string:Group group + Desc: Get the name of a group. + #*/ + sq_register(vm, GroupGetName, "GroupGetName", _SC(".x")); + +/*# + Section: GroupTransform + Desc: Transformation +#*/ + /*# + Func: GroupOffsetMatrix + Proto: void:Group group,matrix4 offset_matrix + Desc: Apply a 4x4 offset matrix to all group members. + See: TransformationMatrix + #*/ + sq_register(vm, GroupOffsetMatrix, "GroupOffsetMatrix", _SC(".xx")); + +/*# + Section: GroupMotion + Desc: Motion +#*/ + /*# + Func: GroupSetMotion + Proto: AnimationSourceGroup:Group group,string motion_name,float blend + Desc: Set motion on all group items, specify the blend duration, stop all current animation sources. + See: ItemSetMotion + #*/ + sq_register(vm, GroupSetMotion, "GroupSetMotion", _SC(".xsn")); +} diff --git a/include/modules/script_squirrel/legacy/hash_binding.cpp b/include/modules/script_squirrel/legacy/hash_binding.cpp new file mode 100644 index 0000000..9aefe96 --- /dev/null +++ b/include/modules/script_squirrel/legacy/hash_binding.cpp @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "hash/md5.h" + #include "hash/nsha1.h" + + +//------------------------------------------------------------------------------ +SQInteger MD5(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(source) + + using namespace GS::MD5; + + Digest md5; + + md5_byte_t digest[16]; + md5.Append((const md5_byte_t *)source, GS::String::strlen(source)); + md5.Finish(digest); + + char md5_string[33]; + DigestToString(digest, md5_string); + md5_string[32] = 0; + + __SQ_GETEND + __SQ_RETURNSTRING(md5_string) +} +SQInteger SHA1(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(source) + GS::String hash = GS::SHA1::ComputeHexa(source); + __SQ_GETEND + __SQ_RETURNSTRING(hash.c_str()) +} +//------------------------------------------------------------------------------ + +void RegisterHashBinding(HSQUIRRELVM vm) +{ + using namespace GS::Script; + +/*# + Topic: Hash +#*/ + +/*# + Section: Hashing + Desc: Hashing +#*/ + /*# + Func: MD5 + Proto: String:String source + Desc: Compute a MD5 hexadecimal hash. + #*/ + sq_register(vm, MD5, "MD5", _SC(".s")); + /*# + Func: SHA1 + Proto: String:String source + Desc: Compute a SHA1 hexadecimal hash. + #*/ + sq_register(vm, SHA1, "SHA1", _SC(".s")); +} diff --git a/include/modules/script_squirrel/legacy/http_binding.cpp b/include/modules/script_squirrel/legacy/http_binding.cpp new file mode 100644 index 0000000..6173110 --- /dev/null +++ b/include/modules/script_squirrel/legacy/http_binding.cpp @@ -0,0 +1,169 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "http_curl/http_curl.h" + #include "script_squirrel/legacy/squirrel_binding.h" + #include "script/script_variant.h" + + using namespace GS; + using namespace GS::Script; + + +#if __PLATFORM_EMSCRIPTEN__ + +//------------------------------------------------------------------------------ +SQInteger HttpPost(HSQUIRRELVM vm) +{ + __SQ_RETURN +} +SQInteger HttpUpdate(HSQUIRRELVM vm) +{ + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +#else + +//------------------------------------------------------------------------------ +class SquirrelHTTP : public HTTP::Curl +{ + HSQUIRRELVM vm; + +public: + + void OnRequestComplete(int ticket_id, const Array &data) + { + SquirrelVM *sq_vm = GetVMObject(vm); + + if (sq_vm->SetupFunctionCall("OnHttpRequestComplete")) + { + sq_vm->PushArgument(ticket_id); + + if (data.GetSize() > 0) + { + String str(data.c_ptr(), data.GetCount()); + sq_vm->PushArgument(str.c_str()); + } + else + sq_vm->PushNullArgument(); + + sq_vm->DoFunctionCall(); + } + } + void OnRequestError(int ticket_id) + { + SquirrelVM *sq_vm = GetVMObject(vm); + + if (sq_vm->SetupFunctionCall("OnHttpRequestError")) + { + sq_vm->PushArgument(ticket_id); + sq_vm->DoFunctionCall(); + } + } + + SquirrelHTTP(HSQUIRRELVM v) : vm(v) {} +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger HttpPost(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(url) + __SQ_GETSTRING(post) + SquirrelVM *sq_vm = GetVMObject(vm); + int id = sq_vm->http->Post(url, post); + __SQ_GETEND + __SQ_RETURNINT(id) +} +SQInteger HttpUpdate(HSQUIRRELVM vm) +{ + SquirrelVM *sq_vm = GetVMObject(vm); + sq_vm->http->Update(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ +//#include +#include +SQInteger GetIp(HSQUIRRELVM vm) +{ + String ip_adress; + + char ac[80]; + if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) { + __SQ_RETURNSTRING(""); + } + struct hostent *phe = gethostbyname(ac); + if (phe == 0) { + __SQ_RETURNSTRING(""); + } + + for (int i = 0; phe->h_addr_list[i] != 0; ++i) { + struct in_addr addr; + memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); + ip_adress += String(inet_ntoa(addr)) + String(" "); + } + + __SQ_RETURNSTRING(ip_adress.c_str()) +} +//********************************************************* + +#endif + +void RegisterHTTPBinding(HSQUIRRELVM vm) +{ +#if __PLATFORM_EMSCRIPTEN__ == 0 + SquirrelVM *sq_vm = GetVMObject(vm); + sq_vm->http = new SquirrelHTTP(vm); +#endif + +/*# + Topic: HTTP + Desc: Send HTTP POST request to a remote URL and receive remote response asynchronously. +#*/ + +/*# + Section: HTTP helper + Desc: HTTP helper functions. +#*/ + /*# + Func: HttpUpdate + Proto: void: + Desc: Update the HTTP subsystem. You must call this function to receive queued events. + See: HttpPost + #*/ + sq_register(vm, HttpUpdate, "HttpUpdate", _SC(".")); + /*# + Func: HttpPost + Proto: int:String url, String post + Desc: POST an HTTP request to a remote URL and returns the request identifier.
This function returns immediately, the request result will be sent to the global HTTP script callbacks. + Example: +// POST a request with two parameters to a remote server. +local id = HttpPost("http://www.someurl.com", "param_a=1&param_b=2") +print("HTTP request posted, id: " + id) + +// The two global HTTP request callbacks. +function OnHttpRequestComplete(ticket_id, data) +{ + print("HTTP request " + ticket_id + " complete.") + print("Data received: " + data) +} +function OnHttpRequestError(ticket_id) +{ + print("HTTP request " + ticket_id + " errored.") +} + #*/ + sq_register(vm, HttpPost, "HttpPost", _SC(".ss")); + + + /*# + Func: GetIp + Proto: string:void + Desc: Get local ip. + #*/ + sq_register(vm, GetIp, "GetIp", _SC(".")); +} diff --git a/include/modules/script_squirrel/legacy/instance_binding.cpp b/include/modules/script_squirrel/legacy/instance_binding.cpp new file mode 100644 index 0000000..2fd5be9 --- /dev/null +++ b/include/modules/script_squirrel/legacy/instance_binding.cpp @@ -0,0 +1,63 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "scene3d/instance.h" + #include "scene3d/group.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger InstanceGetItemList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(instance, Instance, typetag_Instance) + sq_newarray(vm, 0); + if (instance->instance_group) + ListForeachPtr(MItem *, i, instance->instance_group->GetItemList()) + { + CObject::Push(vm, (void *)i, typetag_Item); + sq_arrayappend(vm, -2); + } + return 1; +} + +SQInteger InstanceGetTemplatePath(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(instance, Instance, typetag_Instance) + __SQ_RETURNSTRING(instance->template_path.c_str()) +} + + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterInstanceBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Instance + Type: Instance +#*/ + +/*# + Section: InstanceGeneric + Desc: Generic functions +#*/ + /*# + Func: InstanceGetItemList + Proto: array:Instance + Desc: Return instance item list. Note: The instance must have been instantiate to return any item. + #*/ + sq_register(vm, InstanceGetItemList, "InstanceGetItemList", _SC(".x")); + /*# + Func: InstanceGetTemplatePath + Proto: string:Instance + Desc: Return instance path + #*/ + sq_register(vm, InstanceGetTemplatePath, "InstanceGetTemplatePath", _SC(".x")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/io_binding.cpp b/include/modules/script_squirrel/legacy/io_binding.cpp new file mode 100644 index 0000000..a36659b --- /dev/null +++ b/include/modules/script_squirrel/legacy/io_binding.cpp @@ -0,0 +1,1072 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + #include + + #include "binding_helpers.h" + #include "sqstdblob.h" + #include "filesystem/io_handle.h" + #include "filesystem/filesystem.h" + #include "input/input_system.h" + #include "platform.h" + + using namespace GS; + using namespace GS::Input; + using namespace GS::Script; + +#include +#include +#include +typedef unsigned char BYTE; + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +static inline bool is_base64(BYTE c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(BYTE const *buf, unsigned int bufLen) { + std::string ret; + int i = 0; + int j = 0; + BYTE char_array_3[3]; + BYTE char_array_4[4]; + + while (bufLen--) { + char_array_3[i++] = *(buf++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; (i < 4); i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while ((i++ < 3)) + ret += '='; + } + + return ret; +} + +std::vector base64_decode(std::string const &encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + BYTE char_array_4[4], char_array_3[3]; + std::vector ret; + + while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret.push_back(char_array_3[i]); + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) + ret.push_back(char_array_3[j]); + } + + return ret; +} + +SQInteger BlobFromStringBase64(HSQUIRRELVM vm) { + __SQ_GETSTART(1) + __SQ_GETSTRING(data) + __SQ_GETEND; + + std::vector str = base64_decode(std::string(data, strlen(data))); + size_t size = str.size(); + void *p = sqstd_createblob(vm, size); // blob on stack + if (!p) + return sq_throwerror(vm, "Failed to create allocate blob memory."); + + memcpy(p, str.data(), size); + + return 1; +} + +SQInteger BlobToStringBase64(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + SQUserPointer blob; + sqstd_getblob(vm, __sq_stackpos, &blob); + size_t size = sqstd_getblobsize(vm, __sq_stackpos); + __SQ_GETUPDATESTACK + __SQ_GETEND; + + __SQ_RETURNSTRING(base64_encode((const unsigned char *)blob, size).c_str()) +} + +SQInteger BlobFromString(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + // sq_getstring(vm, __sq_stackpos, &__VARNAME__); __SQ_GETUPDATESTACK + __SQ_GETSTRING(data) + __SQ_GETEND + size_t size = strlen(data); + void *p = sqstd_createblob(vm, size); // blob on stack + if (!p) + return sq_throwerror(vm, "Failed to create allocate blob memory."); + + memcpy(p, data, strlen(data)); + + return 1; +} + +//------------------------------------------------------------------------------ +SQInteger GetMouseDevice(HSQUIRRELVM vm) +{ __SQ_RETURNSAFEPTR(Platform::Get().input_system->GetDevice("mouse"), typetag_InputDevice) } +SQInteger GetKeyboardDevice(HSQUIRRELVM vm) +{ __SQ_RETURNSAFEPTR(Platform::Get().input_system->GetDevice("keyboard"), typetag_InputDevice) } +SQInteger GetInputDevice(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(name) + Device *device = Platform::Get().input_system->GetDevice(name); + __SQ_GETEND + __SQ_RETURNSAFEPTR(device, typetag_InputDevice) +} +SQInteger GetInputDeviceFromGuid(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(guid) + Device *device = Platform::Get().input_system->GetDeviceFromGuid(guid); + __SQ_GETEND + __SQ_RETURNSAFEPTR(device, typetag_InputDevice) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger DeviceIsKeyDown(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(device, Device, typetag_InputDevice) + __SQ_GETINT(key) + __SQ_GETEND + __SQ_RETURNBOOL(device->IsDown((Device::KeyCode)key)) +} +SQInteger DeviceWasKeyDown(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(device, Device, typetag_InputDevice) + __SQ_GETINT(key) + __SQ_GETEND + __SQ_RETURNBOOL(device->WasDown((Device::KeyCode)key)) +} +SQInteger DeviceKeyPressed(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(device, Device, typetag_InputDevice) + __SQ_GETINT(key) + __SQ_GETEND + __SQ_RETURNBOOL(device->IsDown((Device::KeyCode)key) && !device->WasDown((Device::KeyCode)key)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger DeviceInputSetValue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(device, Device, typetag_InputDevice) + __SQ_GETINT(input) + __SQ_GETFLOAT(value) + __SQ_GETEND + __SQ_RETURNBOOL(device->SetValue((Device::InputCode)input, value)) +} +SQInteger DeviceInputValue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(device, Device, typetag_InputDevice) + __SQ_GETINT(input) + __SQ_GETEND + __SQ_RETURNFLOAT(device->GetValue((Device::InputCode)input)) +} +SQInteger DeviceInputLastValue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(device, Device, typetag_InputDevice) + __SQ_GETINT(input) + __SQ_GETEND + __SQ_RETURNFLOAT(device->GetLastValue((Device::InputCode)input)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger GetDeviceList(HSQUIRRELVM vm) +{ + StringList list; + Platform::Get().input_system->GetDeviceList(list); + + sq_newarray(vm, 0); + ListForeach(String, name, list) + { + sq_pushstring(vm, name.Object().c_str(), name.Object().Len()); + sq_arrayappend(vm, -2); + } + return 1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger GetDeviceGuidList(HSQUIRRELVM vm) +{ + StringList list; + Platform::Get().input_system->GetDeviceGuidList(list); + + sq_newarray(vm, 0); + ListForeach(String, name, list) + { + sq_pushstring(vm, name.Object().c_str(), name.Object().Len()); + sq_arrayappend(vm, -2); + } + return 1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger DeviceSetEffect(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(device, Device, typetag_InputDevice) + __SQ_GETINT(effect) + __SQ_GETFLOAT(v) + __SQ_GETEND + device->SetEffect(Device::Effect(effect), v); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger Include(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(path) + + SquirrelVM *sqvm = (SquirrelVM *)sq_getforeignptr(vm); + + Array data; + if (!Platform::Get().io->FileLoad(path, data) || !sqvm->Compile(data, data.GetCount(), NULL, path)) + return sq_throwerror(vm, String::Format("Failed to include script '%s'.", path).c_str()); + + __SQ_GETEND + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//-------------------------------------------- +SQInteger FileRename(HSQUIRRELVM vm) +//-------------------------------------------- +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(oldname) + __SQ_GETSTRING(newname) + bool r = oldname && newname ? !rename(oldname, newname) : false; + __SQ_GETEND + __SQ_RETURNBOOL(r) +} + +//-------------------------------------------- +SQInteger FileDelete(HSQUIRRELVM vm) +//-------------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(filename) + bool r = Platform::Get().io->Delete(filename) ; + __SQ_GETEND + __SQ_RETURNBOOL(r) +} + +SQInteger FolderCreate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(foldername) + + bool r = Platform::Get().io->MkDir(foldername); + + __SQ_GETEND + __SQ_RETURNBOOL(r) +} + +#include +#include +SQInteger FolderExist(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(foldername) + + __SQ_GETEND + + bool r = false; + DWORD ftyp = GetFileAttributesA(foldername); + if (ftyp == INVALID_FILE_ATTRIBUTES) + __SQ_RETURNBOOL(false); //something is wrong with your path! + + if (ftyp & FILE_ATTRIBUTE_DIRECTORY) + __SQ_RETURNBOOL(true); // this is a directory! + + __SQ_RETURNBOOL(false) +} + +SQInteger FileCopy(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(src) + __SQ_GETSTRING(dst) + + bool r = Platform::Get().io->FileCopy(src, dst); + + __SQ_GETEND + __SQ_RETURNBOOL(r) +} + +SQInteger FileMove(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(src) + __SQ_GETSTRING(dst) + + bool r = Platform::Get().io->FileMove(src, dst); + + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger FileExists(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(uri) + bool r = Platform::Get().io->Exists(uri); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger FileReadAsBlob(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(name) + AutoPtr h(Platform::Get().io->Open(name)); + if (h.IsNull()) + return sq_throwerror(vm, String::Format("Failed to open file '%s'.", name)); + + size_t size = h->GetSize(); + void *p = sqstd_createblob(vm, size); // blob on stack + if (!p) + return sq_throwerror(vm, "Failed to create allocate blob memory."); + h->Read(p, size); + + __SQ_GETEND + return 1; +} +SQInteger FileWriteFromBlob(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(name) + void *p = NULL; + sqstd_getblob(vm, __SQ_STACKPOS, &p); + size_t size = sqstd_getblobsize(vm, __SQ_STACKPOS); + __SQ_GETUPDATESTACK + + AutoPtr h(Platform::Get().io->Open(name, IO::ModeWrite)); + if (h.IsNull()) + return sq_throwerror(vm, String::Format("Failed to open file '%s'.", name)); + if (h->Write(p, size) != size) + return sq_throwerror(vm, String::Format("An error occurred while writing blob to file '%s'.", name)); + __SQ_GETEND + __SQ_RETURN +} + +SQInteger FileWriteFromString(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(name) + __SQ_GETSTRING(text) + + AutoPtr h(Platform::Get().io->Open(name, IO::ModeWrite)); + if (h.IsNull()) + return sq_throwerror(vm, String::Format("Failed to open file '%s'.", name)); + if (!h->Write(text, String(text).Size())) + return sq_throwerror(vm, String::Format("An error occurred while writing string to file '%s'.", name)); + __SQ_GETEND + __SQ_RETURN +} + +SQInteger FileOpen(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(name) + __SQ_GETINT(mode) + + AutoPtr h(Platform::Get().io->Open(name, (GS::IO::Mode)mode)); + if (h.IsNull()) + return sq_throwerror(vm, String::Format("Failed to open file '%s'.", name)); + + __SQ_GETEND + __SQ_RETURNSAFEPTR(h.Detach(), typetag_FileHandle) +} + +SQInteger FileClose(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(h, IO::Handle, typetag_FileHandle) + h->GetIOSystem()->Close(h); + delete h; + __SQ_RETURN +} + +SQInteger FileWriteFloat(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(h, IO::Handle, typetag_FileHandle) + __SQ_GETFLOAT(f) + __SQ_GETEND + h->Write(f); + + __SQ_RETURN +} +SQInteger FileReadFloat(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(h, IO::Handle, typetag_FileHandle) + float f = h->Read(); + + __SQ_RETURNFLOAT(f) +} +SQInteger FileWriteInt(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(h, IO::Handle, typetag_FileHandle) + __SQ_GETINT(i) + __SQ_GETEND + h->Write(i); + + __SQ_RETURN +} +SQInteger FileReadInt(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(h, IO::Handle, typetag_FileHandle) + int i = h->Read(); + + __SQ_RETURNINT(i) +} +//------------------------------------------------------------------------------ + +//--------------------------------------------------- +void RegisterIOBinding(HSQUIRRELVM vm) +//--------------------------------------------------- +{ + sq_register(vm, Include, "Include", _SC(".s")); + sq_register(vm, Include, "Import", _SC(".s")); + +/*# + Topic: I/O + Type: InputDevice + Desc: Read inputs from devices connected to the host system. +#*/ + +/*# + Section: FileManipulation + Desc: File manipulation functions +#*//*# + Func: FileRename + Proto: int:string old,string new + Desc: Rename a file. + #*/ + sq_register(vm, FileRename, "FileRename", _SC(".ss")); + /*# + Func: FileDelete + Proto: int:string filename + Desc: delete a file. + #*/ + sq_register(vm, FileDelete, "FileDelete", _SC(".s")); + /*# + Func: FolderExist + Proto: bool:string filename + Desc: check if a folder exist. + #*/ + sq_register(vm, FolderExist, "FolderExist", _SC(".s")); + /*# + Func: FileCopy + Proto: void:String src,string dst + Desc: copy the file src in dst. + #*/ + sq_register(vm, FileCopy, "FileCopy", _SC(".ss")); + /*# + Func: FileMove + Proto: void:String src,string dst + Desc: move the file src in dst. + #*/ + sq_register(vm, FileMove, "FileMove", _SC(".ss")); + /*# + Func: FolderCreate + Proto: int:string folder + Desc: create a folder. + #*/ + sq_register(vm, FolderCreate, "FolderCreate", _SC(".s")); + /*# + Func: FileExists + Proto: bool:String name + Desc: Returns true if the file 'name' can be accessed by the platform's file system. + #*/ + sq_register(vm, FileExists, "FileExists", _SC(".s")); + /*# + Func: FileReadAsBlob + Proto: Blob:String name + Desc: Load a file as a Squirrel blob. + #*/ + sq_register(vm, FileReadAsBlob, "FileReadAsBlob", _SC(".s")); + /*# + Func: FileWriteFromBlob + Proto: void:String name,Blob + Desc: Write a Squirrel blob to a file. + #*/ + sq_register(vm, FileWriteFromBlob, "FileWriteFromBlob", _SC(".s.")); + /*# + Func: FileWriteFromString + Proto: void:String name,string + Desc: Write a string to a file. + #*/ + sq_register(vm, FileWriteFromString, "FileWriteFromString", _SC(".ss")); + + /*# + Func: FileOpen + Proto: void:String name,int mode + Desc: open a file. + #*/ + sq_register(vm, FileOpen, "FileOpen", _SC(".si")); + /*# + Func: FileClose + Proto: void:File + Desc: Close the file. + #*/ + sq_register(vm, FileClose, "FileClose", _SC(".x")); + /*# + Func: FileWriteFloat + Proto: void:File, float + Desc: write the float to the file. + #*/ + sq_register(vm, FileWriteFloat, "FileWriteFloat", _SC(".xn")); + /*# + Func: FileReadFloat + Proto: float:File + Desc: read the float to the file. + #*/ + sq_register(vm, FileReadFloat, "FileReadFloat", _SC(".x")); + + /*# + Func: FileWriteInt + Proto: void:File, int + Desc: write the int to the file. + #*/ + sq_register(vm, FileWriteInt, "FileWriteInt", _SC(".xi")); + /*# + Func: FileReadInt + Proto: int:File + Desc: read the int to the file. + #*/ + sq_register(vm, FileReadInt, "FileReadInt", _SC(".x")); + +/*# + Section: InputDeviceQuery + Desc: Input device query functions +#*/ + /*# + Func: GetMouseDevice + Proto: InputDevice: + Desc: Get platform mouse device. + #*/ + sq_register(vm, GetMouseDevice, "GetMouseDevice", _SC(".")); + /*# + Func: GetKeyboardDevice + Proto: InputDevice: + Desc: Get platform keyboard device. + #*/ + sq_register(vm, GetKeyboardDevice, "GetKeyboardDevice", _SC(".")); + /*# + Func: GetInputDevice + Proto: InputDevice:String name + Desc: Get a platform device from its name. + #*/ + sq_register(vm, GetInputDevice, "GetInputDevice", _SC(".s")); + /*# + Func: GetInputDeviceFromGuid + Proto: InputDevice:String Guid + Desc: Get a platform device from its Guid. + #*/ + sq_register(vm, GetInputDeviceFromGuid, "GetInputDeviceFromGuid", _SC(".s")); + /*# + Func: GetDeviceList + Proto: List:void + Desc: Get a platform devices list. + Example: +// Get the name of all devices connected to this machine. +local devices = GetDeviceList() + +print("Available devices:") +foreach(device_name, i in devices) + print("Device " + i + ": " + device_name) + +// Create the first device from the list. +local device = GetInputDevice(devices[0]) + #*/ + sq_register(vm, GetDeviceList, "GetDeviceList", _SC(".")); + /*# + Func: GetDeviceGuidList + Proto: List:void + Desc: Get a platform devices guid list. + Example: +// Get the name of all devices connected to this machine. +local devices = GetDeviceGuidList() + +print("Available devices:") +foreach(device_guid, i in devices) + print("Device " + i + ": " + device_guid) + +// Create the first device from the list. +local device = GetInputDevice(devices[0]) + #*/ + sq_register(vm, GetDeviceGuidList, "GetDeviceGuidList", _SC(".")); + /*# + Func: DeviceSetEffect + Proto: void:InputDevice device,DeviceEffect effect,float value + Desc: Set device effect. + Example: +// Retrieve the input device connected to XInput port 1. +local device = GetInputDevice("XInput1") + +// Set full vibration on the left motor of the device. +DeviceSetEffect(device, DeviceEffectVibrateLeft, 1.0) + #*/ + sq_register(vm, DeviceSetEffect, "DeviceSetEffect", _SC(".xin")); + +/*# + Section: InputDeviceState + Desc: Input device state functions +#*/ + /*# + Func: DeviceIsKeyDown + Proto: bool:InputDevice,DeviceKey + Desc: Returns true if the given device key is currently down, false otherwise. + Note: The DeviceKey enumeration cannot be used to read analog inputs.
+ Only binary on/off inputs from the device are mapped to this enumeration. + See: DeviceInputLastValue + #*/ + sq_register(vm, DeviceIsKeyDown, "DeviceIsKeyDown", _SC(".xi")); + /*# + Func: DeviceWasKeyDown + Proto: bool:InputDevice,DeviceKey + Desc: Returns true if the given device key was down during the last device update, false otherwise. + #*/ + sq_register(vm, DeviceWasKeyDown, "DeviceWasKeyDown", _SC(".xi")); + /*# + Func: DeviceKeyPressed + Proto: bool:InputDevice,DeviceKey + Desc: Returns true if the given device key was released during the current update, false otherwise. + #*/ + sq_register(vm, DeviceKeyPressed, "DeviceKeyPressed", _SC(".xi")); + /*# + Func: DeviceInputSetValue + Proto: bool:InputDevice,DeviceInput,float new_value + Desc: Returns true if the device could set the value. + Example: +// Get the mouse device. +local mouse_device = GetMouseDevice() + +// Center the mouse cursor on screen. +DeviceInputSetValue(mouse_device, DeviceAxisX, 0.5) +DeviceInputSetValue(mouse_device, DeviceAxisY, 0.5) + #*/ + sq_register(vm, DeviceInputSetValue, "DeviceInputSetValue", _SC(".xin")); + /*# + Func: DeviceInputValue + Proto: float:InputDevice,DeviceInput + Desc: Returns the current value of a device input. + #*/ + sq_register(vm, DeviceInputValue, "DeviceInputValue", _SC(".xi")); + /*# + Func: DeviceInputLastValue + Proto: float:InputDevice,DeviceInput + Desc: Returns the value of a device input during the last update. + Note: A DeviceInput can return a range of values and not only a simple on/off state value.
+ In order to access binary on/off inputs please use the DeviceIsKeyDown function. + See: DeviceIsKeyDown + #*/ + sq_register(vm, DeviceInputLastValue, "DeviceInputLastValue", _SC(".xi")); + + /*# + Func: BlobFromString + Proto: Blob:String data + Desc: Load data as a Squirrel blob. + #*/ + sq_register(vm, BlobFromString, "BlobFromString", _SC(".s")); + + /*# + Func: BlobFromStringBase64 + Proto: Blob:String base64 data + Desc: Load data as a Squirrel blob. + #*/ + sq_register(vm, BlobFromStringBase64, "BlobFromStringBase64", _SC(".s")); + + /*# + Func: BlobToStringBase64 + Proto: String base64 data: Blob + Desc: Load data as a Squirrel blob. + #*/ + sq_register(vm, BlobToStringBase64, "BlobToStringBase64", _SC(".x")); + + // Defines. + sq_pushroottable(vm); + + /*# + Enum: DeviceType + Values: DeviceTypeKeyboard,DeviceTypeMouse,DeviceTypeGame + #*/ + sq_pushstring(vm, "DeviceTypeKeyboard", -1); sq_pushinteger(vm, Device::Type_Keyboard); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceTypeMouse", -1); sq_pushinteger(vm, Device::Type_Mouse); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceTypeGame", -1); sq_pushinteger(vm, Device::Type_Pad); sq_newslot(vm, -3, true); + + /*# + Enum: DeviceEffect + Values: DeviceEffectVibrate,DeviceEffectVibrateLeft,DeviceEffectVibrateRight,DeviceEffectConstantForce + #*/ + sq_pushstring(vm, "DeviceEffectVibrate", -1); sq_pushinteger(vm, Device::Vibrate); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceEffectVibrateLeft", -1); sq_pushinteger(vm, Device::VibrateLeft); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceEffectVibrateRight", -1); sq_pushinteger(vm, Device::VibrateRight); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceEffectConstantForce", -1); sq_pushinteger(vm, Device::ConstantForce); sq_newslot(vm, -3, true); + + /*# + Enum: DeviceInput + Values: DeviceAxisX,DeviceAxisY,DeviceAxisZ,DeviceAxisS,DeviceAxisT,DeviceAxisR,DeviceAxisRotX,DeviceAxisRotY,DeviceAxisRotZ,DeviceAxisRotS,DeviceAxisRotT,DeviceAxisRotR, + DeviceButton0,DeviceButton1,DeviceButton2,DeviceButton3,DeviceButton4,DeviceButton5,DeviceButton6,DeviceButton7,DeviceButton8, + DeviceButton9,DeviceButton10,DeviceButton11,DeviceButton12,DeviceButton13,DeviceButton14,DeviceButton15 + Desc: Device inputs can take a large range of values, they offer more precision than the simpler on/off device keys. + #*/ + sq_pushstring(vm, "DeviceAxisX", -1); sq_pushinteger(vm, Device::Input_AxisX); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisY", -1); sq_pushinteger(vm, Device::Input_AxisY); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisZ", -1); sq_pushinteger(vm, Device::Input_AxisZ); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisS", -1); sq_pushinteger(vm, Device::Input_AxisS); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisT", -1); sq_pushinteger(vm, Device::Input_AxisT); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisR", -1); sq_pushinteger(vm, Device::Input_AxisR); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisRotX", -1); sq_pushinteger(vm, Device::Input_RotX); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisRotY", -1); sq_pushinteger(vm, Device::Input_RotY); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisRotZ", -1); sq_pushinteger(vm, Device::Input_RotZ); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisRotS", -1); sq_pushinteger(vm, Device::Input_RotS); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisRotT", -1); sq_pushinteger(vm, Device::Input_RotT); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceAxisRotR", -1); sq_pushinteger(vm, Device::Input_RotR); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "DeviceButton0", -1); sq_pushinteger(vm, Device::Input_Button0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton1", -1); sq_pushinteger(vm, Device::Input_Button1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton2", -1); sq_pushinteger(vm, Device::Input_Button2); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton3", -1); sq_pushinteger(vm, Device::Input_Button3); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton4", -1); sq_pushinteger(vm, Device::Input_Button4); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton5", -1); sq_pushinteger(vm, Device::Input_Button5); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton6", -1); sq_pushinteger(vm, Device::Input_Button6); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton7", -1); sq_pushinteger(vm, Device::Input_Button7); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton8", -1); sq_pushinteger(vm, Device::Input_Button8); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton9", -1); sq_pushinteger(vm, Device::Input_Button9); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton10", -1); sq_pushinteger(vm, Device::Input_Button10); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton11", -1); sq_pushinteger(vm, Device::Input_Button11); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton12", -1); sq_pushinteger(vm, Device::Input_Button12); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton13", -1); sq_pushinteger(vm, Device::Input_Button13); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton14", -1); sq_pushinteger(vm, Device::Input_Button14); sq_newslot(vm, -3, true); + sq_pushstring(vm, "DeviceButton15", -1); sq_pushinteger(vm, Device::Input_Button15); sq_newslot(vm, -3, true); + + /*# + Enum: DeviceKey + Values: KeyLShift,KeyRShift,KeyLCtrl,KeyRCtrl,KeyLAlt,KeyRAlt,KeyLWin,KeyRWin, + KeyTab,KeyCapsLock,KeySpace,KeyBackspace,KeyReturn,KeyInsert,KeySuppr,KeyHome,KeyEnd,KeyPageUp,KeyPageDown, + KeyUpArrow,KeyDownArrow,KeyLeftArrow,KeyRightArrow, + KeyEscape, + KeyF1,KeyF2,KeyF3,KeyF4,KeyF5,KeyF6,KeyF7,KeyF8,KeyF9,KeyF10,KeyF11,KeyF12, + KeyPrintScreen,KeyScrollLock,KeyPause,KeyNumLock,KeyReturn, + KeyNumpad0,KeyNumpad1,KeyNumpad2,KeyNumpad3,KeyNumpad4,KeyNumpad5,KeyNumpad6,KeyNumpad7,KeyNumpad8,KeyNumpad9, + KeyAdd,KeySub,KeyMul,KeyDiv,KeyEnter, + KeyA,KeyB,KeyC,KeyD,KeyE,KeyF,KeyG,KeyH,KeyI,KeyJ,KeyK,KeyL,KeyM,KeyN,KeyO,KeyP,KeyQ,KeyR,KeyS,KeyT,KeyU,KeyV,KeyW,KeyX,KeyY,KeyZ, + KeyButton0,KeyButton1,KeyButton2,KeyButton3,KeyButton4,KeyButton5,KeyButton6,KeyButton7,KeyButton8,KeyButton9, + KeyButton10,KeyButton11,KeyButton12,KeyButton13,KeyButton14,KeyButton15,KeyButton16,KeyButton17,KeyButton18,KeyButton19, + KeyButton20,KeyButton21,KeyButton22,KeyButton23,KeyButton24,KeyButton25,KeyButton26,KeyButton27,KeyButton28,KeyButton29, + KeyButton30, + KeyCrossUp,KeyCrossDown,KeyCrossLeft,KeyCrossRight, + KeyBack,KeyStart,KeySelect,KeyL1,KeyL2,KeyL3,KeyR1,KeyR2,KeyR3 + Desc: Device keys are binary values, a device key can only be pressed or released at any given time. + #*/ + sq_pushstring(vm, "KeyLShift", -1); sq_pushinteger(vm, Device::Key_LShift); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyRShift", -1); sq_pushinteger(vm, Device::Key_RShift); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyLCtrl", -1); sq_pushinteger(vm, Device::Key_LCtrl); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyRCtrl", -1); sq_pushinteger(vm, Device::Key_RCtrl); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyLAlt", -1); sq_pushinteger(vm, Device::Key_LAlt); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyRAlt", -1); sq_pushinteger(vm, Device::Key_RAlt); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyLWin", -1); sq_pushinteger(vm, Device::Key_LWin); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyRWin", -1); sq_pushinteger(vm, Device::Key_RWin); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyTab", -1); sq_pushinteger(vm, Device::Key_Tab); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyCapsLock", -1); sq_pushinteger(vm, Device::Key_CapsLock); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeySpace", -1); sq_pushinteger(vm, Device::Key_Space); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyBackspace", -1); sq_pushinteger(vm, Device::Key_Backspace); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyReturn", -1); sq_pushinteger(vm, Device::Key_Return); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyAdd", -1); sq_pushinteger(vm, Device::Key_Add); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeySub", -1); sq_pushinteger(vm, Device::Key_Sub); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyMul", -1); sq_pushinteger(vm, Device::Key_Mul); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyDiv", -1); sq_pushinteger(vm, Device::Key_Div); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyEnter", -1); sq_pushinteger(vm, Device::Key_Enter); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyInsert", -1); sq_pushinteger(vm, Device::Key_Insert); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeySuppr", -1); sq_pushinteger(vm, Device::Key_Suppr); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyHome", -1); sq_pushinteger(vm, Device::Key_Home); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyEnd", -1); sq_pushinteger(vm, Device::Key_End); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyPageUp", -1); sq_pushinteger(vm, Device::Key_PageUp); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyPageDown", -1); sq_pushinteger(vm, Device::Key_PageDown); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyUpArrow", -1); sq_pushinteger(vm, Device::Key_Up); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyDownArrow", -1); sq_pushinteger(vm, Device::Key_Down); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyLeftArrow", -1); sq_pushinteger(vm, Device::Key_Left); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyRightArrow", -1); sq_pushinteger(vm, Device::Key_Right); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyEscape", -1); sq_pushinteger(vm, Device::Key_Escape); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF1", -1); sq_pushinteger(vm, Device::Key_F1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF2", -1); sq_pushinteger(vm, Device::Key_F2); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF3", -1); sq_pushinteger(vm, Device::Key_F3); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF4", -1); sq_pushinteger(vm, Device::Key_F4); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF5", -1); sq_pushinteger(vm, Device::Key_F5); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF6", -1); sq_pushinteger(vm, Device::Key_F6); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF7", -1); sq_pushinteger(vm, Device::Key_F7); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF8", -1); sq_pushinteger(vm, Device::Key_F8); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF9", -1); sq_pushinteger(vm, Device::Key_F9); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF10", -1); sq_pushinteger(vm, Device::Key_F10); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF11", -1); sq_pushinteger(vm, Device::Key_F11); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF12", -1); sq_pushinteger(vm, Device::Key_F12); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyPrintScreen", -1); sq_pushinteger(vm, Device::Key_PrintScreen); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyScrollLock", -1); sq_pushinteger(vm, Device::Key_ScrollLock); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyPause", -1); sq_pushinteger(vm, Device::Key_Pause); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyNumLock", -1); sq_pushinteger(vm, Device::Key_NumLock); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyEnter", -1); sq_pushinteger(vm, Device::Key_Enter); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyNumpad0", -1); sq_pushinteger(vm, Device::Key_Numpad0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad1", -1); sq_pushinteger(vm, Device::Key_Numpad1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad2", -1); sq_pushinteger(vm, Device::Key_Numpad2); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad3", -1); sq_pushinteger(vm, Device::Key_Numpad3); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad4", -1); sq_pushinteger(vm, Device::Key_Numpad4); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad5", -1); sq_pushinteger(vm, Device::Key_Numpad5); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad6", -1); sq_pushinteger(vm, Device::Key_Numpad6); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad7", -1); sq_pushinteger(vm, Device::Key_Numpad7); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad8", -1); sq_pushinteger(vm, Device::Key_Numpad8); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyNumpad9", -1); sq_pushinteger(vm, Device::Key_Numpad9); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyA", -1); sq_pushinteger(vm, Device::Key_A); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyB", -1); sq_pushinteger(vm, Device::Key_B); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyC", -1); sq_pushinteger(vm, Device::Key_C); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyD", -1); sq_pushinteger(vm, Device::Key_D); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyE", -1); sq_pushinteger(vm, Device::Key_E); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyF", -1); sq_pushinteger(vm, Device::Key_F); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyG", -1); sq_pushinteger(vm, Device::Key_G); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyH", -1); sq_pushinteger(vm, Device::Key_H); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyI", -1); sq_pushinteger(vm, Device::Key_I); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyJ", -1); sq_pushinteger(vm, Device::Key_J); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyK", -1); sq_pushinteger(vm, Device::Key_K); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyL", -1); sq_pushinteger(vm, Device::Key_L); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyM", -1); sq_pushinteger(vm, Device::Key_M); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyN", -1); sq_pushinteger(vm, Device::Key_N); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyO", -1); sq_pushinteger(vm, Device::Key_O); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyP", -1); sq_pushinteger(vm, Device::Key_P); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyQ", -1); sq_pushinteger(vm, Device::Key_Q); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyR", -1); sq_pushinteger(vm, Device::Key_R); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyS", -1); sq_pushinteger(vm, Device::Key_S); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyT", -1); sq_pushinteger(vm, Device::Key_T); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyU", -1); sq_pushinteger(vm, Device::Key_U); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyV", -1); sq_pushinteger(vm, Device::Key_V); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyW", -1); sq_pushinteger(vm, Device::Key_W); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyX", -1); sq_pushinteger(vm, Device::Key_X); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyY", -1); sq_pushinteger(vm, Device::Key_Y); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyZ", -1); sq_pushinteger(vm, Device::Key_Z); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyButton0", -1); sq_pushinteger(vm, Device::Key_Button0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton1", -1); sq_pushinteger(vm, Device::Key_Button1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton2", -1); sq_pushinteger(vm, Device::Key_Button2); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton3", -1); sq_pushinteger(vm, Device::Key_Button3); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton4", -1); sq_pushinteger(vm, Device::Key_Button4); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton5", -1); sq_pushinteger(vm, Device::Key_Button5); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton6", -1); sq_pushinteger(vm, Device::Key_Button6); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton7", -1); sq_pushinteger(vm, Device::Key_Button7); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton8", -1); sq_pushinteger(vm, Device::Key_Button8); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton9", -1); sq_pushinteger(vm, Device::Key_Button9); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton10", -1); sq_pushinteger(vm, Device::Key_Button10); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton11", -1); sq_pushinteger(vm, Device::Key_Button11); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton12", -1); sq_pushinteger(vm, Device::Key_Button12); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton13", -1); sq_pushinteger(vm, Device::Key_Button13); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton14", -1); sq_pushinteger(vm, Device::Key_Button14); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton15", -1); sq_pushinteger(vm, Device::Key_Button15); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton16", -1); sq_pushinteger(vm, Device::Key_Button16); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton17", -1); sq_pushinteger(vm, Device::Key_Button17); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton18", -1); sq_pushinteger(vm, Device::Key_Button18); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton19", -1); sq_pushinteger(vm, Device::Key_Button19); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton20", -1); sq_pushinteger(vm, Device::Key_Button20); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton21", -1); sq_pushinteger(vm, Device::Key_Button21); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton22", -1); sq_pushinteger(vm, Device::Key_Button22); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton23", -1); sq_pushinteger(vm, Device::Key_Button23); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton24", -1); sq_pushinteger(vm, Device::Key_Button24); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton25", -1); sq_pushinteger(vm, Device::Key_Button25); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton26", -1); sq_pushinteger(vm, Device::Key_Button26); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton27", -1); sq_pushinteger(vm, Device::Key_Button27); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton28", -1); sq_pushinteger(vm, Device::Key_Button28); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton29", -1); sq_pushinteger(vm, Device::Key_Button29); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton30", -1); sq_pushinteger(vm, Device::Key_Button30); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton31", -1); sq_pushinteger(vm, Device::Key_Button31); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton32", -1); sq_pushinteger(vm, Device::Key_Button32); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton33", -1); sq_pushinteger(vm, Device::Key_Button33); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton34", -1); sq_pushinteger(vm, Device::Key_Button34); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton35", -1); sq_pushinteger(vm, Device::Key_Button35); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton36", -1); sq_pushinteger(vm, Device::Key_Button36); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton37", -1); sq_pushinteger(vm, Device::Key_Button37); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton38", -1); sq_pushinteger(vm, Device::Key_Button38); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton39", -1); sq_pushinteger(vm, Device::Key_Button39); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton40", -1); sq_pushinteger(vm, Device::Key_Button40); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton41", -1); sq_pushinteger(vm, Device::Key_Button41); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton42", -1); sq_pushinteger(vm, Device::Key_Button42); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton43", -1); sq_pushinteger(vm, Device::Key_Button43); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton44", -1); sq_pushinteger(vm, Device::Key_Button44); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton45", -1); sq_pushinteger(vm, Device::Key_Button45); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton46", -1); sq_pushinteger(vm, Device::Key_Button46); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton47", -1); sq_pushinteger(vm, Device::Key_Button47); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton48", -1); sq_pushinteger(vm, Device::Key_Button48); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton49", -1); sq_pushinteger(vm, Device::Key_Button49); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton50", -1); sq_pushinteger(vm, Device::Key_Button50); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton51", -1); sq_pushinteger(vm, Device::Key_Button51); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton52", -1); sq_pushinteger(vm, Device::Key_Button52); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton53", -1); sq_pushinteger(vm, Device::Key_Button53); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton54", -1); sq_pushinteger(vm, Device::Key_Button54); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton55", -1); sq_pushinteger(vm, Device::Key_Button55); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton56", -1); sq_pushinteger(vm, Device::Key_Button56); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton57", -1); sq_pushinteger(vm, Device::Key_Button57); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton58", -1); sq_pushinteger(vm, Device::Key_Button58); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton59", -1); sq_pushinteger(vm, Device::Key_Button59); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton60", -1); sq_pushinteger(vm, Device::Key_Button60); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton61", -1); sq_pushinteger(vm, Device::Key_Button61); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton62", -1); sq_pushinteger(vm, Device::Key_Button62); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton63", -1); sq_pushinteger(vm, Device::Key_Button63); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton64", -1); sq_pushinteger(vm, Device::Key_Button64); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton65", -1); sq_pushinteger(vm, Device::Key_Button65); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton66", -1); sq_pushinteger(vm, Device::Key_Button66); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton67", -1); sq_pushinteger(vm, Device::Key_Button67); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton68", -1); sq_pushinteger(vm, Device::Key_Button68); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton69", -1); sq_pushinteger(vm, Device::Key_Button69); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton70", -1); sq_pushinteger(vm, Device::Key_Button70); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton71", -1); sq_pushinteger(vm, Device::Key_Button71); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton72", -1); sq_pushinteger(vm, Device::Key_Button72); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton73", -1); sq_pushinteger(vm, Device::Key_Button73); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton74", -1); sq_pushinteger(vm, Device::Key_Button74); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton75", -1); sq_pushinteger(vm, Device::Key_Button75); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton76", -1); sq_pushinteger(vm, Device::Key_Button76); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton77", -1); sq_pushinteger(vm, Device::Key_Button77); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton78", -1); sq_pushinteger(vm, Device::Key_Button78); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton79", -1); sq_pushinteger(vm, Device::Key_Button79); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton80", -1); sq_pushinteger(vm, Device::Key_Button80); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton81", -1); sq_pushinteger(vm, Device::Key_Button81); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton82", -1); sq_pushinteger(vm, Device::Key_Button82); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton83", -1); sq_pushinteger(vm, Device::Key_Button83); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton84", -1); sq_pushinteger(vm, Device::Key_Button84); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton85", -1); sq_pushinteger(vm, Device::Key_Button85); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton86", -1); sq_pushinteger(vm, Device::Key_Button86); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton87", -1); sq_pushinteger(vm, Device::Key_Button87); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton88", -1); sq_pushinteger(vm, Device::Key_Button88); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton89", -1); sq_pushinteger(vm, Device::Key_Button89); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton90", -1); sq_pushinteger(vm, Device::Key_Button90); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton91", -1); sq_pushinteger(vm, Device::Key_Button91); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton92", -1); sq_pushinteger(vm, Device::Key_Button92); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton93", -1); sq_pushinteger(vm, Device::Key_Button93); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton94", -1); sq_pushinteger(vm, Device::Key_Button94); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton95", -1); sq_pushinteger(vm, Device::Key_Button95); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton96", -1); sq_pushinteger(vm, Device::Key_Button96); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton97", -1); sq_pushinteger(vm, Device::Key_Button97); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton98", -1); sq_pushinteger(vm, Device::Key_Button98); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton99", -1); sq_pushinteger(vm, Device::Key_Button99); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton100", -1); sq_pushinteger(vm, Device::Key_Button100); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton101", -1); sq_pushinteger(vm, Device::Key_Button101); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton102", -1); sq_pushinteger(vm, Device::Key_Button102); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton103", -1); sq_pushinteger(vm, Device::Key_Button103); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton104", -1); sq_pushinteger(vm, Device::Key_Button104); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton105", -1); sq_pushinteger(vm, Device::Key_Button105); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton106", -1); sq_pushinteger(vm, Device::Key_Button106); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton107", -1); sq_pushinteger(vm, Device::Key_Button107); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton108", -1); sq_pushinteger(vm, Device::Key_Button108); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton109", -1); sq_pushinteger(vm, Device::Key_Button109); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton110", -1); sq_pushinteger(vm, Device::Key_Button110); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton111", -1); sq_pushinteger(vm, Device::Key_Button111); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton112", -1); sq_pushinteger(vm, Device::Key_Button112); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton113", -1); sq_pushinteger(vm, Device::Key_Button113); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton114", -1); sq_pushinteger(vm, Device::Key_Button114); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton115", -1); sq_pushinteger(vm, Device::Key_Button115); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton116", -1); sq_pushinteger(vm, Device::Key_Button116); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton117", -1); sq_pushinteger(vm, Device::Key_Button117); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton118", -1); sq_pushinteger(vm, Device::Key_Button118); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton119", -1); sq_pushinteger(vm, Device::Key_Button119); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton120", -1); sq_pushinteger(vm, Device::Key_Button120); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton121", -1); sq_pushinteger(vm, Device::Key_Button121); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton122", -1); sq_pushinteger(vm, Device::Key_Button122); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton123", -1); sq_pushinteger(vm, Device::Key_Button123); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton124", -1); sq_pushinteger(vm, Device::Key_Button124); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton125", -1); sq_pushinteger(vm, Device::Key_Button125); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton126", -1); sq_pushinteger(vm, Device::Key_Button126); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyButton127", -1); sq_pushinteger(vm, Device::Key_Button127); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyCrossUp", -1); sq_pushinteger(vm, Device::Key_Cross_Up); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyCrossDown", -1); sq_pushinteger(vm, Device::Key_Cross_Down); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyCrossLeft", -1); sq_pushinteger(vm, Device::Key_Cross_Left); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyCrossRight", -1); sq_pushinteger(vm, Device::Key_Cross_Right); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "KeyBack", -1); sq_pushinteger(vm, Device::Key_Back); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyStart", -1); sq_pushinteger(vm, Device::Key_Start); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeySelect", -1); sq_pushinteger(vm, Device::Key_Select); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyL1", -1); sq_pushinteger(vm, Device::Key_L1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyL2", -1); sq_pushinteger(vm, Device::Key_L2); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyL3", -1); sq_pushinteger(vm, Device::Key_L3); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyR1", -1); sq_pushinteger(vm, Device::Key_R1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyR2", -1); sq_pushinteger(vm, Device::Key_R2); sq_newslot(vm, -3, true); + sq_pushstring(vm, "KeyR3", -1); sq_pushinteger(vm, Device::Key_R3); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ModeRead", -1); sq_pushinteger(vm, GS::IO::ModeRead); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ModeWrite", -1); sq_pushinteger(vm, GS::IO::ModeWrite); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/item_binding.cpp b/include/modules/script_squirrel/legacy/item_binding.cpp new file mode 100644 index 0000000..02d1a04 --- /dev/null +++ b/include/modules/script_squirrel/legacy/item_binding.cpp @@ -0,0 +1,2455 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "scene3d/mitem_event_interface.h" + #include "scene3d/scene_ace_manager.h" + #include "scene3d/mcamera.h" + #include "scene3d/mlight.h" + #include "scene3d/mobject.h" + #include "scene3d/memitter.h" + #include "scene3d/mtrigger.h" + #include "scene3d/instance.h" + #include "scene3d/scene.h" + #include "scene3d/group.h" + #include "motion/motion_automation_source.h" + #include "script/scripted_object.h" + #include "script/script_unit.h" + #include "metafile/nml_object.h" + #include "core/resource_factories.h" + + using namespace GS; + using namespace GS::S3D; + using namespace GS::Script; + + +static CObjectType item_derived_types[] = { typetag_Item, typetag_Camera, typetag_Object, typetag_Light, typetag_Trigger, typetag_Emitter, typetag_Undefined }; + +//------------------------------------------------------------------------------ +SQInteger ItemTranslate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(i, MItem, item_derived_types) + __SQ_GETVECTOR(t) + __SQ_GETEND + i->GetBaseItem()->SetPosition(i->GetBaseItem()->GetPosition() + t); + __SQ_RETURN +} +SQInteger ItemRotate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(i, MItem, item_derived_types) + __SQ_GETVECTOR(e) + __SQ_GETEND + i->GetBaseItem()->SetRotation(i->GetBaseItem()->GetRotation() + e); + __SQ_RETURN +} +SQInteger ItemScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(i, MItem, item_derived_types) + __SQ_GETVECTOR(s) + __SQ_GETEND + i->GetBaseItem()->SetScale(i->GetBaseItem()->GetScale() * s); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemCastToEmitter(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, MItem, typetag_Item) + if (i->GetItemType() != Type_Emitter) + return sq_throwerror(vm, "Invalid item cast, item is not a particle emitter."); + __SQ_RETURNSAFEPTR((MEmitter *)i, typetag_Emitter) +} +SQInteger ItemCastToCamera(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, MItem, typetag_Item) + if (i->GetItemType() != Type_Camera) + return sq_throwerror(vm, "Invalid item cast, item is not a camera."); + __SQ_RETURNSAFEPTR((MCamera *)i, typetag_Camera) +} +SQInteger ItemCastToObject(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, MItem, typetag_Item) + if (i->GetItemType() != Type_Object) + return sq_throwerror(vm, "Invalid item cast, item is not an object."); + __SQ_RETURNSAFEPTR((MObject *)i, typetag_Object) +} +SQInteger ItemCastToTrigger(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, MItem, typetag_Item) + if (i->GetItemType() != Type_Trigger) + return sq_throwerror(vm, "Invalid item cast, item is not a trigger."); + __SQ_RETURNSAFEPTR((MTrigger *)i, typetag_Trigger) +} +SQInteger ItemCastToLight(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, MItem, typetag_Item) + if (i->GetItemType() != Type_Light) + return sq_throwerror(vm, "Invalid item cast, item is not a light."); + __SQ_RETURNSAFEPTR((MLight *)i, typetag_Light) +} +SQInteger ItemCastToInstance(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, MItem, typetag_Item) + if (i->GetItemType() != Type_Instance) + return sq_throwerror(vm, "Invalid item cast, item is not an instance."); + __SQ_RETURNSAFEPTR((Instance *)i, typetag_Instance) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemDerivedCastToItem(HSQUIRRELVM vm) +{ + MItem *item = NULL; + + //----------------------------------- + #define __GrabDerivedItem(__T__)\ + {\ + __T__ *i;\ + CObject::Get(vm, -1, (void **)&i);\ + item = i;\ + }\ + break; + //----------------------------------- + + CObjectType type; + if (!CObject::GetType(vm, -1, type)) + return -1; + + switch (type) + { + case typetag_Camera: + __GrabDerivedItem(MCamera) + case typetag_Light: + __GrabDerivedItem(MLight) + case typetag_Object: + __GrabDerivedItem(MObject) + case typetag_Trigger: + __GrabDerivedItem(MTrigger) + case typetag_Emitter: + __GrabDerivedItem(MEmitter) + + case typetag_Item: + __GrabDerivedItem(MItem) + + default: break; + } + sq_pop(vm, 1); + + __SQ_RETURNSAFEPTR(item, typetag_Item) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemRegistrySetKey(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(key) + GS::Variant value; + HSQOBJECT o; + sq_getstackobj(vm, __SQ_STACKPOS, &o); + switch (sq_type(o)) + { + case OT_BOOL: + { __SQ_GETBOOL(v) value = asbool(v); } break; + case OT_INTEGER: + { __SQ_GETINT(v) value = (int)v; } break; + case OT_FLOAT: + { __SQ_GETFLOAT(v) value = v; } break; + case OT_STRING: + { __SQ_GETSTRING(s) value = s; } break; + + default: return sq_throwerror(vm, "Unsupported key value type."); + } + item->GetBaseItem()->registry.CreateKey(key, &value); + __SQ_GETEND + __SQ_RETURN +} +SQInteger ItemRegistryGetKey(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(key) + __SQ_GETEND + + GS::Variant v(-1); + GS::NML::Tag *tag = item->GetBaseItem()->registry.GetTag(key); + if (tag) + v = tag->GetValue(); + + switch (v.GetType()) + { + case GS::Variant::VariantBool: __SQ_RETURNBOOL(v.b_value) + case GS::Variant::VariantInteger: __SQ_RETURNINT(v.i_value) + case GS::Variant::VariantFloat: __SQ_RETURNFLOAT(v.f_value) + case GS::Variant::VariantString: __SQ_RETURNSTRING(v.s_value.c_str()) + } + __SQ_RETURNINT(-1) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemSetCommandList(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(list) + ACEManager::Get()->LoadACECommandList(list, item); + __SQ_GETEND + __SQ_RETURN +} +SQInteger ItemResetCommandList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(item, MItem, typetag_Item) + item->ResetCommandList(); + __SQ_RETURN +} +SQInteger ItemIsCommandListDone(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNBOOL(item ? item->IsCommandListDone() : true) +} +//------------------------------------------------------------------------------ + +SQInteger ItemPrint(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __LOG__ << "Item: " << (asbool(item) ? item->name.c_str() : "Null") << " (Uid = " << (asbool(item) ? item->GetUid() : -1) << ").\n"; + __SQ_RETURN +} + +SQInteger ItemReset(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + item->Reset(); + __SQ_RETURN +} + +SQInteger ItemGetType(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNINT(item ? item->GetItemType() : 0) +} + +SQInteger ItemRenderSetup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETEND + if (item->GetBaseItem()) + item->GetBaseItem()->RenderSetup(f); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +#define __SQ_GETMITEMSCRIPTOBJECT(__SRC) ScriptedObject *scripted_object = __SRC->scripted_object; if (!scripted_object) return sq_throwerror(vm, "No script system in scene!"); +#define __SQ_ASSERTSCRIPTUNITOPEN(__UNIT, __NAME) if (!(__UNIT)->IsOpen()) return sq_throwerror(vm, GS::String::Format("Script unit for '%s' is not open.", __NAME)); + +SQInteger ItemSetScript(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(script_file) + __SQ_GETSTRING(script_class) + __SQ_GETMITEMSCRIPTOBJECT(item) + + if (!scripted_object->GetUnitList().GetCount()) + scripted_object->AddUnit(scripted_object->NewUnit()); + + if (GS::Script::Unit *unit = scripted_object->GetUnitList().ObjectAt(0)) + { + unit->script_file = script_file; + unit->script_class = script_class; + } + + __SQ_GETEND + __SQ_RETURN +} +SQInteger ItemGetScriptInstance(HSQUIRRELVM vm) // LEGACY +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETMITEMSCRIPTOBJECT(item) + if (!scripted_object->GetUnitList().GetCount()) + return sq_throwerror(vm, GS::String::Format("Item '%s' has no script unit.", item->name.c_str())); + Script::Unit *unit = scripted_object->GetUnitList()[0]; + __SQ_ASSERTSCRIPTUNITOPEN(unit, item->name.c_str()) + __SQ_RETURNOBJECT(((Script::SquirrelObject *)unit->Self())->object); +} +SQInteger ItemGetScriptInstanceCount(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETMITEMSCRIPTOBJECT(item) + __SQ_RETURNINT(scripted_object->GetUnitList().GetCount()) +} +SQInteger ItemGetScriptInstanceFromIndex(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(index) + __SQ_GETEND + __SQ_GETMITEMSCRIPTOBJECT(item) + Script::Unit *unit = scripted_object->GetUnitList().ObjectAt(index); + __SQ_ASSERTSCRIPTUNITOPEN(unit, item->name.c_str()) + __SQ_RETURNOBJECT(((Script::SquirrelObject *)unit->Self())->object); +} +SQInteger ItemGetScriptInstanceFromClass(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(_class) + __SQ_GETMITEMSCRIPTOBJECT(item) + + Script::Unit *_unit = 0; + ListForeachPtr(Script::Unit *, unit, scripted_object->GetUnitList()) + if (unit->script_class == _class) + { + _unit = unit; + break; + } + + __SQ_GETEND + + if (_unit) + { + __SQ_ASSERTSCRIPTUNITOPEN(_unit, item->name.c_str()) + __SQ_RETURNOBJECT(((Script::SquirrelObject *)_unit->Self())->object); + } + return sq_throwerror(vm, "Script unit not found"); +} +SQInteger ItemHasScript(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(_class) + __SQ_GETMITEMSCRIPTOBJECT(item) + + Script::Unit *_unit = 0; + ListForeachPtr(Script::Unit *, unit, scripted_object->GetUnitList()) + if (unit->script_class == _class) + { + _unit = unit; + break; + } + + __SQ_GETEND + __SQ_RETURNBOOL(asbool(_unit)) +} +SQInteger ItemSetupScript(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETMITEMSCRIPTOBJECT(item) + + if (!scripted_object->GetUnitList().GetCount()) + scripted_object->AddUnit(scripted_object->NewUnit()); + + if (Script::Unit *unit = scripted_object->GetUnitList().ObjectAt(0)) + unit->Open(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +SQInteger ItemCompare(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item_a, MItem, item_derived_types) + __SQ_GETCOBJECTBASE(item_b, MItem, item_derived_types) + __SQ_GETEND + __SQ_RETURNBOOL(item_a == item_b ? true : false) +} + +//------------------------------------------------------------------------------ +SQInteger ItemIsActive(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNBOOL(item ? item->isActive() : false) +} +//------------------------------------------------------------------------------ + +SQInteger ItemIsInvisible(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNBOOL(item ? item->GetBaseItem()->item_flags.IsSet(ItemFlagInvisible) : true) +} + +SQInteger ItemSetInvisible(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETBOOL(invisible) + __SQ_GETEND + item->GetBaseItem()->item_flags.Raise(ItemFlagInvisible, invisible ? true : false); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +static void SetItemInvisibleRecursive(Core::Item *i, bool v) +{ + i->item_flags.Raise(ItemFlagInvisible, v); + ListForeachPtr(Core::Item *, c, i->GetChildren()) + SetItemInvisibleRecursive(c, v); +} +SQInteger ItemHierarchySetInvisible(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETBOOL(invisible) + __SQ_GETEND + SetItemInvisibleRecursive(item->GetBaseItem(), asbool(invisible)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +SQInteger ItemRecordLocation(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + item->SetInitialTransformation(); + __SQ_RETURN +} + +SQInteger ItemGetMinMax(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + MinMax minmax; + item->GetBaseItem()->ComputeLocalMinMax(minmax); + __SQ_RETURNMINMAX(minmax) +} + +SQInteger ItemGetMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNMATRIX4(item->GetBaseItem()->GetMatrix()) +} + +SQInteger ItemGetInverseMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNMATRIX4(item->GetBaseItem()->GetInverseMatrix()) +} + +SQInteger ItemGetLocalMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNMATRIX4(item->GetBaseItem()->GetLocalMatrix()) +} + +SQInteger ItemSetMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETMATRIX4(mtx) + __SQ_GETEND + item->GetBaseItem()->SetMatrix(mtx); + __SQ_RETURN +} + +SQInteger ItemGetRotationMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNMATRIX3(GS::Matrix3::FromMatrix4(item->GetBaseItem()->GetMatrix())) +} + +SQInteger ItemSetRotationMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETMATRIX3(mtx) + __SQ_GETEND + item->GetBaseItem()->SetRotation(mtx); + __SQ_RETURN +} + +SQInteger ItemSnapshotTransformation(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + item->GetBaseItem()->SnapshotTransformation(item->GetBaseItem()->GetMatrix()); + __SQ_RETURN +} + +SQInteger ItemSnapshotMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETMATRIX4(m) + __SQ_GETEND + item->GetBaseItem()->SnapshotTransformation(m); + __SQ_RETURN +} + +SQInteger ItemGetGeometry(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + if (item->GetItemType() != Type_Object) + return sq_throwerror(vm, "Item is not an object, cannot get geometry"); + + if (((MObject *)item)->render_data.IsNull()) + __SQ_RETURNNULL + + __SQ_RETURNSAFEPTR(((MObject *)item)->render_data->geometry.c_ptr(), typetag_Geometry) +} +SQInteger ItemSaveGeometry(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(path) + __SQ_GETSAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETEND + + if (item->GetItemType() != Type_Object) + return sq_throwerror(vm, "Item is not an object, cannot get geometry"); + else + { + NML::SaveToFile(*f->graphic->LoadGeometry(((MObject *)item)->geometry), path); + } + + __SQ_RETURN +} + +SQInteger ItemGetOpacity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNFLOAT(item->GetBaseItem()->opacity) +} + +SQInteger ItemSetOpacity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETFLOAT(a) + __SQ_GETEND + item->GetBaseItem()->opacity = Types::Clamp(a); + __SQ_RETURN +} + +SQInteger ItemSetPriority(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETFLOAT(p) + __SQ_GETEND + item->SetPriority(p); + __SQ_RETURN +} + +SQInteger ItemSetExcludeFromRecord(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETFLOAT(exclude) + __SQ_GETEND + __SQ_RETURN +} + +SQInteger ItemGetExcludeFromRecord(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNBOOL(false) +} + +SQInteger ItemGetChild(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(name) + __SQ_GETEND + + MItem *_ci = NULL; + ListForeachPtr(Core::Item *, ci, item->GetBaseItem()->GetChildren()) + if (Scene::LocateManagedItem(ci)->name == name) + { + _ci = Scene::LocateManagedItem(ci); + break; + } + + __SQ_RETURNSAFEPTR(_ci, typetag_Item) +} + +SQInteger ItemGetName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNSTRING(item->name.c_str()) +} + +SQInteger ItemSetName(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(_name) + item->name = _name; + __SQ_GETEND + __SQ_RETURN +} + +SQInteger ItemGetRotationOrder(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNINT((int)item->GetBaseItem()->GetRotationOrder()) +} + +SQInteger ItemSetRotationOrder(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(rorder) + __SQ_GETEND + item->GetBaseItem()->SetRotationOrder((Math::rOrder)rorder); + __SQ_RETURN +} + +SQInteger ItemComputeMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURN +} + +SQInteger ItemComputeLocalMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURN +} + +SQInteger ItemComputeMinMax(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(item, MItem, typetag_Item) + MinMax minmax; + item->GetBaseItem()->ComputeLocalMinMax(minmax); + __SQ_RETURN +} + +SQInteger ItemSetLinkInheritsPositionOnly(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETBOOL(flag) + __SQ_GETEND + item->GetBaseItem()->item_flags.Raise(ItemFlagInheritPositionOnly, asbool(flag)); + __SQ_RETURN +} + +SQInteger ItemSetPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + item->GetBaseItem()->SetPosition(p); + __SQ_GETEND + __SQ_RETURN +} + +SQInteger ItemGetPosition(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(item->GetBaseItem()->GetPosition()) +} + +SQInteger ItemSetScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(s) + __SQ_GETEND + item->GetBaseItem()->SetScale(s); + __SQ_RETURN +} + +SQInteger ItemGetScale(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(item->GetBaseItem()->GetScale()) +} + +SQInteger ItemGetWorldPosition(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(item->GetBaseItem()->GetMatrix().GetRow(3)) +} +SQInteger ItemGetWorldRotation(HSQUIRRELVM vm) { + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(GS::Matrix3::FromMatrix4(item->GetBaseItem()->GetMatrix()).AsEuler()) +} +SQInteger ItemGetPreviousWorldPosition(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(item->GetBaseItem()->GetPreviousMatrix().GetRow(3)) +} + +SQInteger ItemSetPivot(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETEND + GS::Matrix4 m; + m.SetRow(3, p); + item->GetBaseItem()->SetPivot(m); + __SQ_RETURN +} +SQInteger ItemGetPivot(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(item->GetBaseItem()->GetPivot().GetRow(3)) +} + +SQInteger ItemSetRotation(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(e) + __SQ_GETEND + item->GetBaseItem()->SetRotation(e); + __SQ_RETURN +} + +SQInteger ItemSetRotationQuaternion(HSQUIRRELVM vm) +{ return ItemSetRotation(vm); } + +SQInteger ItemGetRotation(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(item->GetBaseItem()->GetRotation()) +} + +SQInteger ItemSetTarget(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(target) + __SQ_GETEND + item->GetBaseItem()->SetTarget(&target); + __SQ_RETURN +} +SQInteger ItemSetNoTarget(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + item->GetBaseItem()->SetTarget(NULL); + __SQ_RETURN +} +SQInteger ItemGetTarget(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(item->GetBaseItem()->target) +} +SQInteger ItemHasTarget(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNBOOL(item->GetBaseItem()->item_flags.IsSet(ItemFlagHasTarget)); +} + +SQInteger ItemGetParent(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNSAFEPTR(Scene::LocateManagedItem(item->GetBaseItem()->GetParent()), typetag_Item) +} + +SQInteger ItemSetLink(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETCOBJECTBASEALLOWNULL(link, MItem, item_derived_types) + __SQ_GETEND + item->GetBaseItem()->SetParent(link ? link->GetBaseItem() : NULL); + __SQ_RETURN +} + +SQInteger ItemGetChildList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + sq_newarray(vm, 0); + ListForeachPtr(Core::Item *, i, item->GetBaseItem()->GetChildren()) + { + CObject::Push(vm, (void *)Scene::LocateManagedItem(i), typetag_Item); + sq_arrayappend(vm, -2); + } + return 1; +} + +SQInteger ItemGetScriptLogicFrequency(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNFLOAT(-1.f) +} + +SQInteger ItemSetScriptLogicFrequency(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETFLOAT(fq) + __SQ_GETEND +// item->logic_fq = fq; + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +#define __SQ_GETPHYSICITEM(__I__) PhysicItem *iphysic = (__I__)->physic_item.c_ptr(); if (!iphysic) return sq_throwerror(vm, "No physics found, did you setup this item?"); + +SQInteger ItemGetSpeed(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNFLOAT(iphysic->GetLinearVelocity().Len()) +} +SQInteger ItemWake(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + iphysic->SetSleeping(false); + __SQ_RETURN +} +SQInteger ItemSleep(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + iphysic->SetSleeping(true); + __SQ_RETURN +} +SQInteger ItemIsSleeping(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNBOOL(iphysic->IsSleeping()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemPhysicResetTransformation(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETVECTOR(r) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->SetMatrix(GS::Matrix4::TransformationMatrix(p, r, Vector4(1, 1, 1))); + __SQ_RETURN +} +SQInteger ItemGetLinearDamping(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNFLOAT(iphysic->GetLinearDamping()) +} +SQInteger ItemSetLinearDamping(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETFLOAT(d) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->SetLinearDamping(d); + __SQ_RETURN +} +SQInteger ItemSetGravityScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETFLOAT(k) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) +// item->GetPhysics()->SetGravity(item->GetScene().GetPhysics()->GetGravity() * k); + __LOG_W__ << "ItemSetGravityScale(): STUB\n"; + __SQ_RETURN +} +SQInteger ItemSetGravity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(g) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->SetGravity(g); + __SQ_RETURN +} +SQInteger ItemGetGravity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetGravity()) +} +SQInteger ItemGetAngularDamping(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNFLOAT(iphysic->GetAngularDamping()) +} +SQInteger ItemSetAngularDamping(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETFLOAT(k) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->SetAngularDamping(k); + __SQ_RETURN +} +SQInteger ItemGetAngularVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetAngularVelocity()) +} +SQInteger ItemSetAngularVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(w) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->SetAngularVelocity(w); + __SQ_RETURN +} +SQInteger ItemGetMass(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNFLOAT(item->physic_item_desc.GetMass()) +} +SQInteger ItemCollided(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNBOOL(false) // TODO +} +SQInteger ItemUpdateInertiaTensorFromCollision(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) +// iphysic->SetupBody(); + __LOG_E__ << "ItemUpdateInertiaTensorFromCollision::FIXME\n"; + __SQ_RETURN +} +SQInteger ItemPhysicGetFlag(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNINT(0) +} +SQInteger ItemPhysicSetFlag(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(f) + __SQ_GETEND + __SQ_RETURN +} +SQInteger ItemGetPhysicMode(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNINT(item->physic_item_desc.physic_mode) +} +SQInteger ItemSetPhysicMode(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(m) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + item->physic_item_desc.physic_mode = PhysicItemDesc::Mode(m); + __SQ_RETURN +} +SQInteger ItemSetInertiaTensorAndCom(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETMATRIX3(tensor) + __SQ_GETVECTOR(com) + __SQ_GETEND + __SQ_RETURN +} +SQInteger ItemPhysicSetLinearFactor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(k) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + item->physic_item_desc.linear_factor.Set(k); + iphysic->SetLinearFactor(k); + __SQ_RETURN +} +SQInteger ItemPhysicSetAngularFactor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(k) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + item->physic_item_desc.angular_factor.Set(k); + iphysic->SetAngularFactor(k); + __SQ_RETURN +} +SQInteger ItemApplyLinearForce(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(F) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->ApplyForce(F); + __SQ_RETURN +} +SQInteger ItemApplyForce(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETVECTOR(F) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->ApplyForce(F, &p); + __SQ_RETURN +} +SQInteger ItemApplyImpulse(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETVECTOR(J) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->ApplyImpulse(J, &p); + __SQ_RETURN +} +SQInteger ItemApplyLinearImpulse(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(J) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->ApplyImpulse(J); + __SQ_RETURN +} +SQInteger ItemApplyTorque(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(T) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->ApplyTorque(T); + __SQ_RETURN +} +SQInteger ItemGetLinearAcceleration(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(Vector4(0, 0, 0)) +} +SQInteger ItemGetLinearVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetLinearVelocity()) +} +SQInteger ItemGetPreviousLinearVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetLinearVelocity()) +} +SQInteger ItemSetLinearVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(V) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->SetLinearVelocity(V); + __SQ_RETURN +} +SQInteger ItemGetLocalPointVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetLocalPointVelocity(p)) +} +SQInteger ItemGetWorldPointVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetWorldPointVelocity(p)) +} +SQInteger ItemGetPhysicPosition(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + GS::Matrix4 m; + iphysic->GetMatrix(m); + __SQ_RETURNVECTOR(m.GetRow(3)) +} +SQInteger ItemSetPhysicPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + GS::Matrix4 m; + iphysic->GetMatrix(m); + m.SetRow(3, p); + iphysic->SetMatrix(m); + __SQ_RETURN +} +SQInteger ItemGetPhysicPreviousPosition(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNVECTOR(Vector4(0, 0, 0)) +} +SQInteger ItemSetPhysicPreviousPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(position) + __SQ_GETEND + __LOG_E__ << "OBSOLETE\n"; + __SQ_RETURN +} +SQInteger ItemGetPhysicRotation(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + GS::Matrix4 m; + iphysic->GetMatrix(m); + __SQ_RETURNVECTOR(GS::Matrix3::FromMatrix4(m).AsEuler()) +} +SQInteger ItemSetPhysicRotation(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(r) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + GS::Matrix4 m; + iphysic->GetMatrix(m); + Vector4 p, s; + m.Decompose(&p, &s); + iphysic->SetMatrix(GS::Matrix4::TransformationMatrix(p, r, s)); + __SQ_RETURN +} +SQInteger ItemPhysicSynchronizeCollision(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __ERR__(__LOG_E__ << "OBSOLETE", 0) +} +SQInteger ItemWorldPointVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(wp) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetWorldPointVelocity(wp)) +} +SQInteger ItemPointVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(p) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetLocalPointVelocity(p)) +} +SQInteger ItemGetCenterOfMass(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_GETPHYSICITEM(item) + __SQ_RETURNVECTOR(iphysic->GetCenterOfMass()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemPhysicCharacterSetRotationMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETMATRIX3(m) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->CharacterSetRotationMatrix(m); + __SQ_RETURN +} +SQInteger ItemPhysicCharacterSetVelocity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETVECTOR(V) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->CharacterSetVelocity(V); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemPhysicVehicleSetForce(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(index) + __SQ_GETFLOAT(F) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->VehicleSetForce(F, index); + __SQ_RETURN +} +SQInteger ItemPhysicVehicleSetBrake(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(index) + __SQ_GETFLOAT(F) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->VehicleSetBrake(F, index); + __SQ_RETURN +} +SQInteger ItemPhysicVehicleSetSteering(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(index) + __SQ_GETFLOAT(v) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->VehicleSetSteering(v, index); + __SQ_RETURN +} +SQInteger ItemPhysicVehicleSetFriction(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(index) + __SQ_GETFLOAT(f) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + iphysic->VehicleSetFriction(f, index); + __SQ_RETURN +} + +SQInteger ItemPhysicVehicleGetWheelMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(index) + __SQ_GETEND + __SQ_GETPHYSICITEM(item) + __SQ_RETURNMATRIX4(iphysic->VehicleGetWheelMatrix(index)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemGetLocalMinMax(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + + MinMax mm; + if (item->GetItemType() == Type_Object) + { + MObject *obj = (MObject *)item; + + if (obj->geometry.IsEmpty()) + mm.Set(obj->GetMatrix().GetRow(3), obj->GetMatrix().GetRow(3)); + + else + { + if (obj->render_data.IsNull()) + return sq_throwerror(vm, "Object has no render data, you need to call ObjectRenderSetup() first."); + if (obj->render_data->geometry.IsNull()) + return sq_throwerror(vm, "Object has no render geometry, you need to call ObjectRenderSetup() first."); + + mm = obj->render_data->geometry->minmax; + } + } + __SQ_RETURNMINMAX(mm) +} + +SQInteger ItemGetWorldMinMax(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + + MinMax mm; + if (item->GetItemType() == Type_Object) + { + MObject *obj = (MObject *)item; + + if (obj->geometry.IsEmpty()) + mm.Set(obj->GetMatrix().GetRow(3), obj->GetMatrix().GetRow(3)); + + else + { + if (obj->render_data.IsNull()) + return sq_throwerror(vm, "Object has no render data, you need to call ObjectRenderSetup() first."); + if (obj->render_data->geometry.IsNull()) + return sq_throwerror(vm, "Object has no render geometry, you need to call ObjectRenderSetup() first."); + + OBB obb(obj->render_data->geometry->minmax); + obb.Transform(obj->GetMatrix()); + obb.ComputeMinMax(mm); + } + } + __SQ_RETURNMINMAX(mm) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemGetSkinBoneItemsGroup(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + + if (item->GetItemType() != Type_Object) + return sq_throwerror(vm, String("Item '") << item->name << "' is not an object."); + + MObject *o = (MObject *)item; + Core::Skin *skin = o->GetSkin(); + + if (!skin) + return sq_throwerror(vm, String("Object '") << item->name << "' has no skin."); + + Group *g = new Group; + for (uint n = 0; n < skin->bones.GetCount(); ++n) + g->Add(Scene::LocateManagedItem(skin->bones[n])); + + __SQ_RETURNMANAGEDSAFEPTR(g, typetag_Group) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemGetMotionCount(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNINT(item->automation_player->GetMotionList().GetCount()) +} +SQInteger ItemGetMotionFromIndex(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(index) + __SQ_GETEND + __SQ_RETURNSAFEPTR(item->automation_player->GetMotionFromIndex(index), typetag_Motion) +} + +SQInteger ItemStopAllMotions(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + item->automation_player->DisposeAutomationSources(); + __SQ_RETURN +} + +SQInteger ItemSetMotion(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETSTRING(name) + __SQ_GETFLOAT(blend) + Automation::Source *source = item->automation_player->StartAutomation(new Automation::MotionSource(item->automation_player->GetMotion(name), NULL), blend, Automation::Player::SourceSet); + __SQ_GETEND + __SQ_RETURNSAFEPTR(source, typetag_AutomationSource) +} +SQInteger ItemSetMotionRelative(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETBOOL(v) + __SQ_GETEND + item->automation_player->flags.Raise(Automation::Player::FlagRelativeMotion, asbool(v)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ItemSetFlags(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, MItem, item_derived_types) + __SQ_GETINT(flags) + __SQ_GETBOOL(set_flags) + __SQ_GETEND + item->mitem_flags.Raise(flags, asbool(set_flags)); + __SQ_RETURN +} + +SQInteger ItemGetFlags(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, MItem, item_derived_types)) + __SQ_RETURNINT(0) // item->item_flags.Get()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterItemBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Item + Type: Item + Desc: The item object is the base of all scene 3d entities such as cameras, objects, lights or triggers. +It stores the entity transformation and motions. + Related: Scene,Camera,Object,Light,Trigger +#*/ + +/*# + Section: ItemRegistry + Desc: Item registry +#*/ + /*# + Func: ItemRegistrySetKey + Proto: void:Item,string key,value + Desc: Set item registry key value. + #*/ + sq_register(vm, ItemRegistrySetKey, "ItemRegistrySetKey", _SC(".xs.")); + /*# + Func: ItemRegistryGetKey + Proto: value:Item,string key + Desc: Get item registry key value. + #*/ + sq_register(vm, ItemRegistryGetKey, "ItemRegistryGetKey", _SC(".xs")); + +/*# + Section: ItemACE + Desc: ACE +#*/ + /*# + Func: ItemSetCommandList + Proto: void:Item,string command_list + Desc: Set item asynchronous command list (see ACE). + #*/ + sq_register(vm, ItemSetCommandList, "ItemSetCommandList", _SC(".xs")); + /*# + Func: ItemResetCommandList + Proto: void:Item + Desc: Reset item asynchronous command list (see ACE). + #*/ + sq_register(vm, ItemResetCommandList, "ItemResetCommandList", _SC(".x")); + /*# + Func: ItemIsCommandListDone + Proto: bool:Item + Desc: Reset item asynchronous command list (see ACE). + #*/ + sq_register(vm, ItemIsCommandListDone, "ItemIsCommandListDone", _SC(".x")); + +/*# + Section: ItemRender + Desc: Rendering +#*/ + /*# + Func: ItemGetMinMax + Proto: MinMax:Item + Desc: Return the axis aligned bounding box in world space of the item. + #*/ + sq_register(vm, ItemGetMinMax, "ItemGetMinMax", _SC(".x")); + /*# + Func: ItemGetOpacity + Proto: float:Item + Desc: Get item opacity. + #*/ + sq_register(vm, ItemGetOpacity, "ItemGetOpacity", _SC(".x")); + sq_register(vm, ItemGetOpacity, "ItemGetAlpha", _SC(".x")); + /*# + Func: ItemSetOpacity + Proto: void:Item,float opacity + Desc: Set item opacity. + #*/ + sq_register(vm, ItemSetOpacity, "ItemSetOpacity", _SC(".xn")); + sq_register(vm, ItemSetOpacity, "ItemSetAlpha", _SC(".xn")); + +/*# + Section: ItemMotion + Desc: Motion +#*/ + /*# + Func: ItemGetMotionCount + Proto: int:Item + Desc: Get the number of motion in the item motion bank. + #*/ + sq_register(vm, ItemGetMotionCount, "ItemGetMotionCount", _SC(".x")); + /*# + Func: ItemGetMotionFromIndex + Proto: Motion:Item,int index + Desc: Get a motion from its index in the item motion bank. + #*/ + sq_register(vm, ItemGetMotionFromIndex, "ItemGetMotionFromIndex", _SC(".xi")); + /*# + Func: ItemStopAllMotions + Proto: void:Item + Desc: Stop all motions on this item. + #*/ + sq_register(vm, ItemStopAllMotions, "ItemStopAllMotions", _SC(".x")); + /*# + Func: ItemSetMotion + Proto: AnimationSource:Item,string name,float blend + Desc: Start a new motion on this item. + #*/ + sq_register(vm, ItemSetMotion, "ItemSetMotion", _SC(".xsn")); + /*# + Func: ItemSetMotionRelative + Proto: void:Item,bool relative + Desc: Set this item to use relative motion source. Motion started on this item will automatically be set to the correct evaluation mode (relative/absolute). + #*/ + sq_register(vm, ItemSetMotionRelative, "ItemSetMotionRelative", _SC(".xb")); + +/*# + Section: ItemTransform + Desc: Transformation +#*/ + /*# + Func: TranslateItem + Proto: void:Item item,Vector translation + Desc: Translate an item, the translation vector is expressed in the item parent space. + #*/ + sq_register(vm, ItemTranslate, "TranslateItem", _SC(".xx")); + /*# + Func: RotateItem + Proto: void:Item item,Vector rotation + Desc: Rotate an item by a triplet of Euler angles stored in a vector. + #*/ + sq_register(vm, ItemRotate, "RotateItem", _SC(".xx")); + /*# + Func: ScaleItem + Proto: void:Item item,Vector scale + Desc: Scale an item by a triplet of scale coefficients stored in a vector. + #*/ + sq_register(vm, ItemScale, "ScaleItem", _SC(".xx")); + + /*# + Func: ItemSetLinkInheritsPositionOnly + Proto: void:Item,bool inherits + Desc: Set the item to inherits only the position from its parent item. + #*/ + sq_register(vm, ItemSetLinkInheritsPositionOnly, "ItemSetLinkInheritsPositionOnly", _SC(".xb")); + /*# + Func: ItemGetPosition + Proto: Vector:Item + Desc: Get item position in parent space (world space if no parent). + #*/ + sq_register(vm, ItemGetPosition, "ItemGetPosition", _SC(".x")); + /*# + Func: ItemSetPosition + Proto: void:Item,Vector position + Desc: Set item position in parent space (world space if no parent). + #*/ + sq_register(vm, ItemSetPosition, "ItemSetPosition", _SC(".xx")); + /*# + Func: ItemGetScale + Proto: Vector:Item + Desc: Get item scale. + #*/ + sq_register(vm, ItemGetScale, "ItemGetScale", _SC(".x")); + /*# + Func: ItemSetScale + Proto: void:Item,Vector scale + Desc: Set item scale. + #*/ + sq_register(vm, ItemSetScale, "ItemSetScale", _SC(".xx")); + /*# + Func: ItemGetWorldPosition + Proto: Vector:Item + Desc: Return item position in world space. + #*/ + sq_register(vm, ItemGetWorldPosition, "ItemGetWorldPosition", _SC(".x")); + /*# + Func: ItemGetWorldRotation + Proto: Vector:Item + Desc: Get item rotation in world space as Euler angles (x, y, z). + Example: + // Get the world rotation of an item + local world_rot = ItemGetWorldRotation(item) + */ + sq_register(vm, ItemGetWorldRotation, "ItemGetWorldRotation", _SC(".x")); + + /*# + Func: ItemGetPreviousWorldPosition + Proto: Vector:Item + Desc: Return item position in world space during the previously rendered frame. + #*/ + sq_register(vm, ItemGetPreviousWorldPosition, "ItemGetPreviousWorldPosition", _SC(".x")); + /*# + Func: ItemGetRotation + Proto: Vector:Item + Desc: Get item rotation in Euler angles (x, y, z). + #*/ + sq_register(vm, ItemGetRotation, "ItemGetRotation", _SC(".x")); + /*# + Func: ItemSetRotation + Proto: void:Item,Vector euler + Desc: Set item rotation in Euler angles (x, y, z). + Example: +// Set the item rotation to +90 degree on the Y axis. +ItemSetRotation(item, Vector(Deg(0), Deg(90), Deg(0))) + #*/ + sq_register(vm, ItemSetRotation, "ItemSetRotation", _SC(".xx")); + /*# + Func: ItemSetRotationQuaternion + Proto: void:Item,Quaternion rotation + Desc: Set item rotation quaternion. + #*/ + sq_register(vm, ItemSetRotationQuaternion, "ItemSetRotationQuaternion", _SC(".xx")); + /*# + Func: ItemGetPivot + Proto: Vector:Item + Desc: Get item pivot. + #*/ + sq_register(vm, ItemGetPivot, "ItemGetPivot", _SC(".x")); + /*# + Func: ItemSetPivot + Proto: void:Item,Vector pivot + Desc: Set item pivot. + #*/ + sq_register(vm, ItemSetPivot, "ItemSetPivot", _SC(".xx")); + + /*# + Func: ItemComputeMatrix + Proto: void:Item + Desc: Compute item matrix and inverse matrix. + #*/ + sq_register(vm, ItemComputeMatrix, "ItemComputeMatrix", _SC(".x")); + /*# + Func: ItemComputeLocalMatrix + Proto: void:Item + Desc: Compute item local matrix. + #*/ + sq_register(vm, ItemComputeLocalMatrix, "ItemComputeLocalMatrix", _SC(".x")); + /*# + Func: ItemComputeMinMax + Proto: void:Item + Desc: Compute item minmax. + #*/ + sq_register(vm, ItemComputeMinMax, "ItemComputeMinMax", _SC(".x")); + + /*# + Func: ItemGetParent + Proto: Item:Item + Desc: Get item parent item. + #*/ + sq_register(vm, ItemGetParent, "ItemGetParent", _SC(".x")); + /*# + Func: ItemSetParent + Proto: void:Item,Item parent + Desc: Set item parent item. + #*/ + sq_register(vm, ItemSetLink, "ItemSetLink", _SC(".xx")); + sq_register(vm, ItemSetLink, "ItemSetParent", _SC(".xx")); + /*# + Func: ItemGetChildList + Proto: array:Item + Desc: Returns an array containing child items of this item. + #*/ + sq_register(vm, ItemGetChildList, "ItemGetChildList", _SC(".x")); + /*# + Func: ItemSetTarget + Proto: void:Item,Vector world_target + Desc: Set item target position in world space. + #*/ + sq_register(vm, ItemSetTarget, "ItemSetTarget", _SC(".xx")); + /*# + Func: ItemSetNoTarget + Proto: void:Item + Desc: Set no item target. + #*/ + sq_register(vm, ItemSetNoTarget, "ItemSetNoTarget", _SC(".x")); + /*# + Func: ItemGetTarget + Proto: Vector:Item + Desc: Get item target position in world space. + #*/ + sq_register(vm, ItemGetTarget, "ItemGetTarget", _SC(".x")); + /*# + Func: ItemHasTarget + Proto: bool:Item + Desc: Returns true if the item is set to target a specific location. + #*/ + sq_register(vm, ItemHasTarget, "ItemHasTarget", _SC(".x")); + /*# + Func: ItemGetRotationOrder + Proto: RotationOrder:Item + Desc: Return the item rotation order. + #*/ + sq_register(vm, ItemGetRotationOrder, "ItemGetRotationOrder", _SC(".x")); + /*# + Func: ItemSetRotationOrder + Proto: void:Item,RotationOrder + Desc: Set the item rotation order. + #*/ + sq_register(vm, ItemSetRotationOrder, "ItemSetRotationOrder", _SC(".xi")); + /*# + Func: ItemGetRotationMatrix + Proto: Matrix3:Item + Desc: Return the 3x3 item rotation matrix. + #*/ + sq_register(vm, ItemGetRotationMatrix, "ItemGetRotationMatrix", _SC(".x")); + /*# + Func: ItemSetRotationMatrix + Proto: void:Item,Matrix3 rotation + Desc: Set the 3x3 item rotation matrix. + #*/ + sq_register(vm, ItemSetRotationMatrix, "ItemSetRotationMatrix", _SC(".xx")); + /*# + Func: ItemGetMatrix + Proto: Matrix4:Item + Desc: Return the 4x4 item transformation matrix in world space. + #*/ + sq_register(vm, ItemGetMatrix, "ItemGetMatrix", _SC(".x")); + /*# + Func: ItemGetInverseMatrix + Proto: Matrix4:Item + Desc: Return the inverse 4x4 item transformation matrix. + #*/ + sq_register(vm, ItemGetInverseMatrix, "ItemGetInverseMatrix", _SC(".x")); + /*# + Func: ItemGetLocalMatrix + Proto: Matrix4:Item + Desc: Return the 4x4 item transformation matrix in parent space. + #*/ + sq_register(vm, ItemGetLocalMatrix, "ItemGetLocalMatrix", _SC(".x")); + /*# + Func: ItemSetMatrix + Proto: void:Item,Matrix4 + Desc: Set the 4x4 item transformation matrix. + #*/ + sq_register(vm, ItemSetMatrix, "ItemSetMatrix", _SC(".xx")); + /*# + Func: ItemRecordLocation + Proto: void:Item + Desc: Record item start location, item is set back to this location when reseted. + #*/ + sq_register(vm, ItemRecordLocation, "ItemRecordLocation", _SC(".x")); + /*# + Func: ItemSnapshotTransformation + Proto: void:Item + Desc: Snapshot current item transformation matrix to the current orientation method. + #*/ + sq_register(vm, ItemSnapshotTransformation, "ItemSnapshotTransformation", _SC(".x")); + /*# + Func: ItemSnapshotMatrix + Proto: void:Item,Matrix4 + Desc: Snapshot matrix as item transformation. + #*/ + sq_register(vm, ItemSnapshotMatrix, "ItemSnapshotMatrix", _SC(".xx")); + /*# + Func: ItemGetLocalMinMax + Proto: MinMax:Item + Desc: Return an item bounding box in local space. + #*/ + sq_register(vm, ItemGetLocalMinMax, "ItemGetLocalMinMax", _SC(".x")); + /*# + Func: ItemGetWorldMinMax + Proto: MinMax:Item + Desc: Return an item bounding box in world space. + #*/ + sq_register(vm, ItemGetWorldMinMax, "ItemGetWorldMinMax", _SC(".x")); + +/*# + Section: ItemCast + Desc: Type cast +#*/ + /*# + Func: ItemCastToObject + Proto: Object:Item + Desc: Cast item to object. + #*/ + sq_register(vm, ItemCastToObject, "ItemCastToObject", _SC(".x")); + /*# + Func: ItemCastToCamera + Proto: Camera:Item + Desc: Cast item to camera. + #*/ + sq_register(vm, ItemCastToCamera, "ItemCastToCamera", _SC(".x")); + /*# + Func: ItemCastToTrigger + Proto: Trigger:Item + Desc: Cast item to trigger. + #*/ + sq_register(vm, ItemCastToTrigger, "ItemCastToTrigger", _SC(".x")); + /*# + Func: ItemCastToLight + Proto: Light:Item + Desc: Cast item to light. + Example: +local light = ItemCastToLight(item) +LightSetRange(light, Mtr(20)) + #*/ + sq_register(vm, ItemCastToLight, "ItemCastToLight", _SC(".x")); + /*# + Func: ItemCastToInstance + Proto: Instance:Item + Desc: Cast item to instance. + #*/ + sq_register(vm, ItemCastToInstance, "ItemCastToInstance", _SC(".x")); + /*# + Func: ItemCastToEmitter + Proto: Emitter:Item + Desc: Cast item to emitter. + #*/ + sq_register(vm, ItemCastToEmitter, "ItemCastToEmitter", _SC(".x")); + /*# + Func: ItemDerivedCastToItem + Proto: Item:ItemDerived + Desc: Cast an item derived object (camera, object, light, trigger) to an item. + #*/ + sq_register(vm, ItemDerivedCastToItem, "ItemDerivedCastToItem", _SC(".x")); + +/*# + Section: ItemState + Desc: State +#*/ + /*# + Func: ItemIsInvisible + Proto: bool:Item + Desc: Return the visibility state of the item. + #*/ + sq_register(vm, ItemIsInvisible, "ItemIsInvisible", _SC(".x")); + /*# + Func: ItemSetInvisible + Proto: void:Item,bool invisible + Desc: Set item display flag, item is still updated but not displayed anymore. + #*/ + sq_register(vm, ItemSetInvisible, "ItemSetInvisible", _SC(".xb")); + /*# + Func: ItemHierarchySetInvisible + Proto: void:Item,bool + Desc: Set item and children display flag, item and children are still updated but not displayed anymore. + #*/ + sq_register(vm, ItemHierarchySetInvisible, "ItemHierarchySetInvisible", _SC(".xb")); + /*# + Func: ItemIsActive + Proto: bool:Item + Desc: Return true if the given item is active, false otherwise. + #*/ + sq_register(vm, ItemIsActive, "ItemIsActive", _SC(".x")); + +/*# + Section: Item + Desc: General +#*/ + /*# + Func: ItemReset + Proto: void:Item + Desc: Reset an item, effectively calling its OnReset script callbacks and resetting its physic state to the current item transformation. + #*/ + sq_register(vm, ItemReset, "ItemReset", _SC(".x")); + /*# + Func: ItemRenderSetup + Proto: void:Item,ResourceFactory + Desc: Setup the resources required to render an item. + #*/ + sq_register(vm, ItemRenderSetup, "ItemRenderSetup", _SC(".xx")); + /*# + Func: ItemSetup + Proto: void:Item + Desc: Setup an item. + Deprecated: SceneSetupItem + #*/ + ; + /*# + Func: ItemGetType + Proto: ItemType:Item + Desc: Return the item type (camera, light, object, trigger, etc...). + #*/ + sq_register(vm, ItemGetType, "ItemGetType", _SC(".x")); + /*# + Func: ItemCompare + Proto: bool:Item,Item + Desc: Compare two items, returns true is both items are the same object. + #*/ + sq_register(vm, ItemCompare, "ItemCompare", _SC(".xx")); + /*# + Func: ItemGetGeometry + Proto: Geometry:Item + Desc: Get item geometry, an item may have no geometry. + See: ObjectIsValid + #*/ + sq_register(vm, ItemGetGeometry, "ItemGetGeometry", _SC(".x")); + /*# + Func: ItemSaveGeometry + Proto: void:Item, path + Desc:save the item geometry into the path. + #*/ + sq_register(vm, ItemSaveGeometry, "ItemSaveGeometry", _SC(".xsx")); + /*# + Func: ItemSetPriority + Proto: void:Item,float priority + Desc: Set an item priority. + #*/ + sq_register(vm, ItemSetPriority, "ItemSetPriority", _SC(".xn")); + /*# + Func: ItemGetChild + Proto: Item:Item,string name + Desc: Get an item child from its name. + Example: local hand = ItemGetChild(arm_item, "hand") + #*/ + sq_register(vm, ItemGetChild, "ItemGetChild", _SC(".xs")); + + /*# + Func: ItemGetName + Proto: string:Item + Desc: Get item name. + #*/ + sq_register(vm, ItemGetName, "ItemGetName", _SC(".x")); + /*# + Func: ItemSetName + Proto: void:Item,string + Desc: Set item name. + #*/ + sq_register(vm, ItemSetName, "ItemSetName", _SC(".xs")); + /*# + Func: ItemGetFlags + Proto: ItemFlag:Item + Desc: Get item flags. + #*/ + sq_register(vm, ItemGetFlags, "ItemGetFlags", _SC(".x")); + /*# + Func: ItemSetFlags + Proto: void:Item,ItemFlag flag,bool set + Desc: Set or remove one or several item flags. + #*/ + sq_register(vm, ItemSetFlags, "ItemSetFlags", _SC(".xib")); + +/*# + Section: ItemSkin + Desc: Skinning +#*/ + /*# + Func: ItemGetSkinBoneItemsGroup + Proto: Group:Item + Desc: Return the item skin bone items as an item group. + See: GroupGetRootItem, GroupGetItemList + #*/ + sq_register(vm, ItemGetSkinBoneItemsGroup, "ItemGetSkinBoneItemsGroup", _SC(".x")); + +/*# + Section: ItemPhysicState + Desc: Physic state +#*/ + /*# + Func: ItemWake + Proto: void:Item + Desc: Wake a physic item, all collision and physic evaluation will resume. + #*/ + sq_register(vm, ItemWake, "ItemWake", _SC(".x")); + /*# + Func: ItemSleep + Proto: void:Item + Desc: Put a physic item to sleep, all collision and physic evaluation will stop. + #*/ + sq_register(vm, ItemSleep, "ItemSleep", _SC(".x")); + /*# + Func: ItemIsSleeping + Proto: bool:Item + Desc: Returns true if the item is sleeping, false otherwise. + #*/ + sq_register(vm, ItemIsSleeping, "ItemIsSleeping", _SC(".x")); + /*# + Func: ItemPhysicGetFlag + Proto: PhysicFlag:Item + Desc: Get item physic flag. + #*/ + sq_register(vm, ItemPhysicGetFlag, "ItemPhysicGetFlag", _SC(".x")); + /*# + Func: ItemPhysicSetFlag + Proto: void:Item,PhysicFlag + Desc: Set item physic flag. + #*/ + sq_register(vm, ItemPhysicSetFlag, "ItemPhysicSetFlag", _SC(".xi")); + +/*# + Section: ItemCharacterPhysic + Desc: Character Physic +#*/ + /*# + Func: ItemPhysicCharacterSetRotationMatrix + Proto: void:Item,Matrix3 m + Desc: Set physics character rotation matrix. + #*/ + sq_register(vm, ItemPhysicCharacterSetRotationMatrix, "ItemPhysicCharacterSetRotationMatrix", _SC(".xx")); + /*# + Func: ItemPhysicCharacterSetVelocity + Proto: void:Item,Vector V + Desc: Set physics character controller velocity. + #*/ + sq_register(vm, ItemPhysicCharacterSetVelocity, "ItemPhysicCharacterSetVelocity", _SC(".xx")); + +/*# + Section: ItemVehiclePhysic + Desc: Vehicle Physic +#*/ + /*# + Func: ItemPhysicVehicleSetForce + Proto: void:Item,int wheel_index,float F + Desc: Set engine force F for a specific wheel in the vehicle model. + #*/ + sq_register(vm, ItemPhysicVehicleSetForce, "ItemPhysicVehicleSetForce", _SC(".xin")); + /*# + Func: ItemPhysicVehicleSetBrake + Proto: void:Item,int wheel_index,float F + Desc: Set brake force F for a specific wheel in the vehicle model. + #*/ + sq_register(vm, ItemPhysicVehicleSetBrake, "ItemPhysicVehicleSetBrake", _SC(".xin")); + /*# + Func: ItemPhysicVehicleSetSteering + Proto: void:Item,int wheel_index,float angle + Desc: Set steering on a specific wheel of the vehicle model. + #*/ + sq_register(vm, ItemPhysicVehicleSetSteering, "ItemPhysicVehicleSetSteering", _SC(".xin")); + /*# + Func: ItemPhysicVehicleSetFriction + Proto: void:Item,int wheel_index,float friction_slip + Desc: Set friction on a specific wheel of the vehicle model. + #*/ + sq_register(vm, ItemPhysicVehicleSetFriction, "ItemPhysicVehicleSetFriction", _SC(".xin")); + /*# + Func: ItemPhysicVehicleGetWheelMatrix + Proto: Matrix4:Item,int wheel_index + Desc: Get a specific wheel matrix from the vehicle model. + #*/ + sq_register(vm, ItemPhysicVehicleGetWheelMatrix, "ItemPhysicVehicleGetWheelMatrix", _SC(".xi")); + +/*# + Section: ItemPhysic + Desc: Physic +#*/ + /*# + Func: ItemSetInertiaTensorAndCom + Proto: void:Item,Matrix3 tensor,Vector center_of_mass + Desc: Manually set the item inertia tensor and center of mass. + See: ItemUpdateInertiaTensorFromCollision + #*/ + sq_register(vm, ItemSetInertiaTensorAndCom, "ItemSetInertiaTensorAndCom", _SC(".xxx")); + /*# + Func: ItemUpdateInertiaTensorFromCollision + Proto: void:Item + Desc: Compute item inertia tensor and center of mass from the associated collision shape description. + #*/ + sq_register(vm, ItemUpdateInertiaTensorFromCollision, "ItemUpdateInertiaTensorFromCollision", _SC(".x")); + /*# + Func: ItemGetSpeed + Proto: float:Item + Desc: Get item center of mass speed (in m.s). + Note: This is the equivalent of ItemGetLinearVelocity(item).Len() + See: ItemPointVelocity, ItemWorldPointVelocity + #*/ + sq_register(vm, ItemGetSpeed, "ItemGetSpeed", _SC(".x")); + + /*# + Func: ItemApplyLinearForce + Proto: void:Item,Vector force + Desc: Apply a force to the item center of mass. Rotation is not affected. + #*/ + sq_register(vm, ItemApplyLinearForce, "ItemApplyLinearForce", _SC(".xx")); + /*# + Func: ItemApplyForce + Proto: void:Item,Vector position,Vector force + Desc: Apply a force at a specific position in world space to the item. + Example: +// Apply thrust to a ship item, the reactor item is parented to the ship item. +local reactor_matrix = ItemGetMatrix(reactor_item) + +// Get the reactor position and the vector pointing toward its back (and the back of the ship). +local reactor_world_position = reactor_matrix.GetPosition() +local reactor_back_vector = reactor_matrix.GetBack() + +// Apply thrust to the ship at the position of the reactor and in the correct direction. +local thrust_strength = 10.0 // the thrust strength +ItemApplyForce(ship_item, reactor_world_position, reactor_back_vector * thrust_strength) + #*/ + sq_register(vm, ItemApplyForce, "ItemApplyForce", _SC(".xxx")); + /*# + Func: ItemApplyLinearImpulse + Proto: void:Item,Vector impulse + Desc: Apply an impulse to the item center of mass. Rotation is not affected. An impulse is an immediate change of velocity. It is expressed as the difference between the target velocity and the current velocity. + See: ItemApplyImpulse + Example: +// Retrieve the current item linear velocity. +local current_v = ItemGetLinearVelocity(item) + +// Compute the impulse to force the item velocity to {1, 0, 0}. +local J = Vector(1, 0, 0) - current_v + +// Force the item linear velocity to {1, 0, 0} +ItemApplyImpulse(item, J) + #*/ + sq_register(vm, ItemApplyLinearImpulse, "ItemApplyLinearImpulse", _SC(".xx")); + /*# + Func: ItemApplyImpulse + Proto: void:Item,Vector position,Vector impulse + Desc: Apply an impulse at a specific position in world space to the item. + See: ItemApplyLinearImpulse + #*/ + sq_register(vm, ItemApplyImpulse, "ItemApplyImpulse", _SC(".xxx")); + /*# + Func: ItemApplyTorque + Proto: void:Item,Vector torque + Desc: Apply a torque to the item. The torque is the rotational equivalent of the force. It will increase the body angular velocity which will in turn rotate it. + #*/ + sq_register(vm, ItemApplyTorque, "ItemApplyTorque", _SC(".xx")); + + /*# + Func: ItemPhysicSetLinearFactor + Proto: void:Item,Vector factor + Desc: Set the scale factor for all forces applied to this item linear velocity. All forces applied directly and indirectly to this item will be scaled by this factor. + Example: +// Restrict all motions to the XY plane by canceling out all forces Z component. +ItemPhysicSetLinearFactor(item, Vector(1, 1, 0)) + #*/ + sq_register(vm, ItemPhysicSetLinearFactor, "ItemPhysicSetLinearFactor", _SC(".xx")); + /*# + Func: ItemPhysicSetAngularFactor + Proto: void:Item,Vector factor + Desc: Set the scale factor for all forces applied to this item angular velocity. All torques applied directly and indirectly to this item will be scaled by this factor. + Example: +// Restrict all rotations to the Z axis by canceling out all torques on the X and Y axises. +ItemPhysicSetangularFactor(item, Vector(0, 0, 1)) + #*/ + sq_register(vm, ItemPhysicSetAngularFactor, "ItemPhysicSetAngularFactor", _SC(".xx")); + + /*# + Func: ItemPhysicResetTransformation + Proto: void:Item,Vector position,Vector euler + Desc: Reset item physic transformation to specific location (in item local space). + #*/ + sq_register(vm, ItemPhysicResetTransformation, "ItemPhysicResetTransformation", _SC(".xxx")); + /*# + Func: ItemGetLinearDamping + Proto: float:Item + Desc: Get item linear damping. + #*/ + sq_register(vm, ItemGetLinearDamping, "ItemGetLinearDamping", _SC(".x")); + /*# + Func: ItemSetLinearDamping + Proto: void:Item,float damping + Desc: Set item linear damping by which the item linear velocity is scaled after each solver iteration.
+A damping value of 1 will not affect velocity, a damping of 0 will completely cancel velocity and a damping of 0.5 will make the object appear as if moving through a thick invisible material.
+ Note: A small amount of damping (0.99) can help the solver as it prevents sudden change and oscillation in velocity.
Too much damping can prevent the solver from reaching a stable configuration. + #*/ + sq_register(vm, ItemSetLinearDamping, "ItemSetLinearDamping", _SC(".xn")); + /*# + Func: ItemGetAngularDamping + Proto: float:Item + Desc: Get item angular damping. + #*/ + sq_register(vm, ItemGetAngularDamping, "ItemGetAngularDamping", _SC(".x")); + /*# + Func: ItemSetAngularDamping + Proto: void:Item,float damping + Desc: Set item angular damping. This is the rotational equivalent of the linear damping. + See: ItemSetLinearDamping + #*/ + sq_register(vm, ItemSetAngularDamping, "ItemSetAngularDamping", _SC(".xn")); + /*# + Func: ItemGetAngularVelocity + Proto: Vector:Item + Desc: Get item angular velocity (rad.s). The angular velocity is the rate of change in rotation over time. + Note: The angular velocity only affects rotation, position is affected by the linear velocity. + See: ItemGetLinearVelocity + #*/ + sq_register(vm, ItemGetAngularVelocity, "ItemGetAngularVelocity", _SC(".x")); + /*# + Func: ItemSetAngularVelocity + Proto: void:Item,Vector angular_velocity + Desc: Set item angular velocity (rad.s). + Note: This function sets the item angular velocity by bypassing the physics solver. This can lead to all sorts of problems depending on the scene configuration. You are advised to perform such change using an impulse instead. + See: ItemApplyAngularImpulse + #*/ + sq_register(vm, ItemSetAngularVelocity, "ItemSetAngularVelocity", _SC(".xx")); + + /*# + Func: ItemGetPhysicMode + Proto: PhysicMode:Item + Desc: Get the current item physic mode. + #*/ + sq_register(vm, ItemGetPhysicMode, "ItemGetPhysicMode", _SC(".x")); + /*# + Func: ItemSetPhysicMode + Proto: void:Item,PhysicMode mode + Desc: Set item physic mode. + #*/ + sq_register(vm, ItemSetPhysicMode, "ItemSetPhysicMode", _SC(".xi")); + /*# + Func: ItemCollided + Proto: bool:Item + Desc: Returns true if the item collided during the last physic step, false otherwise. + #*/ + sq_register(vm, ItemCollided, "ItemCollided", _SC(".x")); + + /*# + Func: ItemGetLinearAcceleration + Proto: Vector:Item + Desc: Get item linear acceleration (m.s²). Acceleration is the rate of change in speed over time. + #*/ + sq_register(vm, ItemGetLinearAcceleration, "ItemGetLinearAcceleration", _SC(".x")); + /*# + Func: ItemGetMass + Proto: float:Item + Desc: Get item mass (in Kg). + #*/ + sq_register(vm, ItemGetMass, "ItemGetMass", _SC(".x")); + /*# + Func: ItemGetCenterOfMass + Proto: Vector:Item + Desc: Get item center of mass position in item space. + #*/ + sq_register(vm, ItemGetCenterOfMass, "ItemGetCenterOfMass", _SC(".x")); + /*# + Func: ItemGetLocalPointVelocity + Proto: Vector:Item + Desc: Get an item local point velocity (m.s) in world space. + #*/ + sq_register(vm, ItemGetLocalPointVelocity, "ItemGetLocalPointVelocity", _SC(".x")); + /*# + Func: ItemGetWorldPointVelocity + Proto: Vector:Item + Desc: Get an item world point velocity (m.s) in world space. + #*/ + sq_register(vm, ItemGetWorldPointVelocity, "ItemGetWorldPointVelocity", _SC(".x")); + /*# + Func: ItemGetLinearVelocity + Proto: Vector:Item + Desc: Get the item linear velocity (m.s). Velocity is the rate of change of position over time. + Note: The linear velocity only affects position, rotation is affected by the angular velocity. + See: ItemGetLinearAcceleration, ItemGetAngularVelocity + #*/ + sq_register(vm, ItemGetLinearVelocity, "ItemGetLinearVelocity", _SC(".x")); + /*# + Func: ItemGetPreviousLinearVelocity + Proto: Vector:Item + Desc: Get item previous linear velocity (m.s). + #*/ + sq_register(vm, ItemGetPreviousLinearVelocity, "ItemGetPreviousLinearVelocity", _SC(".x")); + /*# + Func: ItemSetLinearVelocity + Proto: void:Item,Vector linear_velocity + Desc: Set item linear velocity (m.s). + Note: This function sets the item linear velocity by bypassing the physics solver. This can lead to all sorts of problems depending on the scene configuration. You are advised to perform such change using an impulse instead. + See: ItemApplyLinearImpulse + #*/ + sq_register(vm, ItemSetLinearVelocity, "ItemSetLinearVelocity", _SC(".xx")); + + /*# + Func: ItemSetGravityScale + Proto: void:Item,float scale + Desc: Set item gravity scale (g = world_gravity * scale). + #*/ + sq_register(vm, ItemSetGravityScale, "ItemSetGravityScale", _SC(".xn")); + /*# + Func: ItemSetGravity + Proto: void:Item,Vector g + Desc: Set item gravity (in m.s²). + Example: ItemSetGravity(item, Vector(0.0, -9.8, 0.0)) // Earth gravity. + #*/ + sq_register(vm, ItemSetGravity, "ItemSetGravity", _SC(".xx")); + /*# + Func: ItemGetGravity + Proto: Vector:Item + Desc: Get item gravity (m.s²). + #*/ + sq_register(vm, ItemGetGravity, "ItemGetGravity", _SC(".x")); + + /*# + Func: ItemWorldPointVelocity + Proto: void:Item,Vector world_position + Desc: Compute the velocity of an item particle, particle position is in world space (in m.s). + #*/ + sq_register(vm, ItemWorldPointVelocity, "ItemWorldPointVelocity", _SC(".xx")); + /*# + Func: ItemPointVelocity + Proto: void:Item,Vector local_position + Desc: Compute the velocity of an item particle, particle position is in item space (in m.s). + #*/ + sq_register(vm, ItemPointVelocity, "ItemPointVelocity", _SC(".xx")); + +/*# + Section: ItemPhysicHack + Desc: Physic hacking +#*/ + /*# + Func: ItemGetPhysicPosition + Proto: Vector:Item + Desc: Get item physic position. + #*/ + sq_register(vm, ItemGetPhysicPosition, "ItemGetPhysicPosition", _SC(".x")); + /*# + Func: ItemSetPhysicPosition + Proto: void:Item,Vector position + Desc: Set item physic position. + Note: Tampering with the internal physic state is likely to cause troubles, use with extreme care! + #*/ + sq_register(vm, ItemSetPhysicPosition, "ItemSetPhysicPosition", _SC(".xx")); + /*# + Func: ItemGetPhysicPreviousPosition + Proto: Vector:Item + Desc: Get item physic previous position. + #*/ + sq_register(vm, ItemGetPhysicPreviousPosition, "ItemGetPhysicPreviousPosition", _SC(".x")); + /*# + Func: ItemGetPhysicRotation + Proto: Vector:Item + Desc: Get item physic rotation. + #*/ + sq_register(vm, ItemGetPhysicRotation, "ItemGetPhysicRotation", _SC(".x")); + /*# + Func: ItemSetPhysicRotation + Proto: void:Item,Vector euler + Desc: Set item physic rotation. + Note: Tampering with the internal physic state is likely to cause troubles, use with extreme care! + #*/ + sq_register(vm, ItemSetPhysicRotation, "ItemSetPhysicRotation", _SC(".xx")); + /*# + Func: ItemPhysicSynchronizeCollision + Proto: void:Item + Desc: Synchronize the collision interface to the physic interface. + #*/ + sq_register(vm, ItemPhysicSynchronizeCollision, "ItemPhysicSynchronizeCollision", _SC(".x")); + +/*# + Section: ItemScript + Desc: Script +#*/ + /*# + Func: ItemSetScript + Proto: void:Item,String file,String class + Desc: Set item script file and class to instantiate for the item first script unit. + #*/ + sq_register(vm, ItemSetScript, "ItemSetScript", _SC(".xss")); + /*# + Func: ItemSetupScript + Proto: void:Item + Desc: Setup item script. + #*/ + sq_register(vm, ItemSetupScript, "ItemSetupScript", _SC(".x")); + /*# + Func: ItemGetScriptInstance + Proto: instance:Item + Desc: Get an item script instance on its first script unit. + See: ItemGetScriptInstanceFromClass + + Example: +local enemy_item = SceneFindItem(g_scene, "an_enemy") +local enemy = ItemGetScriptInstance(enemy_item) + +// Instance can be used to call the script assigned to the item. +enemy->TakeHit(20) + #*/ + sq_register(vm, ItemGetScriptInstance, "ItemGetScriptInstance", _SC(".x")); + /*# + Func: ItemGetScriptInstanceCount + Proto: int:Item + Desc: Get the number of script instance available on an item. + #*/ + sq_register(vm, ItemGetScriptInstanceCount, "ItemGetScriptInstanceCount", _SC(".x")); + /*# + Func: ItemGetScriptInstanceFromIndex + Proto: instance:Item,int index + Desc: Get an item script instance from its index. + See: ItemGetScriptInstanceFromClass + #*/ + sq_register(vm, ItemGetScriptInstanceFromIndex, "ItemGetScriptInstanceFromIndex", _SC(".xi")); + /*# + Func: ItemGetScriptInstanceFromClass + Proto: instance:Item,string class_name + Desc: Get an item script instance from the name of the class it instantiates. + + Example: +local enemy_item = SceneFindItem(g_scene, "an_enemy") +local ai = ItemGetScriptInstanceFromClass(item, "AIComponent") + +// Instance can be used to call the AIComponent instance assigned to the enemy item. +ai->Flee() + #*/ + sq_register(vm, ItemGetScriptInstanceFromClass, "ItemGetScriptInstanceFromClass", _SC(".xs")); +#if 1 + sq_register(vm, ItemSetPhysicPreviousPosition, "ItemSetPhysicPreviousPosition", _SC(".xx")); +#endif + /*# + Func: ItemHasScript + Proto: bool:Item,string class_name + Desc: Test if a specific script is assigned to an item. The script is identified by its class name. + + Example: +// Will return true if this script is instantiated for this item. +local has_some_component = ItemHasScript(item, "AComponentClass") + #*/ + sq_register(vm, ItemHasScript, "ItemHasScript", _SC(".xs")); + +/*# + Section: ItemDebug + Desc: Debug +#*/ + /*# + Func: ItemPrint + Proto: void:Item + Desc: Print item instance address in memory. + #*/ + sq_register(vm, ItemPrint, "ItemPrint", _SC(".x")); + + /*# + Enum: PhysicMode + Values: PhysicModeNone,PhysicModeStatic,PhysicModeDynamic,PhysicModeKinematic + #*/ + sq_pushstring(vm, "PhysicModeNone", -1); sq_pushinteger(vm, PhysicItemDesc::Mode_None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "PhysicModeStatic", -1); sq_pushinteger(vm, PhysicItemDesc::Mode_Static); sq_newslot(vm, -3, true); + sq_pushstring(vm, "PhysicModeDynamic", -1); sq_pushinteger(vm, PhysicItemDesc::Mode_Dynamic); sq_newslot(vm, -3, true); + sq_pushstring(vm, "PhysicModeKinematic", -1); sq_pushinteger(vm, PhysicItemDesc::Mode_Kinematic); sq_newslot(vm, -3, true); + +#if 1 + sq_pushstring(vm, "PhysicModeRigidBody", -1); sq_pushinteger(vm, PhysicItemDesc::Mode_Dynamic); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "OrientationEuler", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "OrientationMatrix", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "OrientationQuaternion", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "OrientationExternal", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); +#endif + + /*# + Enum: PhysicFlag + Values: PhysicFlagNone,PhysicFlagNoGravity,PhysicFlagNoForceField,PhysicFlagMobile,PhysicFlagGhost + #*/ + sq_pushstring(vm, "PhysicFlagNone", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "PhysicFlagNoGravity", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "PhysicFlagNoForceField", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "PhysicFlagMobile", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "PhysicFlagGhost", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + + /*# + Enum: RotationOrder + Values: RotationOrderDefault,RotationOrderZYX,RotationOrderYZX,RotationOrderZXY,RotationOrderXZY,RotationOrderYXZ,RotationOrderXYZ,RotationOrderXY + #*/ + sq_pushstring(vm, "RotationOrderDefault", -1); sq_pushinteger(vm, Math::rOrder_Default); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RotationOrderZYX", -1); sq_pushinteger(vm, Math::rOrder_ZYX); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RotationOrderYZX", -1); sq_pushinteger(vm, Math::rOrder_YZX); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RotationOrderZXY", -1); sq_pushinteger(vm, Math::rOrder_ZXY); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RotationOrderXZY", -1); sq_pushinteger(vm, Math::rOrder_XZY); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RotationOrderYXZ", -1); sq_pushinteger(vm, Math::rOrder_YXZ); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RotationOrderXYZ", -1); sq_pushinteger(vm, Math::rOrder_XYZ); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RotationOrderXY", -1); sq_pushinteger(vm, Math::rOrder_XY); sq_newslot(vm, -3, true); + + /*# + Enum: ItemType + Values: ItemTypeNone,ItemTypeCamera,ItemTypeObject,ItemTypeLight,ItemTypeTrigger,ItemTypeEmitter,ItemTypeInstance + #*/ + sq_pushstring(vm, "ItemTypeNone", -1); sq_pushinteger(vm, Type_None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemTypeCamera", -1); sq_pushinteger(vm, Type_Camera); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemTypeObject", -1); sq_pushinteger(vm, Type_Object); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemTypeLight", -1); sq_pushinteger(vm, Type_Light); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemTypeTrigger", -1); sq_pushinteger(vm, Type_Trigger); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemTypeEmitter", -1); sq_pushinteger(vm, Type_Emitter); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemTypeInstance", -1); sq_pushinteger(vm, Type_Instance); sq_newslot(vm, -3, true); + + /*# + Enum: ItemFlag + Values: ItemFlagNone,ItemFlagBillboard,ItemFlagSolveOverlap + #*/ + sq_pushstring(vm, "ItemFlagNone", -1); sq_pushinteger(vm, MItem::Flag_None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemFlagBillboard", -1); sq_pushinteger(vm, MItem::Flag_Billboard); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ItemFlagSolveOverlap", -1); sq_pushinteger(vm, MItem::Flag_SolveOverlap); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "NullGeometry", -1); CObject::Push(vm, NULL, typetag_Geometry); sq_newslot(vm, -3, true); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/light_binding.cpp b/include/modules/script_squirrel/legacy/light_binding.cpp new file mode 100644 index 0000000..4a7ac70 --- /dev/null +++ b/include/modules/script_squirrel/legacy/light_binding.cpp @@ -0,0 +1,347 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "scene3d/mlight.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +static CObjectType light_derived_types[] = { typetag_Item, typetag_Light, typetag_Undefined }; + +SQInteger LightGetDiffuseIntensity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNFLOAT(l->diffuse_intensity) +} + +SQInteger LightSetProjectionTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETSAFEPTR(t, GS::Render::Texture, typetag_Texture) + l->render_data->projection_texture = t; + __SQ_GETEND + __SQ_RETURN +} +SQInteger LightSetDiffuseIntensity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETFLOAT(i) + __SQ_GETEND + l->diffuse_intensity = i; + __SQ_RETURN +} +SQInteger LightGetDiffuseColor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNVECTOR(l->diffuse_color) +} +SQInteger LightSetDiffuseColor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETVECTOR(color) + __SQ_GETEND + l->diffuse_color = color; + __SQ_RETURN +} +SQInteger LightGetSpecularIntensity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNFLOAT(l->specular_intensity) +} +SQInteger LightSetSpecularIntensity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETFLOAT(i) + __SQ_GETEND + l->specular_intensity = i; + __SQ_RETURN +} +SQInteger LightGetSpecularColor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNVECTOR(l->specular_color) +} +SQInteger LightSetSpecularColor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETVECTOR(color) + __SQ_GETEND + l->specular_color = color; + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +SQInteger LightSetConeAngle(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETFLOAT(angle) + __SQ_GETEND + l->cone_angle = angle; + __SQ_RETURN +} +SQInteger LightGetConeAngle(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNFLOAT(l->cone_angle) +} +SQInteger LightSetEdgeAngle(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETFLOAT(angle) + __SQ_GETEND + l->edge_angle = angle; + __SQ_RETURN +} +SQInteger LightGetEdgeAngle(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNFLOAT(l->edge_angle) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger LightSetRange(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETFLOAT(range) + __SQ_GETEND + l->range = range; + __SQ_RETURN +} +SQInteger LightGetRange(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNFLOAT(l->range) +} +SQInteger LightSetShadowRange(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETFLOAT(shadow_range) + __SQ_GETEND + l->shadow_range = shadow_range; + __SQ_RETURN +} +SQInteger LightGetShadowRange(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNFLOAT(l->shadow_range) +} +SQInteger LightSetVolumeRange(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETFLOAT(range) + __SQ_GETEND + l->volume_range = range; + __SQ_RETURN +} +SQInteger LightGetVolumeRange(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNFLOAT(l->volume_range) +} +//------------------------------------------------------------------------------ + +SQInteger LightGetItem(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNSAFEPTR((MItem *)l, typetag_Item) +} +SQInteger LightGetType(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(l, MLight, light_derived_types)) + __SQ_RETURNINT(l->model) +} +SQInteger LightSetType(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(l, MLight, light_derived_types) + __SQ_GETINT(_type) + __SQ_GETEND + l->model = (GS::Core::Light::Model)_type; + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +void RegisterLightBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Light + Type: Light + Related: Item +#*/ + +/*# + Section: LightColor + Desc: Light color functions +#*/ + /*# + Func: LightGetDiffuseIntensity + Proto: float:Light + Desc: Get light diffuse intensity. + #*/ + sq_register(vm, LightGetDiffuseIntensity, "LightGetDiffuseIntensity", _SC(".x")); + /*# + Func: LightGetDiffuseColor + Proto: Vector:Light + Desc: Get light diffuse color. + #*/ + sq_register(vm, LightGetDiffuseColor, "LightGetDiffuseColor", _SC(".x")); + /*# + Func: LightSetDiffuseIntensity + Proto: void:Light,float intensity + Desc: Set light diffuse intensity. + #*/ + sq_register(vm, LightSetDiffuseIntensity, "LightSetDiffuseIntensity", _SC(".xn")); + /*# + Func: LightSetDiffuseColor + Proto: void:Light,Vector color + Desc: Set light diffuse color. + #*/ + sq_register(vm, LightSetDiffuseColor, "LightSetDiffuseColor", _SC(".xx")); + /*# + Func: LightGetSpecularIntensity + Proto: float:Light + Desc: Get light specular intensity. + #*/ + sq_register(vm, LightGetSpecularIntensity, "LightGetSpecularIntensity", _SC(".x")); + /*# + Func: LightGetSpecularColor + Proto: Vector:Light + Desc: Get light specular color. + #*/ + sq_register(vm, LightGetSpecularColor, "LightGetSpecularColor", _SC(".x")); + /*# + Func: LightSetSpecularIntensity + Proto: void:Light,float intensity + Desc: Set light specular intensity. + #*/ + sq_register(vm, LightSetSpecularIntensity, "LightSetSpecularIntensity", _SC(".xn")); + /*# + Func: LightSetSpecularColor + Proto: void:Light,Vector color + Desc: Set light specular color. + #*/ + sq_register(vm, LightSetSpecularColor, "LightSetSpecularColor", _SC(".xx")); + +/*# + Section: LightSpot + Desc: Spot functions +#*/ + /*# + Func: LightSetConeAngle + Proto: void:Light,float angle + Desc: Set light cone angle in radian, the cone angle is the spot area where intensity is at its maximum. + #*/ + sq_register(vm, LightSetConeAngle, "LightSetConeAngle", _SC(".xn")); + /*# + Func: LightSetEdgeAngle + Proto: void:Light,float angle + Desc: Set light edge angle in radian, the edge angle is the spot area where intensity decreases from its maximum toward zero. + #*/ + sq_register(vm, LightSetEdgeAngle, "LightSetEdgeAngle", _SC(".xn")); + /*# + Func: LightGetConeAngle + Proto: float:Light + Desc: Get light cone angle in radian. + #*/ + sq_register(vm, LightGetConeAngle, "LightGetConeAngle", _SC(".x")); + /*# + Func: LightGetEdgeAngle + Proto: float:Light + Desc: Get light edge angle in radian. + #*/ + sq_register(vm, LightGetEdgeAngle, "LightGetEdgeAngle", _SC(".x")); + +/*# + Section: LightGeneric + Desc: Generic functions +#*/ + /*# + Func: LightSetRange + Proto: void:Light,float range + Desc: Set the light range in meter. + #*/ + sq_register(vm, LightSetRange, "LightSetRange", _SC(".xn")); + /*# + Func: LightGetRange + Proto: float:Light + Desc: Return the light range in meter. + #*/ + sq_register(vm, LightGetRange, "LightGetRange", _SC(".x")); + /*# + Func: LightSetShadowRange + Proto: void:Light,float range + Desc: Set the light range in meter. + #*/ + sq_register(vm, LightSetShadowRange, "LightSetShadowRange", _SC(".xn")); + /*# + Func: LightGetRange + Proto: float:Light + Desc: Return the light range in meter. + #*/ + sq_register(vm, LightGetShadowRange, "LightGetShadowRange", _SC(".x")); + /*# + Func: LightSetVolumeRange + Proto: void:Light,float range + Desc: Set the light volume range in meter. The volume range has no relation with the volumetric system and is only a performance hint used by some renderer. If unsure this value should be kept equal to the light range. + #*/ + sq_register(vm, LightSetVolumeRange, "LightSetVolumeRange", _SC(".xn")); + /*# + Func: LightGetVolumeRange + Proto: float:Light + Desc: Return the light volume range in meter. + #*/ + sq_register(vm, LightGetVolumeRange, "LightGetVolumeRange", _SC(".x")); + + /*# + Func: LightSetProjectionTexture + Proto: void:Light,Texture + Desc: Set light projection texture. + #*/ + sq_register(vm, LightSetProjectionTexture, "LightSetProjectionTexture", _SC(".xx")); + /*# + Func: LightGetItem + Proto: Item:Light + Desc: Get light item. + #*/ + sq_register(vm, LightGetItem, "LightGetItem", _SC(".x")); + /*# + Func: LightGetType + Proto: LightType:Light + Desc: Get light type. + #*/ + sq_register(vm, LightGetType, "LightGetType", _SC(".x")); + /*# + Func: LightSetType + Proto: void:Light,LightType type + Desc: Set light type. + #*/ + sq_register(vm, LightSetType, "LightSetType", _SC(".xi")); + + /*# + Enum: LightType + Values: LightTypeNone,LightTypeSpot,LightTypeLinear,LightTypePoint + #*/ + using GS::Core::Light; + + sq_pushstring(vm, "LightTypeNone", -1); sq_pushinteger(vm, Light::Model_None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "LightTypeSpot", -1); sq_pushinteger(vm, Light::Model_Spot); sq_newslot(vm, -3, true); + sq_pushstring(vm, "LightTypeLinear", -1); sq_pushinteger(vm, Light::Model_Linear); sq_newslot(vm, -3, true); + sq_pushstring(vm, "LightTypePoint", -1); sq_pushinteger(vm, Light::Model_Point); sq_newslot(vm, -3, true); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/material_binding.cpp b/include/modules/script_squirrel/legacy/material_binding.cpp new file mode 100644 index 0000000..752f3bc --- /dev/null +++ b/include/modules/script_squirrel/legacy/material_binding.cpp @@ -0,0 +1,532 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "core/material_to_shader_tree.h" + #include "core/render_data.h" +#include "gpu/gpu_material.h" + +using namespace GS::Render; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger MaterialGetDiffuse(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNVECTORW(m->diffuse) +} +SQInteger MaterialSetDiffuse(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETVECTORW(c) + __SQ_GETEND + m->diffuse = c; + __SQ_RETURN +} +SQInteger MaterialGetSpecular(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNVECTORW(m->specular) +} +SQInteger MaterialSetSpecular(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETVECTORW(c) + __SQ_GETEND + m->specular = c; + __SQ_RETURN +} +SQInteger MaterialGetSelf(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNVECTORW(m->self) +} +SQInteger MaterialSetSelf(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETVECTORW(c) + __SQ_GETEND + m->self = c; + __SQ_RETURN +} +SQInteger MaterialGetAmbient(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNVECTORW(m->ambient) +} +SQInteger MaterialSetAmbient(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETVECTORW(c) + __SQ_GETEND + m->ambient = c; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MaterialGetGlossiness(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNFLOAT(m->glossiness) +} +SQInteger MaterialSetGlossiness(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETFLOAT(v) + __SQ_GETEND + m->glossiness = v; + __SQ_RETURN +} +SQInteger MaterialGetOpacity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNFLOAT(m->opacity) +} +SQInteger MaterialSetOpacity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETFLOAT(v) + __SQ_GETEND + m->opacity = v; + __SQ_RETURN +} +SQInteger MaterialGetAlphaThreshold(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNFLOAT(m->athreshold) +} +SQInteger MaterialSetAlphaThreshold(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETFLOAT(v) + __SQ_GETEND + m->athreshold = v; + __SQ_RETURN +} +SQInteger MaterialGetDepthBias(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Material, typetag_Material) + __SQ_RETURNFLOAT(m->depth_bias) +} +SQInteger MaterialSetDepthBias(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(m, Material, typetag_Material) + __SQ_GETFLOAT(v) + __SQ_GETEND + m->depth_bias = v; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MaterialGetName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mat, Material, typetag_Material) + __SQ_RETURNSTRING(mat->name.c_str()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MaterialFlagGet(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mat, Material, typetag_Material) + __SQ_GETINT(flag) + __SQ_GETEND + __SQ_RETURNBOOL(asbool(mat->renderword & flag)) +} +SQInteger MaterialFlagSet(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mat, Material, typetag_Material) + __SQ_GETINT(flag) + __SQ_GETBOOL(state) + __SQ_GETEND + if (state) + mat->renderword |= flag; + else mat->renderword &= ~flag; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MaterialGetBlendOperator(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mat, Material, typetag_Material) + __SQ_RETURNINT(mat->blendop) +} +SQInteger MaterialSetBlendOperator(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mat, Material, typetag_Material) + __SQ_GETINT(op) + __SQ_GETEND + mat->blendop = op; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MaterialGetTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mat, Material, typetag_Material) + __SQ_GETINT(slot) + __SQ_GETEND + if ((slot < 0) || (slot >= GS::Core::Material::max_texture_stage)) + return sq_throwerror(vm, "Invalid material texture slot index."); + __SQ_RETURNSAFEPTR(mat->texture_table[slot].c_ptr(), typetag_Texture) +} +SQInteger MaterialSetTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mat, Material, typetag_Material) + __SQ_GETINT(slot) + __SQ_GETSAFEPTR(tex, Texture, typetag_Texture) + __SQ_GETEND + if ((slot < 0) || (slot >= GS::Core::Material::max_texture_stage)) + return sq_throwerror(vm, "Invalid material texture slot index."); + mat->texture_table[slot] = tex; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MaterialClone(HSQUIRRELVM vm) +{ + __LOG_W__ << "[SQ] MaterialClone: Called from Squirrel.\n"; + + __SQ_GETSINGLESAFEPTR(mat, Material, typetag_Material) + + __LOG_W__ << "[SQ] MaterialClone: Got material pointer: " << (void*)mat << "\n"; + + if (!mat) + { + __LOG_E__ << "[SQ] MaterialClone: Input material is NULL!\n"; + return sq_throwerror(vm, "Input material is NULL"); + } + + __LOG_W__ << "[SQ] MaterialClone: Material name: '" << mat->name << "'\n"; + __LOG_W__ << "[SQ] MaterialClone: Material refcount: " << mat->GetRefCount() << "\n"; + + // Cast to GPU::Material to ensure we're working with the right type + __LOG_W__ << "[SQ] MaterialClone: Attempting dynamic_cast to GPU::Material...\n"; + GS::GPU::Material *gpu_mat = dynamic_cast(mat); + + if (!gpu_mat) + { + __LOG_E__ << "[SQ] MaterialClone: Material is not a GPU::Material! Cannot clone.\n"; + return sq_throwerror(vm, "Material type not supported for cloning"); + } + + __LOG_W__ << "[SQ] MaterialClone: dynamic_cast succeeded, got GPU::Material at " << (void*)gpu_mat << "\n"; + + // WORKAROUND: Clone manually without calling virtual methods + // (calling virtual methods crashes for unknown reason) + __LOG_W__ << "[SQ] MaterialClone: Cloning manually (bypassing virtual Clone())...\n"; + + Material *cloned = NULL; + + try + { + __LOG_W__ << "[SQ] MaterialClone: Accessing renderer reference...\n"; + GS::GPU::Renderer &rend = gpu_mat->renderer; + __LOG_W__ << "[SQ] MaterialClone: Renderer at: " << (void*)&rend << "\n"; + + __LOG_W__ << "[SQ] MaterialClone: Allocating new GPU::Material...\n"; + cloned = new GS::GPU::Material(rend); + __LOG_W__ << "[SQ] MaterialClone: Allocation succeeded: " << (void*)cloned << "\n"; + + // Copy properties manually + __LOG_W__ << "[SQ] MaterialClone: Copying name...\n"; + cloned->name = gpu_mat->name + "_clone"; + + __LOG_W__ << "[SQ] MaterialClone: Copying BasicMaterial properties...\n"; + *((GS::Core::BasicMaterial *)cloned) = *((GS::Core::BasicMaterial *)gpu_mat); + + __LOG_W__ << "[SQ] MaterialClone: Copying shader reference...\n"; + ((GS::GPU::Material*)cloned)->shader = gpu_mat->shader; + + __LOG_W__ << "[SQ] MaterialClone: Copying texture table...\n"; + for (uint n = 0; n < GS::Core::Material::max_texture_stage; ++n) + { + cloned->texture_table[n] = gpu_mat->texture_table[n]; + } + + __LOG_W__ << "[SQ] MaterialClone: Manual clone complete!\n"; + } + catch (...) + { + __LOG_E__ << "[SQ] MaterialClone: EXCEPTION caught during manual clone!\n"; + if (cloned) + delete cloned; + return sq_throwerror(vm, "Exception during clone"); + } + + __LOG_W__ << "[SQ] MaterialClone: Clone() returned: " << (void*)cloned << "\n"; + + if (!cloned) + { + __LOG_E__ << "[SQ] MaterialClone: Clone() returned NULL!\n"; + return sq_throwerror(vm, "Failed to clone material"); + } + + __LOG_W__ << "[SQ] MaterialClone: Returning managed pointer to Squirrel...\n"; + // Use managed pointer so Squirrel will handle the reference counting + __SQ_RETURNMANAGEDSAFEPTR(cloned, typetag_Material) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MaterialGetShader(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mat, Material, typetag_Material) + __SQ_RETURNSAFEPTR(mat->GetShader(), typetag_MaterialShader) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterMaterialBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Material + Type: Material + Type: MaterialShader +#*/ + +/*# + Section: MaterialRenderAttributes + Desc: Render attributes functions +#*/ + /*# + Func: MaterialGetDiffuse + Proto: Vector:Material material + Desc: Get material diffuse color. + #*/ + sq_register(vm, MaterialGetDiffuse, "MaterialGetDiffuse", _SC(".x")); + /*# + Func: MaterialSetDiffuse + Proto: void:Material material,Vector diffuse_color + Desc: Set material diffuse color. + #*/ + sq_register(vm, MaterialSetDiffuse, "MaterialSetDiffuse", _SC(".xx")); + /*# + Func: MaterialGetSpecular + Proto: Vector:Material material + Desc: Get material specular color. + #*/ + sq_register(vm, MaterialGetSpecular, "MaterialGetSpecular", _SC(".x")); + /*# + Func: MaterialSetSpecular + Proto: void:Material material,Vector specular_color + Desc: Set material specular color. + Note: This value is combined with the light source own specular color and intensity. + #*/ + sq_register(vm, MaterialSetSpecular, "MaterialSetSpecular", _SC(".xx")); + /*# + Func: MaterialGetSelf + Proto: Vector:Material material + Desc: Get material self color. + #*/ + sq_register(vm, MaterialGetSelf, "MaterialGetSelf", _SC(".x")); + /*# + Func: MaterialSetSelf + Proto: void:Material material,Vector self_color + Desc: Set material self color. + #*/ + sq_register(vm, MaterialSetSelf, "MaterialSetSelf", _SC(".xx")); + /*# + Func: MaterialGetAmbient + Proto: Vector:Material material + Desc: Get material ambient color. + #*/ + sq_register(vm, MaterialGetAmbient, "MaterialGetAmbient", _SC(".x")); + /*# + Func: MaterialSetAmbient + Proto: void:Material material,Vector ambient_color + Desc: Set material ambient color. + #*/ + sq_register(vm, MaterialSetAmbient, "MaterialSetAmbient", _SC(".xx")); + + /*# + Func: MaterialGetGlossiness + Proto: float:Material material + Desc: Get material glossiness. + #*/ + sq_register(vm, MaterialGetGlossiness, "MaterialGetGlossiness", _SC(".x")); + /*# + Func: MaterialSetGlossiness + Proto: void:Material material,float glossiness + Desc: Set material glossiness. + #*/ + sq_register(vm, MaterialSetGlossiness, "MaterialSetGlossiness", _SC(".xn")); + /*# + Func: MaterialGetOpacity + Proto: float:Material material + Desc: Get material opacity. + #*/ + sq_register(vm, MaterialGetOpacity, "MaterialGetOpacity", _SC(".x")); + /*# + Func: MaterialSetOpacity + Proto: void:Material material,float opacity + Desc: Set material opacity. + See: MaterialSetBlendOperator + #*/ + sq_register(vm, MaterialSetOpacity, "MaterialSetOpacity", _SC(".xn")); + /*# + Func: MaterialGetAlphaThreshold + Proto: float:Material material + Desc: Get material alpha threshold. + #*/ + sq_register(vm, MaterialGetAlphaThreshold, "MaterialGetAlphaThreshold", _SC(".x")); + /*# + Func: MaterialSetAlphaThreshold + Proto: void:Material material,float threshold + Desc: Set material alpha threshold. + #*/ + sq_register(vm, MaterialSetAlphaThreshold, "MaterialSetAlphaThreshold", _SC(".xn")); + /*# + Func: MaterialGetDepthBias + Proto: float:Material material + Desc: Get material depth bias. + #*/ + sq_register(vm, MaterialGetDepthBias, "MaterialGetDepthBias", _SC(".x")); + /*# + Func: MaterialSetDepthBias + Proto: void:Material material,float depth_bias + Desc: Set material depth bias. + #*/ + sq_register(vm, MaterialSetDepthBias, "MaterialSetDepthBias", _SC(".xn")); + /*# + Func: MaterialGetTexture + Proto: Texture:Material material,int slot + Desc: Get texture at a given material slot. + #*/ + sq_register(vm, MaterialGetTexture, "MaterialGetTexture", _SC(".xn")); + /*# + Func: MaterialSetTexture + Proto: void:Material material,int slot,Texture texture + Desc: Set texture at a given material slot. + #*/ + sq_register(vm, MaterialSetTexture, "MaterialSetTexture", _SC(".xnx")); + /*# + Func: MaterialGetShader + Proto: MaterialShader:Material material + Desc: Return the material shader for a given material. + Note: A material shader encapsulates all the variants of a shader required to render a material. + #*/ + sq_register(vm, MaterialGetShader, "MaterialGetShader", _SC(".x")); + +/*# + Section: MaterialGeneric + Desc: Generic functions +#*/ + /*# + Func: MaterialGetName + Proto: string:Material mat + Desc: Get material name. + #*/ + sq_register(vm, MaterialGetName, "MaterialGetName", _SC(".x")); + + /*# + Func: MaterialClone + Proto: Material:Material mat + Desc: Clone a material (create an independent copy in memory). + Note: The cloned material has all the same textures, properties, and configuration as the original, but changes to the clone won't affect the original material. + Example: local mat_clone = MaterialClone(original_material) + #*/ + sq_register(vm, MaterialClone, "MaterialClone", _SC(".x")); + +/*# + Section: MaterialFlag + Desc: Rendering flag functions +#*/ + /*# + Func: MaterialSetRenderFlag + Proto: void:Material mat,MaterialRenderFlag flag,bool state + Desc: Add or remove a material render flag. + Example: +// Set the first material of a geometry to be double-sided. +local mat = GeometryGetMaterialFromIndex(geo, 0) +MaterialSetRenderFlag(mat, MaterialRenderDoubleSided, true) + #*/ + sq_register(vm, MaterialFlagSet, "MaterialFlagSet", _SC(".xib")); + sq_register(vm, MaterialFlagSet, "MaterialSetRenderFlag", _SC(".xib")); + /*# + Func: MaterialTestRenderFlag + Proto: bool:Material mat,MaterialRenderFlag flag + Desc: Test a material render flag. + #*/ + sq_register(vm, MaterialFlagGet, "MaterialFlagGet", _SC(".xi")); + sq_register(vm, MaterialFlagGet, "MaterialTestRenderFlag", _SC(".xi")); + + /*# + Func: MaterialSetBlendOperator + Proto: void:Material mat,MaterialBlendOperator op + Desc: Set the material blend operator. The blend operator controls how a material is composited onto screen. + Example: +// Set the first material of a geometry to use additive blending. +local mat = GeometryGetMaterialFromIndex(geo, 0) +MaterialSetBlendOperator(mat, MaterialBlendAdditive) + #*/ + sq_register(vm, MaterialSetBlendOperator, "MaterialSetBlendOperator", _SC(".xi")); + /*# + Func: MaterialGetBlendOperator + Proto: MaterialBlendOperator:Material mat + Desc: Get the material blend operator. + See: MaterialSetBlendOperator + #*/ + sq_register(vm, MaterialGetBlendOperator, "MaterialGetBlendOperator", _SC(".x")); + + // + + sq_pushroottable(vm); + sq_pushstring(vm, "NullMaterial", -1); CObject::Push(vm, NULL, typetag_Material); sq_newslot(vm, -3, true); + + using GS::Core::Material; + + /*# + Enum: MaterialBlendOperator + Values: MaterialBlendNone,MaterialBlendAlpha,MaterialBlendAdditive + #*/ + sq_pushstring(vm, "MaterialBlendNone", -1); sq_pushinteger(vm, Material::Blend_None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialBlendAlpha", -1); sq_pushinteger(vm, Material::Blend_Alpha); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialBlendAdditive", -1); sq_pushinteger(vm, Material::Blend_Add); sq_newslot(vm, -3, true); + + /*# + Enum: MaterialRenderFlag + Values: MaterialRenderUnlit,MaterialRenderSmooth,MaterialRenderNormalMapTangent,MaterialRenderNoFog,MaterialRenderDoubleSided,MaterialRenderWire,MaterialRenderVertexColor,MaterialRenderParralax,MaterialRenderToonShading,MaterialRenderNoDepthWrite,MaterialRenderNoDepthTest,MaterialRenderAlphaSoftZ,MaterialRenderAlphaInShadow + #*/ + sq_pushstring(vm, "MaterialRenderUnlit", -1); sq_pushinteger(vm, Material::Render_Unlit); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderSmooth", -1); sq_pushinteger(vm, Material::Render_Smooth); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderNormalMapTangent", -1); sq_pushinteger(vm, Material::Render_NormalTangent); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderNoFog", -1); sq_pushinteger(vm, Material::Render_NoFog); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "MaterialRenderDoubleSided", -1); sq_pushinteger(vm, Material::Render_DoubleSided); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderWire", -1); sq_pushinteger(vm, Material::Render_Wire); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderVertexColor", -1); sq_pushinteger(vm, Material::Render_VertexColor); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderParralax", -1); sq_pushinteger(vm, Material::Render_ParralaxDisp); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderToonShading", -1); sq_pushinteger(vm, Material::Render_Toon); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "MaterialRenderNoDepthWrite", -1); sq_pushinteger(vm, Material::Render_NoZWrite); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderNoDepthTest", -1); sq_pushinteger(vm, Material::Render_NoZTest); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "MaterialRenderAlphaSoftZ", -1); sq_pushinteger(vm, Material::Render_AlphaSoftZ); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderAlphaInShadow", -1); sq_pushinteger(vm, Material::Render_AlphaInShadow); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/material_shader_binding.cpp b/include/modules/script_squirrel/legacy/material_shader_binding.cpp new file mode 100644 index 0000000..666e987 --- /dev/null +++ b/include/modules/script_squirrel/legacy/material_shader_binding.cpp @@ -0,0 +1,72 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "core/render_data.h" + + using namespace GS::Render; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger MaterialShaderSetUniformValue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(shader, MaterialShader, typetag_MaterialShader) + __SQ_GETSTRING(name) + __SQ_GETVECTOR(value) + bool r = shader->SetUserUniformValue(name, value); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger MaterialShaderSetUniformTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(shader, MaterialShader, typetag_MaterialShader) + __SQ_GETSTRING(name) + __SQ_GETSAFEPTRALLOWNULL(t, Texture, typetag_Texture) + bool r = shader->SetUserUniformValue(name, t); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterMaterialShaderBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Material Shader + Type: MaterialShader + Desc: A material shader holds all the variants of a shader required to render a material. +#*/ + +/*# + Section: MaterialShaderGeneral + Desc: General functions +#*/ + /*# + Func: MaterialShaderSetUniformValue + Proto: bool:MaterialShader shader,String name,Vector value + Desc: Set uniform value in a material shader. + Note: The value is always passed as a vector of 4 floats, if the uniform type is smaller than vec4 unused entries of the vector are ignored. + Example: +local shader = MaterialGetShader(material) +// u_user_param is a float. +MaterialShaderSetUniformValue(shader, "u_user_param", Vector(1.0, 0.0, 0.0, 0.0)) + #*/ + sq_register(vm, MaterialShaderSetUniformValue, "MaterialShaderSetUniformValue", _SC(".xsx")); + /*# + Func: MaterialShaderSetUniformTexture + Proto: bool:MaterialShader shader,String name,Texture texture + Desc: Set uniform texture in a material shader. + Example: +local shader = MaterialGetShader(material) +// u_user_tex is a Texture2D. +MaterialShaderSetUniformTexture(shader, "u_user_tex", ResourceFactoryLoadTexture(g_factory, "textures/texture.png")) + #*/ + sq_register(vm, MaterialShaderSetUniformTexture, "MaterialShaderSetUniformTexture", _SC(".xsx")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/matrix_binding.cpp b/include/modules/script_squirrel/legacy/matrix_binding.cpp new file mode 100644 index 0000000..bd18e84 --- /dev/null +++ b/include/modules/script_squirrel/legacy/matrix_binding.cpp @@ -0,0 +1,165 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "math/matrix4.h" + #include "math/matrix3.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +SQInteger PushMatrix4(HSQUIRRELVM vm, const Matrix4 &mtx) +{ + push_Matrix4(vm, mtx); +/* + if (!CreateClassInstance(vm, "Matrix4", true)) + return sq_suspendvm(vm); + + SetTableKey("m00", sq_pushfloat, -1, mtx.m[0][0]); + SetTableKey("m10", sq_pushfloat, -1, mtx.m[1][0]); + SetTableKey("m20", sq_pushfloat, -1, mtx.m[2][0]); + SetTableKey("m30", sq_pushfloat, -1, mtx.m[3][0]); + SetTableKey("m01", sq_pushfloat, -1, mtx.m[0][1]); + SetTableKey("m11", sq_pushfloat, -1, mtx.m[1][1]); + SetTableKey("m21", sq_pushfloat, -1, mtx.m[2][1]); + SetTableKey("m31", sq_pushfloat, -1, mtx.m[3][1]); + SetTableKey("m02", sq_pushfloat, -1, mtx.m[0][2]); + SetTableKey("m12", sq_pushfloat, -1, mtx.m[1][2]); + SetTableKey("m22", sq_pushfloat, -1, mtx.m[2][2]); + SetTableKey("m32", sq_pushfloat, -1, mtx.m[3][2]); + SetTableKey("m03", sq_pushfloat, -1, mtx.m[0][3]); + SetTableKey("m13", sq_pushfloat, -1, mtx.m[1][3]); + SetTableKey("m23", sq_pushfloat, -1, mtx.m[2][3]); + SetTableKey("m33", sq_pushfloat, -1, mtx.m[3][3]); +*/ + return 1; +} +SQInteger GetMatrix4(HSQUIRRELVM vm, int idx, Matrix4 &mtx) +{ + GetTableKey("m00", sq_getfloat, idx, mtx.m[0][0]); + GetTableKey("m10", sq_getfloat, idx, mtx.m[1][0]); + GetTableKey("m20", sq_getfloat, idx, mtx.m[2][0]); + GetTableKey("m30", sq_getfloat, idx, mtx.m[3][0]); + GetTableKey("m01", sq_getfloat, idx, mtx.m[0][1]); + GetTableKey("m11", sq_getfloat, idx, mtx.m[1][1]); + GetTableKey("m21", sq_getfloat, idx, mtx.m[2][1]); + GetTableKey("m31", sq_getfloat, idx, mtx.m[3][1]); + GetTableKey("m02", sq_getfloat, idx, mtx.m[0][2]); + GetTableKey("m12", sq_getfloat, idx, mtx.m[1][2]); + GetTableKey("m22", sq_getfloat, idx, mtx.m[2][2]); + GetTableKey("m32", sq_getfloat, idx, mtx.m[3][2]); + GetTableKey("m03", sq_getfloat, idx, mtx.m[0][3]); + GetTableKey("m13", sq_getfloat, idx, mtx.m[1][3]); + GetTableKey("m23", sq_getfloat, idx, mtx.m[2][3]); + GetTableKey("m33", sq_getfloat, idx, mtx.m[3][3]); + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PushMatrix3(HSQUIRRELVM vm, const Matrix3 &mtx) +{ + push_Matrix3(vm, mtx); +/* + if (!CreateClassInstance(vm, "Matrix3", true)) + return sq_suspendvm(vm); + + SetTableKey("m00", sq_pushfloat, -1, mtx.m[0][0]); + SetTableKey("m10", sq_pushfloat, -1, mtx.m[1][0]); + SetTableKey("m20", sq_pushfloat, -1, mtx.m[2][0]); + SetTableKey("m01", sq_pushfloat, -1, mtx.m[0][1]); + SetTableKey("m11", sq_pushfloat, -1, mtx.m[1][1]); + SetTableKey("m21", sq_pushfloat, -1, mtx.m[2][1]); + SetTableKey("m02", sq_pushfloat, -1, mtx.m[0][2]); + SetTableKey("m12", sq_pushfloat, -1, mtx.m[1][2]); + SetTableKey("m22", sq_pushfloat, -1, mtx.m[2][2]); +*/ + return 1; +} +SQInteger GetMatrix3(HSQUIRRELVM vm, int idx, Matrix3 &mtx) +{ + GetTableKey("m00", sq_getfloat, idx, mtx.m[0][0]); + GetTableKey("m10", sq_getfloat, idx, mtx.m[1][0]); + GetTableKey("m20", sq_getfloat, idx, mtx.m[2][0]); + GetTableKey("m01", sq_getfloat, idx, mtx.m[0][1]); + GetTableKey("m11", sq_getfloat, idx, mtx.m[1][1]); + GetTableKey("m21", sq_getfloat, idx, mtx.m[2][1]); + GetTableKey("m02", sq_getfloat, idx, mtx.m[0][2]); + GetTableKey("m12", sq_getfloat, idx, mtx.m[1][2]); + GetTableKey("m22", sq_getfloat, idx, mtx.m[2][2]); + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RotationMatrixFromDirection(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETVECTOR(direction)) + __SQ_RETURNMATRIX3(Matrix3::FromOrthonormalBasis(direction)) +} +SQInteger RotationMatrixFromDirectionAndUp(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETVECTOR(direction) + __SQ_GETVECTOR(up) + __SQ_GETEND + __SQ_RETURNMATRIX3(Matrix3::FromOrthonormalBasis(direction, &up)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger EulerFromDirection(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETVECTOR(direction)) + __SQ_RETURNVECTOR(Matrix3::FromOrthonormalBasis(direction).AsEuler()) +} +SQInteger EulerFromDirectionAndUp(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETVECTOR(direction) + __SQ_GETVECTOR(up) + __SQ_GETEND + __SQ_RETURNVECTOR(Matrix3::FromOrthonormalBasis(direction, &up).AsEuler()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MatrixToEuler(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETMATRIX3(matrix) + __SQ_GETINT(rorder) + __SQ_GETEND + __SQ_RETURNVECTOR(matrix.AsEuler((Math::rOrder)rorder)) +} +SQInteger TransformationMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETVECTOR(p) + __SQ_GETVECTOR(r) + __SQ_GETVECTOR(s) + __SQ_GETVECTOR(t) + __SQ_GETEND + __SQ_RETURNMATRIX4(Matrix4::TransformationMatrix(p, r, s, &t)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterMatrixBinding(HSQUIRRELVM vm) +{ + using namespace GS::Script; + + sq_register(vm, MatrixToEuler, "MatrixToEuler", _SC(".xi")); + sq_register(vm, TransformationMatrix, "TransformationMatrix", _SC(".xxxx")); + + sq_register(vm, RotationMatrixFromDirection, "RotationMatrixFromDirection", _SC(".x")); + sq_register(vm, RotationMatrixFromDirectionAndUp, "RotationMatrixFromDirectionAndUp", _SC(".xx")); + sq_register(vm, EulerFromDirection, "EulerFromDirection", _SC(".x")); + sq_register(vm, EulerFromDirectionAndUp, "EulerFromDirectionAndUp", _SC(".xx")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/mixer_binding.cpp b/include/modules/script_squirrel/legacy/mixer_binding.cpp new file mode 100644 index 0000000..778b547 --- /dev/null +++ b/include/modules/script_squirrel/legacy/mixer_binding.cpp @@ -0,0 +1,399 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "core/sound.h" + #include "core/mixer.h" + + using namespace GS::Audio; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger MixerSetGain(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETFLOAT(gain) + __SQ_GETEND + mixer->SetMasterVolume(gain); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MixerMute(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mixer, IMixer, typetag_Mixer) + mixer->SetMasterVolume(0); + __SQ_RETURN +} +SQInteger MixerUnmute(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mixer, IMixer, typetag_Mixer) + mixer->SetMasterVolume(1); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MixerChannelLock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_RETURNINT(mixer->LockChannel()) +} +SQInteger MixerChannelUnlock(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETEND + mixer->UnlockChannel(channel); + __SQ_RETURN +} +SQInteger MixerChannelUnlockAll(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mixer, IMixer, typetag_Mixer) + mixer->UnlockAllChannels(); + __SQ_RETURN +} +SQInteger MixerChannelStart(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETSAFEPTR(sound, Sound, typetag_Sound) + __SQ_GETEND + __SQ_RETURNBOOL(mixer->Start(channel, sound->mixer_data)) +} +SQInteger MixerChannelStartStream(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETSTRING(uri) + int r = mixer->Stream(channel, uri); + __SQ_GETEND + __SQ_RETURNBOOL(r != -1) +} +SQInteger MixerSoundStartFast(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETSAFEPTR(sound, Sound, typetag_Sound) + bool r = mixer->StartFast(-1, sound->mixer_data); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger MixerSoundStart(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETSAFEPTR(sound, Sound, typetag_Sound) + int channel = mixer->Start(-1, sound->mixer_data); + __SQ_GETEND + __SQ_RETURNINT(channel) +} +SQInteger MixerStreamStartFast(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETSTRING(uri) + bool r = mixer->StreamFast(-1, uri); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger MixerStreamStart(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETSTRING(uri) + int channel = mixer->Stream(-1, uri); + __SQ_GETEND + __SQ_RETURNINT(channel) +} +SQInteger MixerChannelPause(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETEND + mixer->Pause(channel); + __SQ_RETURN +} +SQInteger MixerChannelResume(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETEND + mixer->Resume(channel); + __SQ_RETURN +} +SQInteger MixerChannelGetState(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETEND + __SQ_RETURNINT(0) +} +SQInteger MixerChannelStop(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETEND + mixer->Stop(channel); + __SQ_RETURN +} +SQInteger MixerChannelStopAll(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(mixer, IMixer, typetag_Mixer) +// mixer->StopAllChannels(); + __SQ_RETURN +} +SQInteger MixerChannelSetGain(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETFLOAT(gain) + __SQ_GETEND + mixer->SetChannelVolume(channel, gain); + __SQ_RETURN +} +SQInteger MixerChannelSetPitch(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETFLOAT(pitch) + __SQ_GETEND + mixer->SetChannelPitch(channel, pitch); + __SQ_RETURN +} +SQInteger MixerChannelSetPanning(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETFLOAT(panning) + __SQ_GETEND + mixer->SetChannelPanning(channel, panning); + __SQ_RETURN +} +SQInteger MixerChannelSetLoopMode(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETINT(loop) + __SQ_GETEND + mixer->SetChannelLoopMode(channel, (IMixer::Loop)loop); + __SQ_RETURN +} +SQInteger MixerChannelSetLoopPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mixer, IMixer, typetag_Mixer) + __SQ_GETINT(channel) + __SQ_GETINT(position) + __SQ_GETEND + mixer->SetChannelLoopPosition(channel, position); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterMixerBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Mixer + Type: Mixer + Type: Channel + Related: Sound,ResourceFactory +#*/ + +/*# + Section: ChannelManagement + Desc: Channel management functions +#*/ + /*# + Func: MixerChannelGetState + Proto: ChannelState:Mixer,int channel + Desc: Return the channel state. + #*/ + sq_register(vm, MixerChannelGetState, "MixerChannelGetState", _SC(".xi")); + /*# + Func: MixerChannelStop + Proto: void:Mixer,int channel + Desc: Stop playback on a given channel. + #*/ + sq_register(vm, MixerChannelStop, "MixerChannelStop", _SC(".xi")); + /*# + Func: MixerChannelPause + Proto: void:Mixer,int channel + Desc: Pause playback on a given channel. + #*/ + sq_register(vm, MixerChannelPause, "MixerChannelPause", _SC(".xi")); + /*# + Func: MixerChannelResume + Proto: void:Mixer,int channel + Desc: Resume playback on a given channel. + #*/ + sq_register(vm, MixerChannelResume, "MixerChannelResume", _SC(".xi")); + /*# + Func: MixerChannelStopAll + Proto: void:Mixer + Desc: Stop replay on all mixer channels. + #*/ + sq_register(vm, MixerChannelStopAll, "MixerChannelStopAll", _SC(".x")); + +/*# + Section: MixerControl + Desc: Mixer control functions +#*/ + /*# + Func: MixerSetGain + Proto: void:Mixer mixer,float gain + Desc: Set the global mixer gain. + #*/ + sq_register(vm, MixerSetGain, "MixerSetGain", _SC(".xn")); + /*# + Func: MixerPlaySoundFast + Proto: bool:Mixer mixer,Sound sound + Desc: Play a sound on the first channel available, this function returns immediately and the channel used for replay is not returned. + See: ResourceFactoryLoadSound + #*/ + sq_register(vm, MixerSoundStartFast, "MixerSoundStartFast", _SC(".xx")); + sq_register(vm, MixerSoundStartFast, "MixerPlaySoundFast", _SC(".xx")); + /*# + Func: MixerPlaySound + Proto: Channel:Mixer mixer,Sound sound + Desc: Play a sound on the first channel available, the channel used for replay is returned. If no free channel was found -1 is returned. + Note: Use MixerPlaySoundFast to prevent waiting for the mixer thread to return the channel used for playback if you do not need this information. + See: MixerPlaySoundFast,ResourceFactoryLoadSound,MixerChannelPlaySound + #*/ + sq_register(vm, MixerSoundStart, "MixerSoundStart", _SC(".xx")); + sq_register(vm, MixerSoundStart, "MixerPlaySound", _SC(".xx")); + /*# + Func: MixerStartStreamFast + Proto: bool:Mixer,uri + Desc: Play a stream on the first channel available, this function returns immediately and the channel used for replay is not returned. + #*/ + sq_register(vm, MixerStreamStartFast, "MixerStreamStartFast", _SC(".xs")); + sq_register(vm, MixerStreamStartFast, "MixerStartStreamFast", _SC(".xs")); + /*# + Func: MixerStartStream + Proto: Channel:Mixer,uri + Desc: Play a stream on the first channel available, the channel used for replay is returned. If no free channel was found -1 is returned. + Note: Use MixerStartStreamFast to prevent waiting for the mixer thread to return the channel used for playback if you do not need this information. + See: MixerStartStreamFast,MixerChannelStartStream + #*/ + sq_register(vm, MixerStreamStart, "MixerStreamStart", _SC(".xs")); + sq_register(vm, MixerStreamStart, "MixerStartStream", _SC(".xs")); + /*# + Func: MixerMute + Proto: void:Mixer + Desc: Mute all sound output. + #*/ + sq_register(vm, MixerMute, "MixerMute", _SC(".x")); + /*# + Func: MixerUnmute + Proto: void:Mixer + Desc: Unmute all sound output. + #*/ + sq_register(vm, MixerUnmute, "MixerUnmute", _SC(".x")); + +/*# + Section: ChannelControl + Desc: Channel control functions +#*/ + /*# + Func: MixerChannelLock + Proto: Channel:Mixer + Desc: Lock a new mixer channel. + #*/ + sq_register(vm, MixerChannelLock, "MixerChannelLock", _SC(".x")); + /*# + Func: MixerChannelUnlock + Proto: void:Mixer,Channel + Desc: Unlock channel. + #*/ + sq_register(vm, MixerChannelUnlock, "MixerChannelUnlock", _SC(".xi")); + /*# + Func: MixerChannelUnlockAll + Proto: void:Mixer + Desc: Unlock all channels. + #*/ + sq_register(vm, MixerChannelUnlockAll, "MixerChannelUnlockAll", _SC(".x")); + /*# + Func: MixerChannelPlaySound + Proto: bool:Mixer,Channel,Sound + Desc: Play a sound on a specific channel. Returns true on success, false otherwise. + #*/ + sq_register(vm, MixerChannelStart, "MixerChannelStart", _SC(".xix")); + sq_register(vm, MixerChannelStart, "MixerChannelPlaySound", _SC(".xix")); + /*# + Func: MixerChannelStartStream + Proto: bool:Mixer,Channel,string uri + Desc: Play a stream on a specific channel. Returns true on success, false otherwise. + #*/ + sq_register(vm, MixerChannelStartStream, "MixerChannelStartStream", _SC(".xis")); + + /*# + Func: MixerChannelSetGain + Proto: void:Mixer,Channel,float gain + Desc: Set channel gain. Note: The channel gain is not reset by starting new sounds. + #*/ + sq_register(vm, MixerChannelSetGain, "MixerChannelSetGain", _SC(".xin")); + /*# + Func: MixerChannelSetPitch + Proto: void:Mixer,Channel,float pitch + Desc: Set channel pitch (Default: 1.0). Note: The channel pitch is not reset by starting new sounds. + #*/ + sq_register(vm, MixerChannelSetPitch, "MixerChannelSetPitch", _SC(".xin")); + /*# + Func: MixerChannelSetPanning + Proto: void:Mixer,Channel,float panning + Desc: Set channel panning (Default: 0.5). Note: The channel panning is not reset by starting new sounds. + #*/ + sq_register(vm, MixerChannelSetPanning, "MixerChannelSetPanning", _SC(".xin")); + /*# + Func: MixerChannelSetLoopMode + Proto: void:Mixer,Channel,ChannelLoop loop + Desc: Set channel loop mode. + #*/ + sq_register(vm, MixerChannelSetLoopMode, "MixerChannelSetLoopMode", _SC(".xii")); + /*# + Func: MixerChannelSetLoopPosition + Proto: void:Mixer,Channel,int ms + Desc: Set channel loop position in millisecond, the loop mode must be set to LoopRepeat for this setting to have any effect. + #*/ + sq_register(vm, MixerChannelSetLoopPosition, "MixerChannelSetLoopPosition", _SC(".xii")); + + // Push defines. + sq_pushroottable(vm); + + /*# + Enum: ChannelLoop + Values: LoopNone,LoopRepeat + #*/ + sq_pushstring(vm, "LoopNone", -1); sq_pushinteger(vm, IMixer::None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "LoopRepeat", -1); sq_pushinteger(vm, IMixer::Repeat); sq_newslot(vm, -3, true); + + /*# + Enum: ChannelState + Values: ChannelStateInvalid,ChannelStateStopped,ChannelStatePlaying,ChannelStatePaused + #*/ + sq_pushstring(vm, "ChannelStateInvalid", -1); sq_pushinteger(vm, IMixer::Invalid); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelStateStopped", -1); sq_pushinteger(vm, IMixer::Stopped); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelStatePlaying", -1); sq_pushinteger(vm, IMixer::Playing); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelStatePaused", -1); sq_pushinteger(vm, IMixer::Paused); sq_newslot(vm, -3, true); + sq_pop(vm, 1); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/motion_binding.cpp b/include/modules/script_squirrel/legacy/motion_binding.cpp new file mode 100644 index 0000000..4dd5cb5 --- /dev/null +++ b/include/modules/script_squirrel/legacy/motion_binding.cpp @@ -0,0 +1,250 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "motion/motion.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::Script; + +/* +#include "micropather.h" +using namespace micropather; + +#include "pathfinding.h" + +MicroPather *pather; +MapPathFinder* pathfinding_map; + +//------------------------------------------------------------------------------ +SQInteger NodePathFinder_CreateNode(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETINT(id) + __SQ_GETINT(id_child) + __SQ_GETEND + + pathfinding_map->AddChildToNode(id, id_child); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +SQInteger NodePathFinder_AddChild(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETINT(id) + __SQ_GETFLOAT(weight) + __SQ_GETEND + + pathfinding_map->CreateNode(weight, id); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +SQInteger CreateMicroPather(HSQUIRRELVM vm) +{ + pathfinding_map = new MapPathFinder(); + pather = new MicroPather(pathfinding_map, 20); + __SQ_RETURN +} +*/ +//------------------------------------------------------------------------------ +SQInteger MotionGetClosestPoint(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(motion, Motion, typetag_Motion) + __SQ_GETVECTOR(p) + __SQ_GETEND + + Vector4 closest; + if (motion) + motion->GetClosestPoint(p, closest); + __SQ_RETURNVECTOR(closest) +} +SQInteger MotionGetClosestTime(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(motion, Motion, typetag_Motion) + __SQ_GETVECTOR(p) + __SQ_GETEND + + Vector4 closest; + float closest_t = 0.f; + if (motion) + motion->GetClosestPoint(p, closest, &closest_t); + __SQ_RETURNFLOAT(closest_t); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MotionEvaluateData(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(motion, Motion, typetag_Motion) + __SQ_GETFLOAT(t) + __SQ_GETEND + GS::Variant sample; + if (motion) + motion->EvaluateData(Time::fromSec(t), sample); + __SQ_RETURNSTRING(sample.s_value) +} +SQInteger MotionEvaluatePosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(motion, Motion, typetag_Motion) + __SQ_GETFLOAT(t) + __SQ_GETEND + Vector4 sample(0, 0, 0); + if (motion) + motion->EvaluatePosition(Time::fromSec(t), sample, Curve::Repeat); + __SQ_RETURNVECTOR(sample) +} + +SQInteger MotionEvaluateDirection(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(motion, Motion, typetag_Motion) + __SQ_GETFLOAT(t) + __SQ_GETEND + Vector4 sample(0, 0, 0); + if (motion) + motion->EvaluateDirection(Time::fromSec(t), sample, Curve::Repeat); + __SQ_RETURNVECTOR(sample) +} + + +SQInteger MotionEvaluatePositionConstant(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(motion, Motion, typetag_Motion) + __SQ_GETFLOAT(t) + __SQ_GETEND + Vector4 sample(0, 0, 0); + if (motion) + motion->EvaluatePosition(Time::fromSec(t), sample, Curve::Constant); + __SQ_RETURNVECTOR(sample) +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger MotionGetName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Motion, typetag_Motion) + __SQ_RETURNSTRING(m->name) +} +SQInteger MotionGetLength(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(m, Motion, typetag_Motion) + __SQ_RETURNFLOAT(m->GetDuration().toSec()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterMotionBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Motion + Type: Motion +#*/ + +/*# + Section: Motion + Desc: Motion functions +#*/ + /*# + Func: MotionGetClosestPoint + Proto: float:Motion,Vector + Desc: Return the nearest point on this motion for the position given + #*/ + sq_register(vm, MotionGetClosestPoint, "MotionGetClosestPoint", _SC(".xx")); + /*# + Func: MotionGetClosestTime + Proto: float:Motion,Vector + Desc: Return the time for the nearest position. + #*/ + sq_register(vm, MotionGetClosestTime, "MotionGetClosestTime", _SC(".xx")); + /*# + Func: MotionGetName + Proto: String:Motion + Desc: Return motion name. + #*/ + sq_register(vm, MotionGetName, "MotionGetName", _SC(".x")); + /*# + Func: MotionEvaluateData + Proto: String:Motion,float time + Desc: Evaluate the data in motion at the specified time. + #*/ + sq_register(vm, MotionEvaluateData, "MotionEvaluateData", _SC(".xn")); + /*# + Func: MotionEvaluatePosition + Proto: Vector:Motion,float time + Desc: Evaluate position triplet (x, y, z) in motion at the specified time. Note that a motion may not have all or any of the channels required for this evaluation. + #*/ + sq_register(vm, MotionEvaluatePosition, "MotionEvaluatePosition", _SC(".xn")); + sq_register(vm, MotionEvaluateDirection, "MotionEvaluateDirection", _SC(".xn")); + /*# + Func: MotionEvaluatePositionConstant + Proto: Vector:Motion,float time + Desc: IT'S CLAMPED TO THE BEGINING AND END. Evaluate position triplet (x, y, z) in motion at the specified time. Note that a motion may not have all or any of the channels required for this evaluation. + #*/ + sq_register(vm, MotionEvaluatePositionConstant, "MotionEvaluatePositionConstant", _SC(".xn")); + + /*# + Func: MotionGetLength + Proto: float:Motion + Desc: Return highest timecode in motion. + #*/ + sq_register(vm, MotionGetLength, "MotionGetLength", _SC(".x")); + + // Push defines. + sq_pushroottable(vm); + + sq_pushstring(vm, "ChannelNone", -1); sq_pushinteger(vm, MotionChannel::NoType); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelXPos", -1); sq_pushinteger(vm, MotionChannel::XPos); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelYPos", -1); sq_pushinteger(vm, MotionChannel::YPos); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelZPos", -1); sq_pushinteger(vm, MotionChannel::ZPos); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelXRot", -1); sq_pushinteger(vm, MotionChannel::XRot); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelYRot", -1); sq_pushinteger(vm, MotionChannel::YRot); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelZRot", -1); sq_pushinteger(vm, MotionChannel::ZRot); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelXScl", -1); sq_pushinteger(vm, MotionChannel::XScl); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelYScl", -1); sq_pushinteger(vm, MotionChannel::YScl); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelZScl", -1); sq_pushinteger(vm, MotionChannel::ZScl); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelXPiv", -1); sq_pushinteger(vm, MotionChannel::XPiv); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelYPiv", -1); sq_pushinteger(vm, MotionChannel::YPiv); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelZPiv", -1); sq_pushinteger(vm, MotionChannel::ZPiv); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelRDif", -1); sq_pushinteger(vm, MotionChannel::RDif); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelGDif", -1); sq_pushinteger(vm, MotionChannel::GDif); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelBDif", -1); sq_pushinteger(vm, MotionChannel::BDif); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelRSpc", -1); sq_pushinteger(vm, MotionChannel::RSpc); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelGSpc", -1); sq_pushinteger(vm, MotionChannel::GSpc); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelBSpc", -1); sq_pushinteger(vm, MotionChannel::BSpc); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelDiffuseIntensity", -1); sq_pushinteger(vm, MotionChannel::DiffuseIntensity); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelSpecularIntensity", -1); sq_pushinteger(vm, MotionChannel::SpecularIntensity); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelConeAngle", -1); sq_pushinteger(vm, MotionChannel::ConeAngle); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelEdgeAngle", -1); sq_pushinteger(vm, MotionChannel::EdgeAngle); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelAlpha", -1); sq_pushinteger(vm, MotionChannel::Alpha); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelZoomFactor", -1); sq_pushinteger(vm, MotionChannel::ZoomFactor); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelRange", -1); sq_pushinteger(vm, MotionChannel::Range); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "ChannelFogStart", -1); sq_pushinteger(vm, MotionChannel::FogStart); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelFogEnd", -1); sq_pushinteger(vm, MotionChannel::FogEnd); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelRFog", -1); sq_pushinteger(vm, MotionChannel::RFog); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelGFog", -1); sq_pushinteger(vm, MotionChannel::GFog); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ChannelBFog", -1); sq_pushinteger(vm, MotionChannel::BFog); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/nml_binding.cpp b/include/modules/script_squirrel/legacy/nml_binding.cpp new file mode 100644 index 0000000..2c27b95 --- /dev/null +++ b/include/modules/script_squirrel/legacy/nml_binding.cpp @@ -0,0 +1,502 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "metafile/nml.h" + + using namespace GS; + using namespace GS::NML; + using namespace GS::Script; + + +//----------------------------------------------------------------------------- +SQInteger MetafileGetRoots(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(metafile, File, typetag_Metafile) + + sq_newarray(vm, 0); + if (metafile) + { + NMLFileForeach(tag, *metafile) + { + CObject::Push(vm, tag, typetag_Metatag, false); + sq_arrayappend(vm, -2); + } + } + return 1; +} +SQInteger MetatagGetChildren(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(metatag, Tag, typetag_Metatag) + + sq_newarray(vm, 0); + if (metatag) + { + NMLTagForeach(tag, *metatag) + { + CObject::Push(vm, tag, typetag_Metatag, false); + sq_arrayappend(vm, -2); + } + } + return 1; +} + +SQInteger MetafileNew(HSQUIRRELVM vm) +{ __SQ_RETURNMANAGEDSAFEPTR(new File, typetag_Metafile) } +SQInteger MetafileDelete(HSQUIRRELVM vm) +{ __SQ_RETURN } + +SQInteger MetafileLoadFromString(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mf, File, typetag_Metafile) + __SQ_GETSTRING(file) + bool success = Parser::LoadFromMemory((char *)file, String::strlen(file), *mf); + __SQ_GETEND + __SQ_RETURNBOOL(success) +} +SQInteger MetafileLoad(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mf, File, typetag_Metafile) + __SQ_GETSTRING(uri) + bool success = Parser::Load(uri, *mf); // take care of the string + __SQ_GETEND + __SQ_RETURNBOOL(success) +} +SQInteger MetafileSave(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mf, File, typetag_Metafile) + __SQ_GETSTRING(uri) + bool success = Parser::Save(uri, *mf); + __SQ_GETEND + __SQ_RETURNBOOL(success) +} + +//----------------------------------------------------------------------------- +static Tag *CreateMetatagFromSquirrelStackEntry(HSQUIRRELVM vm, int idx, const char *path) +{ + Tag *tag = NULL; + switch (sq_gettype(vm, idx)) + { + case OT_NULL: + tag = new Tag(path); + break; + + case OT_INTEGER: + { + SQInteger value; + sq_getinteger(vm, idx, &value); + tag = new Tag(path, (int)value); + } + break; + + case OT_FLOAT: + { + float value; + sq_getfloat(vm, idx, &value); + tag = new Tag(path, value); + } + break; + + case OT_BOOL: + { + SQBool value; + sq_getbool(vm, idx, &value); + tag = new Tag(path, value ? true : false); + } + break; + + case OT_STRING: + { + const char *value; + sq_getstring(vm, idx, &value); + tag = new Tag(path, value); + } + break; + + case OT_TABLE: + case OT_ARRAY: + default: + __LOG_E__ << "Cannot convert input Squirrel type to metatag value.\n"; + break; + } + return tag; +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +SQInteger MetafileAddRoot(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mf, File, typetag_Metafile) + __SQ_GETSTRING(path) + Tag *tag = new Tag(path); + if (!tag) + return sq_throwerror(vm, "Failed to allocate metatag."); + mf->AddRoot(tag); + __SQ_GETEND + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +SQInteger MetatagAddChild(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(itg, Tag, typetag_Metatag) + __SQ_GETSTRING(path) + Tag *tag = new Tag(path); + if (!tag) + return sq_throwerror(vm, "Failed to allocate metatag."); + itg->AddChild(tag); + __SQ_GETEND + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +SQInteger MetatagDeleteChild(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(tag, Tag, typetag_Metatag) + __SQ_GETSAFEPTR(child, Tag, typetag_Metatag) + __SQ_GETEND + + if (!tag->RemoveTag(child)) + return sq_throwerror(vm, "Child tag does not belong to this tag."); + + __SQ_INVALIDATENATIVEREF(child); + _safe_delete(child); // tags are not managed + __SQ_RETURN +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +SQInteger MetafileAddRootWithValue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mf, File, typetag_Metafile) + __SQ_GETSTRING(path) + Tag *tag = CreateMetatagFromSquirrelStackEntry(vm, __SQ_STACKPOS, path); + __SQ_GETUPDATESTACK + __SQ_GETEND + if (!tag) + return sq_throwerror(vm, "Failed to add root tag to metafile."); + mf->AddRoot(tag); + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +SQInteger MetatagAddChildWithValue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(itg, Tag, typetag_Metatag) + __SQ_GETSTRING(path) + Tag *tag = CreateMetatagFromSquirrelStackEntry(vm, __SQ_STACKPOS, path); + __SQ_GETUPDATESTACK + __SQ_GETEND + if (!tag) + return sq_throwerror(vm, "Failed to add child tag."); + itg->AddChild(tag); + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +SQInteger MetafileGetTag(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mf, File, typetag_Metafile) + __SQ_GETSTRING(path) + Tag *tag = mf->GetTag(path); + __SQ_GETEND + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +SQInteger MetafileGetTypedTag(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mf, File, typetag_Metafile) + __SQ_GETSTRING(path) + __SQ_GETINT(type) + Tag *tag = mf->GetTypedTag(path, (GS::Variant::Type)type); + __SQ_GETEND + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +SQInteger MetatagGetTag(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mf, Tag, typetag_Metatag) + __SQ_GETSTRING(path) + Tag *tag = mf->GetTag(path); + __SQ_GETEND + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +SQInteger MetatagGetTypedTag(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mf, Tag, typetag_Metatag) + __SQ_GETSTRING(path) + __SQ_GETINT(type) + Tag *tag = mf->GetTypedTag(path, (GS::Variant::Type)type); + __SQ_GETEND + __SQ_RETURNSAFEPTR(tag, typetag_Metatag) +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +SQInteger MetatagGetType(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(tag, Tag, typetag_Metatag) + __SQ_RETURNINT((int)tag->GetValue().GetType()) +} +SQInteger MetatagGetName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(tag, Tag, typetag_Metatag) + __SQ_RETURNSTRING(tag->name.c_str()) +} +SQInteger MetatagSetName(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(tag, Tag, typetag_Metatag) + __SQ_GETSTRING(_name) + tag->name = _name; + __SQ_GETEND + __SQ_RETURN +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +SQInteger MetatagGetValue(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(tag, Tag, typetag_Metatag) + + switch (tag->GetValue().GetType()) + { + default: + case GS::Variant::VariantNone: + case GS::Variant::VariantBinary: + break; + + case GS::Variant::VariantBool: + __SQ_RETURNBOOL(tag->GetBool()) + case GS::Variant::VariantInteger: + __SQ_RETURNINT(tag->GetInteger()) + case GS::Variant::VariantFloat: + __SQ_RETURNFLOAT(tag->GetReal()) + case GS::Variant::VariantString: + __SQ_RETURNSTRING(tag->GetString()) + } + + __LOG_E__ << "Cannot get value from tag '" << tag->name << "'. Unsupported type.\n"; + __SQ_RETURNINT(-1) +} +SQInteger MetatagSetValue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(tag, Tag, typetag_Metatag) + + switch (sq_gettype(vm, -1)) + { + case OT_INTEGER: + { + __SQ_GETINT(value) + tag->SetInteger(value); + } + break; + + case OT_FLOAT: + { + __SQ_GETFLOAT(value) + tag->SetReal(value); + } + break; + + case OT_BOOL: + { + __SQ_GETBOOL(value) + tag->SetBool(value ? true : false); + } + break; + + case OT_STRING: + { + __SQ_GETSTRING(value) + tag->SetString(value); + } + break; + + case OT_NULL: + case OT_TABLE: + case OT_ARRAY: + default: + return sq_throwerror(vm, "Type cannot be converted to metatag value."); + } + + __SQ_GETEND + __SQ_RETURN +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +void RegisterNMLBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Metafile + Type: Metafile + Type: Metatag + Desc: A metafile is very similar to an XML file, it is mostly used to store data in a structured way. +#*/ + +/*# + Section: MetaFile + Desc: File functions +#*/ + /*# + Func: MetafileNew + Proto: Metafile: + Desc: Create a new metafile, this object is managed, the VM will free it. + #*/ + sq_register(vm, MetafileNew, "MetafileNew", _SC(".")); + // Obsolete + sq_register(vm, MetafileDelete, "MetafileDelete", _SC(".x")); + /*# + Func: MetafileLoadFromString + Proto: bool:Metafile,string content + Desc: Load metafile from a string. + #*/ + sq_register(vm, MetafileLoadFromString, "MetafileLoadFromString", _SC(".xs")); + /*# + Func: MetafileLoad + Proto: bool:Metafile,string path + Desc: Load metafile from file system. + #*/ + sq_register(vm, MetafileLoad, "MetafileLoad", _SC(".xs")); + /*# + Func: MetafileSave + Proto: bool:Metafile,string path + Desc: Save metafile to file system. + #*/ + sq_register(vm, MetafileSave, "MetafileSave", _SC(".xs")); + /*# + Func: MetafileAddRoot + Proto: Metatag:Metafile,string tag_name + Desc: Add metafile root, returns the newly created metatag. + #*/ + sq_register(vm, MetafileAddRoot, "MetafileAddRoot", _SC(".xs")); + /*# + Func: MetafileAddRootWithValue + Proto: Metatag:Metafile,string tag_name,... + Desc: Add metafile root, returns the newly created metatag. + #*/ + sq_register(vm, MetafileAddRootWithValue, "MetafileAddRootWithValue", _SC(".xs.")); + /*# + Func: MetafileGetRoots + Proto: array:Metafile + Desc: Return all root tags of a metafile in an array. + #*/ + sq_register(vm, MetafileGetRoots, "MetafileGetRoots", _SC(".x")); + /*# + Func: MetafileGetTag + Proto: Metatag:Metafile,string tag_path + Desc: Get metatag from metafile, the metatag path is formatted as follow: tag:child:tag_id; (eg: 'Pref:Sound:Volume;'). + #*/ + sq_register(vm, MetafileGetTag, "MetafileGetTag", _SC(".xs")); + /*# + Func: MetafileGetTypedTag + Proto: Metatag:Metafile,string tag_path,TagType + Desc: Get metatag of a specific value type from a metafile. + #*/ + sq_register(vm, MetafileGetTypedTag, "MetafileGetTypedTag", _SC(".xsi")); + +/*# + Section: MetaTag + Desc: Tag functions +#*/ + /*# + Func: MetatagGetName + Proto: string:Metatag + Desc: Get metatag name. + #*/ + sq_register(vm, MetatagGetName, "MetatagGetName", _SC(".x")); + /*# + Func: MetatagSetName + Proto: void:Metatag,String + Desc: Set metatag name. + #*/ + sq_register(vm, MetatagSetName, "MetatagSetName", _SC(".xs")); + /*# + Func: MetatagGetType + Proto: TagType:Metatag + Desc: Get metatag type. + #*/ + sq_register(vm, MetatagGetType, "MetatagGetType", _SC(".x")); + /*# + Func: MetatagGetValue + Proto: ...:Metatag + Desc: Get metatag value. + #*/ + sq_register(vm, MetatagGetValue, "MetatagGetValue", _SC(".x")); + /*# + Func: MetatagSetValue + Proto: void:Metatag,... + Desc: Set metatag value, the value type is automatically handled. + #*/ + sq_register(vm, MetatagSetValue, "MetatagSetValue", _SC(".x.")); + + /*# + Func: MetatagDeleteChild + Proto: void:Metatag tag, Metatag child + Desc: Delete a metatag child tag. + Note: The removed child tag is freed and all existing script references to it are invalidated. + #*/ + sq_register(vm, MetatagDeleteChild, "MetatagDeleteChild", _SC(".xx")); + /*# + Func: MetatagAddChild + Proto: Metatag:Metatag,string tag_name + Desc: Add metatag child, returns the newly created metatag. + #*/ + sq_register(vm, MetatagAddChild, "MetatagAddChild", _SC(".xs")); + /*# + Func: MetatagAddChildWithValue + Proto: Metatag:Metatag,string tag_name,... + Desc: Add metatag child, returns the newly created metatag. + #*/ + sq_register(vm, MetatagAddChildWithValue, "MetatagAddChildWithValue", _SC(".xs.")); + + /*# + Func: MetatagGetTag + Proto: Metatag:Metatag,string tag_path + Desc: Find metatag child. + #*/ + sq_register(vm, MetatagGetTag, "MetatagGetTag", _SC(".xs")); + /*# + Func: MetatagGetTypedTag + Proto: Metatag:Metatag,string tag_path,TagType + Desc: Find child of a specific value type from a metatag. + #*/ + sq_register(vm, MetatagGetTypedTag, "MetatagGetTypedTag", _SC(".xsi")); + /*# + Func: MetatagGetChildren + Proto: Array:Metatag + Desc: Return all children of a metatag in an array. + #*/ + sq_register(vm, MetatagGetChildren, "MetatagGetChildren", _SC(".x")); + + // Push defines. + sq_pushroottable(vm); + + /*# + Enum: TagType + Values: TagTypeBinary,TagTypeString,TagTypeInteger,TagTypeReal,TagTypeNode,TagTypeNone + #*/ + sq_pushstring(vm, "TagTypeBinary", -1); sq_pushinteger(vm, GS::Variant::VariantBinary); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TagTypeInteger", -1); sq_pushinteger(vm, GS::Variant::VariantInteger); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TagTypeNone", -1); sq_pushinteger(vm, GS::Variant::VariantNone); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TagTypeReal", -1); sq_pushinteger(vm, GS::Variant::VariantFloat); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TagTypeString", -1); sq_pushinteger(vm, GS::Variant::VariantString); sq_newslot(vm, -3, true); +#if 1 + sq_pushstring(vm, "TagTypeNode", -1); sq_pushinteger(vm, GS::Variant::VariantNone); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TagTypeTag", -1); sq_pushinteger(vm, GS::Variant::VariantNone); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TagTypeShortcut", -1); sq_pushinteger(vm, GS::Variant::VariantNone); sq_newslot(vm, -3, true); +#endif + + sq_pop(vm, 1); +} +//----------------------------------------------------------------------------- diff --git a/include/modules/script_squirrel/legacy/object_binding.cpp b/include/modules/script_squirrel/legacy/object_binding.cpp new file mode 100644 index 0000000..45e2df4 --- /dev/null +++ b/include/modules/script_squirrel/legacy/object_binding.cpp @@ -0,0 +1,217 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/legacy/binding_helpers.h" + #include "scene3d/mobject.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +static CObjectType object_derived_types[] = { typetag_Item, typetag_Object, typetag_Undefined }; + +//------------------------------------------------------------------------------ +SQInteger ObjectGetLODBias(HSQUIRRELVM vm) +{ + __SQ_RETURNFLOAT(GS::Core::Object::lod_bias) +} +SQInteger ObjectSetLODBias(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETFLOAT(bias)) + GS::Core::Object::lod_bias = bias; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//----------------------------------------------- +SQInteger ObjectGetItem(HSQUIRRELVM vm) +//----------------------------------------------- +{ + __SQ_GETSINGLESAFEPTR(obj, MObject, typetag_Object) + __SQ_RETURNSAFEPTR((MItem *)obj, typetag_Item) +} + +//------------------------------------------------------------------------------ +#define __SQ_ASSERTRENDERDATA(__I__) if (__I__->render_data.IsNull()) return sq_throwerror(vm, "No render data, have you setup this item render data?"); + +SQInteger ObjectSetGeometry(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(o, MObject, object_derived_types) + __SQ_GETSAFEPTRALLOWNULL(geo, GS::Render::Geometry, typetag_Geometry) + __SQ_GETEND + __SQ_ASSERTRENDERDATA(o) + o->geometry = geo ? geo->name : NULL; + o->render_data->geometry = geo; + __SQ_RETURN +} +SQInteger ObjectGetGeometry(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(o, MObject, object_derived_types)) + __SQ_ASSERTRENDERDATA(o) + __SQ_RETURNSAFEPTR(o->render_data->geometry.c_ptr(), typetag_Geometry) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ObjectSkinGetItemCount(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(o, MObject, object_derived_types)) + __SQ_RETURNINT(o->GetBoneCount()) +} +SQInteger ObjectSkinGetItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(o, MObject, object_derived_types) + __SQ_GETINT(n) + __SQ_GETEND + __SQ_RETURNSAFEPTR(o->GetBone(n) ? o->GetBone(n)->mitem : NULL, typetag_Item) +} +SQInteger ObjectSkinSetItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(o, MObject, object_derived_types) + __SQ_GETINT(n) + __SQ_GETSAFEPTRALLOWNULL(b, MItem, typetag_Item) + __SQ_GETEND + o->BindBone(n, b ? b->GetBaseItem() : NULL); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ObjectSetSkinMotion(HSQUIRRELVM vm) +{ +/* + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(obj, MObject, typetag_Object) + __SQ_GETSTRING(motion_id) + __SQ_GETFLOAT(blend) + __SQ_GETFLOAT(weight) + __SQ_GETFLOAT(t) + __SQ_GETBOOL(loop) + nHierarchyMotion *mot = (nHierarchyMotion *)obj->skin_motion_list.Find(motion_id); + if (obj && mot) + SetHierarchyMotion(obj->GetSkin(), mot, blend, weight, t, loop ? true : false); + __SQ_GETEND + __SQ_RETURN +*/ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(o, MObject, object_derived_types) + __SQ_GETSTRING(motion_name) + +// obj->SetSkinMotion(motion_name); + + __SQ_GETEND + __SQ_RETURN +} +SQInteger ObjectSetSkinMotionClockScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(o, MObject, object_derived_types) + __SQ_GETFLOAT(scale) + __SQ_GETEND + return 0; +} +SQInteger ObjectStopAllSkinMotion(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(o, MObject, object_derived_types)) +// if (obj) +// StopAllHierarchyMotion(obj->GetSkin()); + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterObjectBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Object + Type: Object + Related: Item +#*/ + +/*# + Section: ObjectGeneric + Desc: Generic functions +#*/ + /*# + Func: ObjectGetItem + Proto: Item:Object + Desc: Get object item. + #*/ + sq_register(vm, ObjectGetItem, "ObjectGetItem", _SC(".x")); + /*# + Func: ObjectSetGeometry + Proto: void:Object,Geometry + Desc: Set object geometry. + #*/ + sq_register(vm, ObjectSetGeometry, "ObjectSetGeometry", _SC(".xx")); + /*# + Func: ObjectGetGeometry + Proto: Geometry:Object + Desc: Get geometry object. + #*/ + sq_register(vm, ObjectGetGeometry, "ObjectGetGeometry", _SC(".x")); + /*# + Func: ObjectGetLODBias + Proto: float: + Desc: Get global object geometry lod bias. + Note: This value is added to the distance used to select the lod level for a geometry before displaying it. + #*/ + sq_register(vm, ObjectGetLODBias, "ObjectGetLODBias", _SC(".")); + /*# + Func: ObjectSetLODBias + Proto: void:float bias + Desc: Set global object geometry lod bias. + Note: This value is added to the distance used to select the lod level for a geometry before displaying it. + Example: ObjectSetLODBias(Mtr(10.0)) // Push all geometry LODs back by 10 meters. + #*/ + sq_register(vm, ObjectSetLODBias, "ObjectSetLODBias", _SC(".n")); + +/*# + Section: ObjectSkin + Desc: Skin functions +#*/ + /*# + Func: ObjectSkinGetItemCount + Proto: int:Object + Desc: Return the number of bone items in the object skin. + #*/ + sq_register(vm, ObjectSkinGetItemCount, "ObjectSkinGetItemCount", _SC(".x")); + /*# + Func: ObjectSkinGetItem + Proto: Item:Object,int index + Desc: Return a bone item from the object skin. + #*/ + sq_register(vm, ObjectSkinGetItem, "ObjectSkinGetItem", _SC(".xi")); + /*# + Func: ObjectSkinSetItem + Proto: void:Object,int index,Item bone + Desc: Set a bone item in the object skin. + #*/ + sq_register(vm, ObjectSkinSetItem, "ObjectSkinSetItem", _SC(".xix")); + + /*# + Func: ObjectSetSkinMotion + Proto: void:Object,string name + Desc: Set object skin motion. + #*/ + sq_register(vm, ObjectSetSkinMotion, "ObjectSetSkinMotion", _SC(".xs")); + /*# + Func: ObjectSetSkinMotionClockScale + Proto: void:Object,float scale + Desc: Set current object skin motion clock scale. + #*/ + sq_register(vm, ObjectSetSkinMotionClockScale, "ObjectSetSkinMotionClockScale", _SC(".xf")); + /*# + Func: ObjectStopAllSkinMotion + Proto: void:Object + Desc: Stop all object skin motions. + #*/ + sq_register(vm, ObjectStopAllSkinMotion, "ObjectStopAllSkinMotion", _SC(".x")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/peer_network_binding.cpp b/include/modules/script_squirrel/legacy/peer_network_binding.cpp new file mode 100644 index 0000000..eddbaa1 --- /dev/null +++ b/include/modules/script_squirrel/legacy/peer_network_binding.cpp @@ -0,0 +1,222 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "squirrel_binding.h" + #include "script/script_variant.h" + #include "async/async_call_queue_thread.h" + #include "binding_helpers.h" + #include "sqstdblob.h" + + using namespace GS; + using namespace GS::Script; + + +#if __PLATFORM_EMSCRIPTEN__ == 0 + + #include "network_enet/enet_network.h" + +//------------------------------------------------------------------------------ +struct ScriptPeerThread : public Network::Enet, public Threading::ASyncCallQueueThread +{ + void OnIdle() + { UpdateHost(); } + + //---------------------------------------------------------------------- + struct VMThreadData + { + SquirrelVM *vm; + + void OnPeerConnection(void *peer) + { + if (peer && vm->SetupFunctionCall("OnPeerConnection")) + { + vm->PushVariant(Script::Variant(peer, typetag_Peer)); + vm->DoFunctionCall(); + } + } + void OnPacketReceived(void *peer, const Array &packet) + { + if (peer && vm->SetupFunctionCall("OnPacketReceived")) + { + vm->PushVariant(Script::Variant(peer, typetag_Peer)); + vm->PushVariant(Script::Variant((const void *)packet.c_ptr(), packet.GetSize())); + vm->DoFunctionCall(); + } + } + void OnConnectionClosed(void *peer) + { + if (peer && vm->SetupFunctionCall("OnConnectionClosed")) + { + vm->PushVariant(Script::Variant(peer, typetag_Peer)); + vm->DoFunctionCall(); + } + } + + // To be executed from the VM thread. + ASync::CallQueue task_queue; + + VMThreadData(SquirrelVM *v) : vm(v) {} + }; + + VMThreadData vm_thread; + //---------------------------------------------------------------------- + + //---------------------------------------------------------------------- + void OnPeerConnection(void *peer) + { vm_thread.task_queue.QueueMemberCall(&vm_thread, &VMThreadData::OnPeerConnection, peer); } + void OnPacketReceived(void *peer, const void *data, size_t size) + { vm_thread.task_queue.QueueMemberCall(&vm_thread, &VMThreadData::OnPacketReceived, peer, Array (size, (const char *)data)); } + void OnConnectionClosed(void *peer) + { vm_thread.task_queue.QueueMemberCall(&vm_thread, &VMThreadData::OnConnectionClosed, peer); } + //---------------------------------------------------------------------- + + ScriptPeerThread(SquirrelVM *v) : vm_thread(v) {} +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PeerNetOpenServer(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(ip) + __SQ_GETINT(port) + __SQ_GETEND + + ScriptPeerThread *t = new ScriptPeerThread(GetVMObject(vm)); + if (t == NULL) + return sq_throwerror(vm, "Failed to allocate peer network controller."); + + t->Start(); + t->QueueMemberCall(t, &ScriptPeerThread::OpenServer, String(ip), port); + + __SQ_RETURNMANAGEDSAFEPTR(t, typetag_PeerController) +} +SQInteger PeerNetOpenClient(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(ip) + __SQ_GETINT(port) + __SQ_GETEND + + ScriptPeerThread *t = new ScriptPeerThread(GetVMObject(vm)); + if (t == NULL) + return sq_throwerror(vm, "Failed to allocate peer network controller."); + + t->Start(); + t->QueueMemberCall(t, &ScriptPeerThread::OpenClient, String(ip), port); + + __SQ_RETURNMANAGEDSAFEPTR(t, typetag_PeerController) +} +SQInteger PeerNetUpdate(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(t, ScriptPeerThread, typetag_PeerController) + t->vm_thread.task_queue.ExecuteAll(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PeerNetSendString(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(t, ScriptPeerThread, typetag_PeerController) + __SQ_GETSAFEPTR(peer, ENetPeer *, typetag_Peer) + __SQ_GETSTRING(data) + __SQ_GETEND + t->QueueMemberCall(t, &ScriptPeerThread::SendString, peer, String(data)); + __SQ_RETURN +} +SQInteger PeerNetBroadcastString(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(t, ScriptPeerThread, typetag_PeerController) + __SQ_GETSTRING(data) + __SQ_GETEND + t->QueueMemberCall(t, &ScriptPeerThread::BroadcastString, String(data)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +#else + +SQInteger PeerNetOpenServer(HSQUIRRELVM vm) +{ return 0; } +SQInteger PeerNetOpenClient(HSQUIRRELVM vm) +{ return 0; } +SQInteger PeerNetUpdate(HSQUIRRELVM vm) +{ return 0; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PeerNetSendString(HSQUIRRELVM vm) +{ return 0; } +SQInteger PeerNetBroadcastString(HSQUIRRELVM vm) +{ return 0; } + +#endif + +//------------------------------------------------------------------------------ +void RegisterINetBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Peer Network + Desc: Implement a peer-to-peer network. + Type: PeerController +#*/ + +/*# + Section: PeerNetHandshake + Desc: Handshaking +#*/ + /*# + Func: PeerNetOpenServer + Proto: PeerController:String ip,int port + Desc: Open a listening server connection on a given ip address and port. + Note: A server connection is usually opened on the local host ip "127.0.0.1". + Example: +// Start a peer server on the local host on port 8000. +PeerNetOpenServer("127.0.0.1", 8000) + #*/ + sq_register(vm, PeerNetOpenServer, "PeerNetOpenServer", _SC(".si")); + /*# + Func: PeerNetOpenClient + Proto: PeerController:String ip,int port + Desc: Open a client connection to a given ip address and port. + Example: +// Connect client to peer server on the remote address 192.168.0.12 on port 8000. +PeerNetOpenClient("192.168.0.12", 8000) + #*/ + sq_register(vm, PeerNetOpenClient, "PeerNetOpenClient", _SC(".ss")); +/*# + Section: PeerNetCommunication + Desc: Communication +#*/ + /*# + Func: PeerNetSendString + Proto: void:PeerController controller,Peer peer,String data + Desc: Send a string to a specific peer controller. + Example: +// Send the HELLO string to a specific peer. +PeerNetSendString(controller, peer, "HELLO") + #*/ + sq_register(vm, PeerNetSendString, "PeerNetSendString", _SC(".xxs")); + /*# + Func: PeerNetBroadcastString + Proto: void:PeerController controller,String data + Desc: Send a string to all peer controllers connected to this controller. + Example: +// Broadcast the HELLO string to all connected peers. +PeerNetBroadcastString(controller, "HELLO") + #*/ + sq_register(vm, PeerNetBroadcastString, "PeerNetBroadcastString", _SC(".xs")); + /*# + Func: PeerNetUpdate + Proto: void:PeerController controller + Desc: Dispatch all pending network events for a controller to the global handler functions. + #*/ + sq_register(vm, PeerNetUpdate, "PeerNetUpdate", _SC(".x")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/physic_binding.cpp b/include/modules/script_squirrel/legacy/physic_binding.cpp new file mode 100644 index 0000000..aa8b397 --- /dev/null +++ b/include/modules/script_squirrel/legacy/physic_binding.cpp @@ -0,0 +1,448 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "squirrel.h" + #include "binding_helpers.h" + #include "physic/physic_constraint.h" + #include "physic/physic_world.h" + #include "scene3d/mconstraint.h" +#include "scene3d/scene.h" +#include "math/matrix4.h" +#include "math/vector.h" + + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger SceneAddConstraint(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + if (!s->physic_world) + return sq_throwerror(vm, "Cannot create constraint, no physic world in scene."); + MConstraint *c = new MConstraint(s->physic_world->NewConstraint()); + if (!c) + return sq_throwerror(vm, "Failed to allocate constraint."); + c->name = name; + s->AddItem(c, true); + + __SQ_GETEND + __SQ_RETURNSAFEPTR(c, typetag_Constraint) +} +SQInteger SceneAddPointConstraint(HSQUIRRELVM vm) +{ + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + __SQ_GETSAFEPTR(a, MItem, typetag_Item) + __SQ_GETSAFEPTR(b, MItem, typetag_Item) + __SQ_GETVECTOR(pivot_a) + __SQ_GETVECTOR(pivot_b) + + if (!s->physic_world) + return sq_throwerror(vm, "Cannot create constraint, no physic world in scene."); + MConstraint *c = new MConstraint(s->physic_world->NewConstraint()); + if (!c) + return sq_throwerror(vm, "Failed to allocate constraint."); + c->name = name; + s->AddItem(c, true); + + if (!a->physic_item || !b->physic_item) + return sq_throwerror(vm, "Item has no physics component."); + + c->desc.type = PhysicConstraintDesc::TypePoint; + c->desc.item_a = a; + c->desc.item_b = b; + c->desc.pivot_a = GS::Matrix4::TranslationMatrix(pivot_a); + c->desc.pivot_b = GS::Matrix4::TranslationMatrix(pivot_b); + + c->Setup(s->physic_world); + + __SQ_GETEND + __SQ_RETURNSAFEPTR(c, typetag_Constraint) +} +SQInteger SceneAddPointConstraintHinge(HSQUIRRELVM vm) +{ + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + __SQ_GETSAFEPTR(a, MItem, typetag_Item) + __SQ_GETSAFEPTR(b, MItem, typetag_Item) + __SQ_GETVECTOR(pivot_a) + __SQ_GETVECTOR(pivot_b) + + if (!s->physic_world) + return sq_throwerror(vm, "Cannot create constraint, no physic world in scene."); + MConstraint *c = new MConstraint(s->physic_world->NewConstraint()); + if (!c) + return sq_throwerror(vm, "Failed to allocate constraint."); + c->name = name; + s->AddItem(c, true); + + if (!a->physic_item || !b->physic_item) + return sq_throwerror(vm, "Item has no physics component."); + + c->desc.type = PhysicConstraintDesc::TypeHinge; + c->desc.item_a = a; + c->desc.item_b = b; + c->desc.pivot_a = GS::Matrix4::TranslationMatrix(pivot_a); + c->desc.pivot_b = GS::Matrix4::TranslationMatrix(pivot_b); + + c->Setup(s->physic_world); + + __SQ_GETEND + __SQ_RETURNSAFEPTR(c, typetag_Constraint) +} +SQInteger ConstraintEnable(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_GETBOOL(b) + __SQ_GETEND + if (c->physic_data.IsValid()) + c->physic_data->Enable(asbool(b)); + __SQ_RETURN +} +SQInteger ConstraintGetPivotA(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_RETURNVECTOR(c->desc.pivot_a.GetRow(3)) +} +SQInteger ConstraintGetPivotB(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_RETURNVECTOR(c->desc.pivot_b.GetRow(3)) +} +SQInteger ConstraintSetPivotA(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_GETVECTOR(pivot) + __SQ_GETEND + c->desc.pivot_a = GS::Matrix4::TranslationMatrix(pivot); + c->physic_data->SetPivotA(c->desc.pivot_a); + __SQ_RETURN +} +SQInteger ConstraintSetPivotB(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_GETVECTOR(pivot) + __SQ_GETEND + c->desc.pivot_b = GS::Matrix4::TranslationMatrix(pivot); + c->physic_data->SetPivotB(c->desc.pivot_b); + __SQ_RETURN +} +#include "physic_bullet/bullet_constraint.h" +SQInteger ConstraintSetLimit(HSQUIRRELVM vm) +{ + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_GETFLOAT(low) + __SQ_GETFLOAT(high) + __SQ_GETFLOAT(softness) + __SQ_GETFLOAT(biasfactor) + __SQ_GETFLOAT(relaxationFactor) + __SQ_GETEND + ((BulletConstraint*)(c->physic_data.c_ptr()))->setLimitHinge(low, high, softness, biasfactor, relaxationFactor); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ConstraintGetItem(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_RETURNSAFEPTR((MItem *)c, typetag_Item) +} +SQInteger ConstraintSetItemA(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_GETSAFEPTR(i, MItem, typetag_Item) + __SQ_GETEND + c->desc.item_a = i; + __SQ_RETURN +} +SQInteger ConstraintSetItemB(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(c, MConstraint, typetag_Constraint) + __SQ_GETSAFEPTR(i, MItem, typetag_Item) + __SQ_GETEND + c->desc.item_b = i; + __SQ_RETURN +} +//------------------------------------------------------------------------------ +#include "script_squirrel/mmf.h" + +// See TELEMETRY_DATA.flags +#define MMF_CONFIG_EXPLICIT_LOCAL_VEL 1 +#define MMF_CONFIG_EXPLICIT_LOCAL_ACCEL 2 +#define MMF_CONFIG_EXPLICIT_GLOBAL_ACCEL 4 +#define MMF_CONFIG_EXPLICIT_ACCEL_EXCLUDES_GRAVITY 8 + +// See TELEMETRY_DATA.flags +#define CONFIG_EXPLICIT_LOCAL_VEL (1 << 0) +#define CONFIG_EXPLICIT_LOCAL_ACCEL (1 << 1) +#define CONFIG_EXPLICIT_ACCEL_EXCLUDES_GRAVITY (1 << 3) +#define CONFIG_ROW_ORDERED_MATRIX (1 << 4) + +// See TELEMETRY_DATA.axis +#define AXIS_X_UP (1 << 0) +#define AXIS_X_DOWN (1 << 1) +#define AXIS_X_NORTH (1 << 2) +#define AXIS_X_SOUTH (1 << 3) +#define AXIS_X_EAST (1 << 4) +#define AXIS_X_WEST (1 << 5) +#define AXIS_Y_UP (1 << 8) +#define AXIS_Y_DOWN (1 << 9) +#define AXIS_Y_NORTH (1 << 10) +#define AXIS_Y_SOUTH (1 << 11) +#define AXIS_Y_EAST (1 << 12) +#define AXIS_Y_WEST (1 << 13) +#define AXIS_Z_UP (1 << 16) +#define AXIS_Z_DOWN (1 << 17) +#define AXIS_Z_NORTH (1 << 18) +#define AXIS_Z_SOUTH (1 << 19) +#define AXIS_Z_EAST (1 << 20) +#define AXIS_Z_WEST (1 << 21) + + +struct TELEMETRY_DATA +{ + unsigned int flags; + unsigned int axis; + float accel[3]; + float vel[3]; + float rotationMatrix[3][3]; + DWORD packetTimeMillis; +}; +/* +struct SIMPHYNITYMMF +{ +unsigned char flags; +DWORD packetTime; +float telemetryMatrix[16]; +float velocity[3]; +float accel[3]; +};*/ +struct SIMPHYNITYMMF +{ + DWORD packetTime; + float telemetryMatrix[16]; + float globalVelocity[3]; +}; + + +//------------------------------------------------------- +SQInteger CreateMMF(HSQUIRRELVM vm) +//------------------------------------------------------- +{ + __SQ_RETURNSAFEPTR(new CMMF(_T("$SIMPHYNITYTELEM$"), sizeof(TELEMETRY_DATA), _T("$SIMPHYNITYTELEMMUTEX$")), typetag_Item) +// __SQ_RETURNSAFEPTR(new CMMF(_T("$SIMPHYNITYTELEM$"), sizeof(SIMPHYNITYMMF), _T("$SIMPHYNITYTELEMMUTEX$")), typetag_Item) +} +#define __SQ_GETPHYSICITEM(__I__) PhysicItem *iphysic = (__I__)->physic_item.c_ptr(); if (!iphysic) return sq_throwerror(vm, "No physics found, did you setup this item?"); +//------------------------------------------------------- +SQInteger UpdateMMF(HSQUIRRELVM vm) +//------------------------------------------------------- +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(mmf, CMMF, typetag_Item) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETFLOAT(Physic_T) + __SQ_GETEND + + __SQ_GETPHYSICITEM(item) + + GS::Matrix4 item_matrix; + iphysic->GetMatrix(item_matrix); + item_matrix = item->GetBaseItem()->GetMatrix(); + + GS::Vector4 position; + GS::Vector4 scale; + GS::Matrix3 rotation; + item_matrix.Decompose(&position, &scale, &rotation); + +// GS::Vector4 velocity_vec = (item && item->isActive() ? iphysic->GetLinearVelocity() : GS::Vector4(0, 0, 0)); + GS::Vector4 velocity_vec = (item && item->isActive() ? iphysic->GetLinearVelocity() : GS::Vector4(0, 0, 0)); +/* + + SIMPHYNITYMMF m_Telem; + m_Telem.packetTime = Physic_T*1000.0f; // Current physics time. + memcpy(m_Telem.telemetryMatrix, item_matrix.m, sizeof(m_Telem.telemetryMatrix)); // Current rotation, position. + memcpy(m_Telem.globalVelocity, ((float *)&(velocity_vec.x)), sizeof(m_Telem.globalVelocity)); // Global vel XYZ. + mmf->Write(&m_Telem); +*/ + + TELEMETRY_DATA m_Telem; + m_Telem.packetTimeMillis = Physic_T*1000.0f; // Current physics time. + m_Telem.axis = AXIS_X_EAST | AXIS_Y_UP | AXIS_Z_NORTH; + m_Telem.flags = CONFIG_EXPLICIT_LOCAL_VEL | CONFIG_EXPLICIT_ACCEL_EXCLUDES_GRAVITY | CONFIG_ROW_ORDERED_MATRIX; + memcpy(m_Telem.rotationMatrix, rotation.m, sizeof(m_Telem.rotationMatrix)); // Current rotation + memcpy(m_Telem.vel, ((float *)&(velocity_vec.x)), sizeof(m_Telem.vel)); // Global vel XYZ. + m_Telem.accel[0] = 0; m_Telem.accel[1] = 0; m_Telem.accel[2] = 0; + mmf->Write(&m_Telem); + + + __SQ_RETURN +} + + +//-------------------------------------------------------------- +struct ENGINE_TELEMETRY_DATA +{ + char package[32768]; +}; + +SQInteger CreateEngineMMF(HSQUIRRELVM vm) +//------------------------------------------------------- +{ + __SQ_RETURNSAFEPTR(new CMMF(_T("$DevelterInnovationSimulateur$"), sizeof(ENGINE_TELEMETRY_DATA), _T("$DevelterInnovationSimulateurMUTEX$")), typetag_Item) +} +//------------------------------------------------------- +SQInteger UpdateEngineMMF(HSQUIRRELVM vm) +//------------------------------------------------------- +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(mmf, CMMF, typetag_Item) + __SQ_GETSTRING(package) + __SQ_GETEND + + GS::String spackage(package); + + if (spackage.Size() > 32768) + return sq_throwerror(vm, "UpdateEngineMMF: package bigger than 16384 bits."); + + ENGINE_TELEMETRY_DATA m_Telem; + memset(m_Telem.package, 0, 32768); + memcpy(m_Telem.package, spackage.c_str(), spackage.Size()); + mmf->Write(&m_Telem); + + __SQ_RETURN +} +//------------------------------------------------------------------------------ +void RegisterPhysicBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Physic + Type: Constraint + Desc: Physic world functions. For item related physic functions please refer to the Item topic. + Related: Item +#*/ + + /*# + Func: CreateMMF + Proto: MMF:void + Desc: Create mmf object for simu purpose. + #*/ + sq_register(vm, CreateMMF, "CreateMMF", _SC(".")); + /*# + Func: UpdateMMF + Proto: void:MMF, , + Desc: update the mmf with the object rotation and velocity. + #*/ + sq_register(vm, UpdateMMF, "UpdateMMF", _SC(".xxf")); + + /*# + Func: CreateEngineMMF + Proto: MMF:void + Desc: Create mmf object for simu purpose. + #*/ + sq_register(vm, CreateEngineMMF, "CreateEngineMMF", _SC(".")); + /*# + Func: UpdateEngineMMF + Proto: void:MMF + Desc: update the mmf with the json values + #*/ + sq_register(vm, UpdateEngineMMF, "UpdateEngineMMF", _SC(".xs")); +/*# + Section: ConstraintManagement + Desc: Constraint management functions +#*/ + /*# + Func: SceneAddPointConstraint + Proto: Constraint:Scene,string name, Item a,Item b,Vector pivot_a,Vector pivot_b + Desc: Create a new point constraint between two items. The pivot position is in item space. The null item can be set as item B to specify an unmovable world space hook. + #*/ + sq_register(vm, SceneAddPointConstraint, "SceneAddPointConstraint", _SC(".xsxxxx")); + /*# + Func: SceneAddPointConstraintHinge + Proto: Constraint:Scene,string name, Item a,Item b,Vector pivot_a,Vector pivot_b + Desc: Create a new point constraint between two items. The pivot position is in item space. The null item can be set as item B to specify an unmovable world space hook. + #*/ + sq_register(vm, SceneAddPointConstraintHinge, "SceneAddPointConstraintHinge", _SC(".xsxxxx")); + + /*# + Func: ConstraintEnable + Proto: void:Constraint,bool + Desc: Enable/disable constraint. + #*/ + sq_register(vm, ConstraintEnable, "ConstraintEnable", _SC(".xb")); + +/*# + Section: ConstraintConfiguration + Desc: Constraint configuration functions +#*/ + /*# + Func: ConstraintGetPivotA + Proto: Vector:Constraint + Desc: Get the constraint item A pivot vector. + #*/ + sq_register(vm, ConstraintGetPivotA, "ConstraintGetPivotA", _SC(".x")); + /*# + Func: ConstraintGetPivotB + Proto: Vector:Constraint + Desc: Get the constraint item B pivot vector. + #*/ + sq_register(vm, ConstraintGetPivotB, "ConstraintGetPivotB", _SC(".x")); + /*# + Func: ConstraintSetPivotA + Proto: void:Constraint,Vector pivot + Desc: Set the constraint item A pivot vector. + #*/ + sq_register(vm, ConstraintSetPivotA, "ConstraintSetPivotA", _SC(".xx")); + /*# + Func: ConstraintSetPivotB + Proto: void:Constraint,Vector pivot + Desc: Set the constraint item B pivot vector. + #*/ + sq_register(vm, ConstraintSetPivotB, "ConstraintSetPivotB", _SC(".xx")); + /*# + Func: ConstraintSetLimit + Proto: void:Constraint,float low, float high, float softness, float biasfactor, float relaxationfactor + Desc: Set the constraint limit. + #*/ + sq_register(vm, ConstraintSetLimit, "ConstraintSetLimit", _SC(".xfffff")); + + /*# + Func: ConstraintGetItem + Proto: Item:Constraint + Desc: Get constraint item. + #*/ + sq_register(vm, ConstraintGetItem, "ConstraintGetItem", _SC(".x")); + /*# + Func: ConstraintSetItemA + Proto: void:Constraint,Item + Desc: Set constraint item A. + #*/ + sq_register(vm, ConstraintSetItemA, "ConstraintSetItemA", _SC(".xx")); + /*# + Func: ConstraintSetItemB + Proto: void:Constraint,Item + Desc: Set constraint item B. + #*/ + sq_register(vm, ConstraintSetItemB, "ConstraintSetItemB", _SC(".xx")); + + // Push defines. + sq_pushroottable(vm); + + sq_pop(vm, 1); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/picture_binding.cpp b/include/modules/script_squirrel/legacy/picture_binding.cpp new file mode 100644 index 0000000..263941d --- /dev/null +++ b/include/modules/script_squirrel/legacy/picture_binding.cpp @@ -0,0 +1,515 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "ui/ui.h" + #include "font/font_renderer.h" + #include "picture/pict_io.h" + + using namespace GS; + using namespace GS::Script; + + void IterateTextParameters(HSQUIRRELVM vm, int idx, TextState &state); + + +//------------------------------------------------------------------------------ +SQInteger NewPicture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETINT(w) + __SQ_GETINT(h) + __SQ_GETEND + Picture *p = new Picture; + if (!p || !p->AllocAs(w, h)) + return sq_throwerror(vm, String::Format("Failed to allocate a new %dx%d picture.", w, h)); + __SQ_RETURNSAFEPTR(p, typetag_Picture) +} +SQInteger LoadPicture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(path) + Picture *p = new Picture; + if (!p) + return sq_throwerror(vm, "Failed to allocate picture."); + if (!PictureIO::Get().Load(*p, path)) + return sq_throwerror(vm, String::Format("Failed to load picture '%s'.", path)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(p, typetag_Picture) +} +SQInteger PictureClone(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(p, Picture, typetag_Picture) + __SQ_RETURNSAFEPTR(new Picture(*p), typetag_Picture); +} +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------- +SQInteger PictureWriteText(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETRECT(out_rect) + __SQ_GETSTRING(text) + __SQ_GETSAFEPTR(font, FontEx, typetag_Font) + + TextState state; + IterateTextParameters(vm, -1, state); + __SQ_GETUPDATESTACK + + state.font = font; + + iRect clip_rect = p->GetRect(); + FontRenderer::Format(text, state, out_rect); + FontRenderer::Compose(*p, text, state, out_rect, clip_rect); + + __SQ_GETEND + __SQ_RETURN +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +SQInteger PictureApplyConvolution(HSQUIRRELVM vm) +{ + Picture *pic; + if (!CObject::Get(vm, -6, (void **)&pic, typetag_Picture)) + return -1; + if (!pic) + return sq_throwerror(vm, "Invalid picture."); + + // Kernel size. + SQInteger kw, kh; + sq_getinteger(vm, -5, &kw); + sq_getinteger(vm, -4, &kh); + + int kernel[1024]; + if ((kw * kh) > 1024) + return sq_throwerror(vm, "The convolution kernel is exceeding 1024 entries."); + + sq_pushnull(vm); // iterator + for (int n = 0; n < (kw * kh); ++n) + { + if (SQ_FAILED(sq_next(vm, -4))) + break; + + // Here -1 is the value and -2 is the key. + SQInteger v; + sq_getinteger(vm, -1, &v); + kernel[n] = v; + sq_pop(vm, 2); // Pops key and val before the next iteration. + } + sq_pop(vm, 1); // Pop the iterator. + + SQFloat weight; + sq_getfloat(vm, -2, &weight); + SQInteger pass; + sq_getinteger(vm, -1, &pass); + + sq_pop(vm, 4); // Pop function arguments. + + if (!pic->ApplyConvolution(kw, kh, kernel, int(weight * 256), pass)) + return sq_throwerror(vm, "Convolution filter failed."); + + return 0; +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +SQInteger PictureLine(HSQUIRRELVM vm) +{ + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(pic, Picture, typetag_Picture) + __SQ_GETFLOAT(sx) + __SQ_GETFLOAT(sy) + __SQ_GETFLOAT(ex) + __SQ_GETFLOAT(ey) + __SQ_GETVECTORW(c) + __SQ_GETEND + + fRect rect = pic->GetRect().AsFloat(); + rect.ex -= 2; rect.ey -= 2; + if ((rect.ex <= rect.sx) || (rect.ey < rect.sy)) + return 0; + pic->DrawLineHQ(sx, sy, ex, ey, c.x, c.y, c.z, c.w, &rect); + return 0; +} +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +SQInteger PictureLoadContent(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(pic, Picture, typetag_Picture) + __SQ_GETSTRING(path) + bool r = PictureIO::Get().Load(*pic, path); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger PictureSaveTGA(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETSTRING(path) + if (!PictureIO::Get().TgaSave(*p, path)) + return sq_throwerror(vm, String::Format("Failed to save picture to '%s'", path)); + __SQ_GETEND + __SQ_RETURN +} +SQInteger PictureSaveJPG(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETSTRING(path) + p->Convert(PixelFormat::RGB8); + if (!PictureIO::Get().Save(*p, path, "IJG")) + return sq_throwerror(vm, String::Format("Failed to save picture to '%s'", path)); + __SQ_GETEND + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PictureGetRect(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(p, Picture, typetag_Picture) + iRect rect(0, 0, 0, 0); + if (p) rect.Set(0, 0, p->GetWidth(), p->GetHeight()); + __SQ_RETURNRECT(rect) +} +SQInteger PictureAlloc(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETINT(w) + __SQ_GETINT(h) + __SQ_GETEND + if (!p->AllocAs(w, h)) + return sq_throwerror(vm, "Failed to allocate picture buffer"); + __SQ_RETURN +} +SQInteger PictureResize(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETINT(w) + __SQ_GETINT(h) + __SQ_GETEND + p->Resize(w, h); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PictureSetPixel(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETVECTORW(c) + __SQ_GETEND + p->DrawPlot(x, y, c.x, c.y, c.z, c.w); + __SQ_RETURN +} +SQInteger PictureGetPixel(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + Color c; + p->Sample(x / p->GetWidth(), y / p->GetHeight(), c); + __SQ_RETURNVECTORW(Vector4(c.x, c.y, c.z, c.w)) +} +SQInteger PictureFlip(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETBOOL(h) + __SQ_GETBOOL(v) + __SQ_GETEND + p->Flip(asbool(h), asbool(v)); + __SQ_RETURN +} +SQInteger PictureFillLockAlpha(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETVECTORW(c) + __SQ_GETEND + p->Fill(c.x, c.y, c.z, c.w, 0, true); + __SQ_RETURN +} +SQInteger PictureFill(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETVECTORW(c) + __SQ_GETEND + p->Fill(c.x, c.y, c.z, c.w); + __SQ_RETURN +} +SQInteger PictureFillRect(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETVECTORW(c) + __SQ_GETRECT(clip_rect) + __SQ_GETEND + p->Fill(c.x, c.y, c.z, c.w, &clip_rect); + __SQ_RETURN +} +SQInteger PictureBlitRect(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(src, Picture, typetag_Picture) + __SQ_GETSAFEPTR(dst, Picture, typetag_Picture) + __SQ_GETRECT(src_rect) + __SQ_GETRECT(dst_rect) + __SQ_GETINT(blend_mode) + __SQ_GETEND + Picture::Blit(*src, *dst, &src_rect, &dst_rect, (Picture::BlendMode)blend_mode); + __SQ_RETURN +} +SQInteger PictureBlitRectMasked(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(src, Picture, typetag_Picture) + __SQ_GETSAFEPTR(dst, Picture, typetag_Picture) + __SQ_GETSAFEPTR(msk, Picture, typetag_Picture) + __SQ_GETRECT(src_rect) + __SQ_GETRECT(dst_rect) + __SQ_GETEND + Picture::BlitMask(*src, *dst, *msk, &src_rect, &dst_rect); + __SQ_RETURN +} +SQInteger PictureBlit(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(src, Picture, typetag_Picture) + __SQ_GETSAFEPTR(dst, Picture, typetag_Picture) + __SQ_GETINT(blend_mode) + __SQ_GETEND + Picture::Blit(*src, *dst, 0, 0, (Picture::BlendMode)blend_mode); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//-------------------------------------------------------- +void RegisterPictureBinding(HSQUIRRELVM vm) +//-------------------------------------------------------- +{ +/*# + Topic: Picture + Type: Picture +#*/ + +/*# + Section: PictureManagement + Desc: Management +#*/ + /*# + Func: NewPicture + Proto: Picture:int width,int height + Desc: Create a new picture, width and height are specified in pixels. + Example: local picture = NewPicture() + #*/ + sq_register(vm, NewPicture, "NewPicture", _SC(".nn")); + /*# + Func: LoadPicture + Proto: Picture:string path + Desc: Load a picture. This function supports the following formats: Jpeg, Bmp, Targa, Png, Gif and PSD with alpha channel. + Note: No caching mechanism involved, every call to this function will result in a filesystem access. + Example: local picture = LoadPicture("assets/picture.png") + #*/ + sq_register(vm, LoadPicture, "LoadPicture", _SC(".s")); + /*# + Func: PictureClone + Proto: Picture:Picture source + Desc: Clone a picture, return the cloned picture. + #*/ + sq_register(vm, PictureClone, "PictureClone", _SC(".x")); + +/*# + Section: PictureDrawing + Desc: Drawing +#*/ + /*# + Func: PictureAlloc + Proto: bool:Picture,width,height + Desc: Change the picture internal storage dimensions, existing data will be lost. + #*/ + sq_register(vm, PictureAlloc, "PictureAlloc", _SC(".xnn")); + /*# + Func: PictureLoadContent + Proto: bool:Picture,string path + Desc: Reload a picture object content from file. + See: LoadPicture + #*/ + sq_register(vm, PictureLoadContent, "PictureLoadContent", _SC(".xs")); + /*# + Func: PictureSaveTGA + Proto: void:Picture,string path + Desc: Save a picture object to Targa. + Note: Make sure that you have access to the filesystem you plan on writing to. + See: SystemHasMountPoint + #*/ + sq_register(vm, PictureSaveTGA, "PictureSaveTGA", _SC(".xs")); + /*# + Func: PictureSaveJPG + Proto: void:Picture,string path + Desc: Save a picture object to jpg. + Note: Make sure that you have access to the filesystem you plan on writing to. + See: SystemHasMountPoint + #*/ + sq_register(vm, PictureSaveJPG, "PictureSaveJPG", _SC(".xs")); + /*# + Func: PictureGetRect + Proto: Rect:Picture + Desc: Return a picture bounding rectangle. + Example: +local pict = PictureLoad("picture.psd") +local rect = PictureGetRect(pict) + +print("Picture width = " + rect.GetWidth() + ", height = " + rect.GetHeight()) + #*/ + sq_register(vm, PictureGetRect, "PictureGetRect", _SC(".x")); + /*# + Func: PictureFill + Proto: void:Picture,Vector rgba + Desc: Fill a picture with a solid color defined as an RGBA vector. + #*/ + sq_register(vm, PictureFill, "PictureFill", _SC(".xx")); + /*# + Func: PictureFillLockAlpha + Proto: void:Picture,Vector rgba + Desc: Fill a picture with a solid color defined from an RGBA vector, does not write to alpha. + #*/ + sq_register(vm, PictureFillLockAlpha, "PictureFillLockAlpha", _SC(".xx")); + /*# + Func: PictureFillRect + Proto: void:Picture,Vector rgba,Rect + Desc: Fill a rectangle inside a picture with a solid color defined from an RGBA vector. + #*/ + sq_register(vm, PictureFillRect, "PictureFillRect", _SC(".xxx")); + /*# + Func: PictureApplyConvolution + Proto: void:Picture,int kernel_width,int kernel_height,array kernel_values,float filter_weight,int pass_count + Desc: Apply a convolution filter to the picture using a user specified kernel of values.
+
+ The weight and pass parameters will be 1 in most use case, + kernel values are integer in the nominal range [0;255]. + Example: +function BlurPicture(picture, blur_strength = 1, blur_pass_count = 1) +{ + local kernel = // 7x7 kernel + [ + 0, 1, 2, 4, 2, 1, 0, + 1, 2, 4, 6, 4, 2, 1, + 2, 3, 5, 8, 5, 3, 2, + 2, 4, 8, 8, 8, 4, 2, + 2, 3, 5, 8, 5, 3, 2, + 1, 2, 4, 6, 4, 2, 1, + 0, 1, 2, 4, 2, 1, 0 + ] + PictureApplyConvolution(picture, 7, 7, kernel, blur_strength, blur_pass_count) +} + #*/ + sq_register(vm, PictureApplyConvolution, "PictureApplyConvolution", _SC(".xiiani")); + /*# + Func: PictureLine + Proto: bool:Texture,float start_x,float start_y,float end_x,float end_y,Vector rgba + Desc: Draw a line, color is specified as an RGBA vector. + #*/ + sq_register(vm, PictureLine, "PictureLine", _SC(".xnnnnx")); + /*# + Func: PictureWriteFont + Proto: void:Picture,rect,string text,Font font,TextState + Desc: Render formatted text to a picture.
+ TextState is table containing the following keys:
+
    +
  • 'size': Size in pixels. +
  • 'color': Hexadecimal RGBA (eg. 0xff0000ff for red at 100% opacity). +
  • 'align': Text alignment, can be any of "left", "center", "right" or "justify". +
  • 'format': Text formating, can be any of "standard", "paragraph" or "column". +
  • 'tracking': Integer value specifying an extra space between glyphs. +
  • 'heading': Integer value specifying an extra space between lines. +
+ #*/ + sq_register(vm, PictureWriteText, "PictureWriteFont", _SC(".xxsxt")); + sq_register(vm, PictureWriteText, "PictureWriteText", _SC(".xxsxt")); + /*# + Func: PictureSetPixel + Proto: void:Picture,float x,float y,Vector rgba + Desc: Set picture pixel at coordinate {x, y} in picture space from an RGBA vector. + #*/ + sq_register(vm, PictureSetPixel, "PictureSetPixel", _SC(".xnnx")); + /*# + Func: PictureGetPixel + Proto: Vector:Picture,float x,float y + Desc: Return the picture pixel at coordinate {x, y} in picture space as an RGBA vector. + #*/ + sq_register(vm, PictureGetPixel, "PictureGetPixel", _SC(".xnn")); + +/*# + Section: PictureManipulation + Desc: Manipulation +#*/ + /*# + Func: PictureResize + Proto: void:Picture,float w,float h + Desc: Resize picture. + #*/ + sq_register(vm, PictureResize, "PictureResize", _SC(".xii")); + /*# + Func: PictureFlip + Proto: void:Picture,bool horizontal, bool vertical + Desc: Flip picture on one or both axis. + #*/ + sq_register(vm, PictureFlip, "PictureFlip", _SC(".xbb")); + +/*# + Section: PictureBlitting + Desc: Blitting +#*/ + /*# + Func: PictureBlit + Proto: void:Picture source,Picture destination,BlendMode mode + Desc: Blit a picture to another picture with a selectable blend mode. + #*/ + sq_register(vm, PictureBlit, "PictureBlit", _SC(".xxi")); + /*# + Func: PictureBlitRect + Proto: void:Picture source,Picture destination,Rect source,Rect destination,BlendMode mode + Desc: Blit a picture to another picture, both clipping zones and the blend mode can be specified. + #*/ + sq_register(vm, PictureBlitRect, "PictureBlitRect", _SC(".xxxxi")); + /*# + Func: PictureBlitRectMasked + Proto: void:Picture source,Picture destination,Picture mask,Rect source,Rect destination + Desc: Blit a picture to another picture using a third picture alpha channel as an opacity mask. + #*/ + sq_register(vm, PictureBlitRectMasked, "PictureBlitRectMasked", _SC(".xxxxx")); + + sq_pushroottable(vm); + + /*# + Enum: BlendMode + Values: BlendReplace,BlendAdd,BlendCompose,BlendComposeFast,BlendMultiply,BlendMultiply2x,BlendAlphaAdd,BlendAlphaMultiply,BlendAlphaMultiply2x,RgbToAlpha + #*/ + sq_pushstring(vm, "BlendReplace", -1); sq_pushinteger(vm, Picture::BlendReplace); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendAdd", -1); sq_pushinteger(vm, Picture::BlendAdd); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendCompose", -1); sq_pushinteger(vm, Picture::BlendCompose); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendComposeFast", -1); sq_pushinteger(vm, Picture::BlendComposeFast); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendMultiply", -1); sq_pushinteger(vm, Picture::BlendMultiply); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendMultiply2x", -1); sq_pushinteger(vm, Picture::BlendMultiply2x); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendAlphaAdd", -1); sq_pushinteger(vm, Picture::BlendAlphaAdd); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendAlphaMultiply", -1); sq_pushinteger(vm, Picture::BlendAlphaMultiply); sq_newslot(vm, -3, true); + sq_pushstring(vm, "BlendAlphaMultiply2x", -1); sq_pushinteger(vm, Picture::BlendAlphaMultiply2x); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RgbToAlpha", -1); sq_pushinteger(vm, Picture::RgbToAlpha); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/platform_binding.cpp b/include/modules/script_squirrel/legacy/platform_binding.cpp new file mode 100644 index 0000000..949552d --- /dev/null +++ b/include/modules/script_squirrel/legacy/platform_binding.cpp @@ -0,0 +1,262 @@ +/* ----------------------------------------------------------------------------- + nEngine - GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "squirrel.h" + #include "script_squirrel/legacy/binding_helpers.h" + #include "licensing/licensing.h" + #include "analytics/analytics.h" + #include "billing/billing.h" + #include "locale/country.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +SQInteger PlatformAnalyticsLogEvent(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(name) + if (Platform::Get().analytics.IsValid()) + Platform::Get().analytics->logEvent(name); + __SQ_GETEND + __SQ_RETURN +} +SQInteger PlatformAnalyticsServeFullscreenAd(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(location) + if (Platform::Get().analytics.IsValid()) + Platform::Get().analytics->serveFullscreenAd(location); + __SQ_GETEND + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PlatformBillingConfirmEvent(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(id) + if (Platform::Get().billing.IsNull()) + return sq_throwerror(vm, "No billing system on this platform."); + Platform::Get().billing->confirmPurchase(id); + __SQ_GETEND + __SQ_RETURN +} +SQInteger PlatformBillingRestorePurchases(HSQUIRRELVM vm) +{ + if (Platform::Get().billing.IsNull()) + return sq_throwerror(vm, "No billing system on this platform."); + Platform::Get().billing->restorePurchases(); + __SQ_RETURN +} +SQInteger PlatformBillingRequestPurchase(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(id) + if (Platform::Get().billing.IsNull()) + return sq_throwerror(vm, "No billing system on this platform."); + Platform::Get().billing->requestPurchase(id); + __SQ_GETEND + __SQ_RETURN +} +SQInteger PlatformBillingIsSupported(HSQUIRRELVM vm) +{ __SQ_RETURNBOOL(Platform::Get().billing.IsValid()) } +SQInteger PlatformGetLocale(HSQUIRRELVM vm) +{ __SQ_RETURNSTRING(Platform::Get().GetLocale()) } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PlatformLicensingIsSupported(HSQUIRRELVM vm) +{ + __SQ_RETURNBOOL(Platform::Get().licensing.IsValid()) +} +SQInteger PlatformLicensingCheck(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(id) + if (Platform::Get().licensing.IsNull()) + return sq_throwerror(vm, "No licensing system on this platform."); + Platform::Get().licensing->updateLicence(id); + __SQ_GETEND + __SQ_RETURNBOOL(true) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PlatformGetName(HSQUIRRELVM vm) +{ __SQ_RETURNSTRING(Platform::Get().GetName()) } +SQInteger PlatformGetDeviceName(HSQUIRRELVM vm) +{ __SQ_RETURNSTRING(Platform::Get().GetDeviceName()) } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PlatformOpenURL(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(url) + bool r = Platform::Get().OpenURL(url); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger PlatformSendToBackground(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETBOOL(kill) + __SQ_GETEND + __SQ_RETURNBOOL(Platform::Get().SendToBackground(asbool(kill))) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PlatformGetUserPath(HSQUIRRELVM vm) +{ + String path; + if (!Platform::Get().GetUserDir(path)) + return sq_throwerror(vm, "Failed to get user path."); + __SQ_RETURNSTRING(path) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger PlatformOpenAppPage(HSQUIRRELVM vm) +{ + Platform::Get().OpenAppPage(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterPlatformBinding(HSQUIRRELVM vm) +{ + using namespace GS::Script; + +/*# + Section: SystemMisc + Desc: Miscellaneous +#*/ + /*# + Func: PlatformOpenURL + Proto: bool:String id + Desc: Open an URL using the platform browser if available. + #*/ + sq_register(vm, PlatformOpenURL, "PlatformOpenURL", _SC(".s")); + /*# + Func: PlatformSendToBackground + Proto: bool:bool kill + Desc: Send the current application to background, optionally try to kill it. + #*/ + sq_register(vm, PlatformSendToBackground, "PlatformSendToBackground", _SC(".b")); + + /*# + Func: PlatformGetUserPath + Proto: String: + Desc: Return the current user path. + #*/ + sq_register(vm, PlatformGetUserPath, "PlatformGetUserPath", _SC(".")); + +/*# + Section: SystemVisibility + Desc: Platform visibility +#*/ + /*# + Func: PlatformOpenAppPage + Proto: void: + Desc: Open the platform specific application page, use this to send the user to your rating page. + #*/ + sq_register(vm, PlatformOpenAppPage, "PlatformOpenAppPage", _SC(".")); + +/*# + Section: SystemLicensing + Desc: Licensing +#*/ + /*# + Func: PlatformLicensingCheck + Proto: void:String license_info + Desc: Launch an asynchronous licensing request, the result will be sent to your script global 'OnLicensingEvent(String event)' function. + #*/ + sq_register(vm, PlatformLicensingCheck, "PlatformLicensingCheck", _SC(".s")); + /*# + Func: PlatformLicensingIsSupported + Proto: bool: + Desc: Returns true if the current platform supports app license verification. + #*/ + sq_register(vm, PlatformLicensingIsSupported, "PlatformLicensingIsSupported", _SC(".")); + +/*# + Section: SystemBilling + Desc: In-app billing +#*/ + /*# + Func: PlatformBillingConfirmEvent + Proto: void:String id + Desc: Confirm a billing event (like a purchase or a refund). + #*/ + sq_register(vm, PlatformBillingConfirmEvent, "PlatformBillingConfirmEvent", _SC(".s")); + /*# + Func: PlatformBillingRestorePurchases + Proto: void: + Desc: Restore all managed purchases. The billing event callback will be called for each purchase ever made by the current user with the event string "Restored". + #*/ + sq_register(vm, PlatformBillingRestorePurchases, "PlatformBillingRestorePurchases", _SC(".")); + /*# + Func: PlatformBillingRequestPurchase + Proto: void:String id + Desc: Launch a purchase intent for the specified virtual good identifier. Returns true of the intent was successfully launched. Results will be transmitted to you through the global 'OnBillingEvent(String event, String item)' script callback. + #*/ + sq_register(vm, PlatformBillingRequestPurchase, "PlatformBillingRequestPurchase", _SC(".s")); + /*# + Func: PlatformBillingIsSupported + Proto: bool: + Desc: Returns true if the current platform supports in-app billing (in-app purchase). + #*/ + sq_register(vm, PlatformBillingIsSupported, "PlatformBillingIsSupported", _SC(".")); + /*# + Func: PlatformGetLocale + Proto: String: + Desc: Return the current platform locale ISO2 code string (ISO 3166 two-character alphabetic code). + #*/ + sq_register(vm, PlatformGetLocale, "PlatformGetLocale", _SC(".")); + +/*# + Section: SystemAnalytics + Desc: Analytics +#*/ + /*# + Func: PlatformAnalyticsLogEvent + Proto: void:String name + Desc: Log a named analytics event. + #*/ + sq_register(vm, PlatformAnalyticsLogEvent, "PlatformAnalyticsLogEvent", _SC(".s")); + /*# + Func: PlatformAnalyticsServeFullscreenAd + Proto: void:String location + Desc: Serve a fullscreen ad, the location string is used as a marker to track the location of the display. + #*/ + sq_register(vm, PlatformAnalyticsServeFullscreenAd, "PlatformAnalyticsServeFullscreenAd", _SC(".s")); + +/*# + Section: SystemHardware + Desc: Host device +#*/ + /*# + Func: PlatformGetName + Proto: String: + Desc: Return the platform name (eg. "Win32", "iOS", "Android", ...). + Note: A platform may run on several devices. +fd See: PlatformGetDeviceName + #*/ + sq_register(vm, PlatformGetDeviceName, "PlatformGetDeviceName", _SC(".")); + /*# + Func: PlatformGetDeviceName + Proto: String: + Desc: Return the device name the platform is currently running on (eg. "iPad", "iPhone"). + #*/ + sq_register(vm, PlatformGetDeviceName, "PlatformGetDeviceName", _SC(".")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/profiler_binding.cpp b/include/modules/script_squirrel/legacy/profiler_binding.cpp new file mode 100644 index 0000000..4ab493a --- /dev/null +++ b/include/modules/script_squirrel/legacy/profiler_binding.cpp @@ -0,0 +1,241 @@ +/* ----------------------------------------------------------------------------- + GSFramework + 2023 Emmanuel Julien +----------------------------------------------------------------------------- */ + +#include "binding_helpers.h" + +#include +#include +#include +#include +#include +#include +#include + +struct CallId { + SQUserPointer caller; // caller funcid, 0 means native call + SQUserPointer funcid; +}; + +typedef uint64_t time_ns; + +static time_ns get_clock() { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); +} + +typedef uint32_t CallIdx; + +struct Call { + CallId id; + time_ns start; + time_ns total{0}; + uint32_t hit{0}; // number of time this call was performed + std::vector child_calls; // [EJ] this is wasteful and inefficient +}; + +struct FuncInfo { + std::string name; + std::string source; +}; + +struct VMProfile { + std::map func_info; + + std::vector all_calls; + CallIdx call_count{0}; + + std::vector root_calls; + std::vector callstack; // current callstack +}; + +static std::map vm_profiles; + +static CallIdx find_call(std::vector &all_calls, std::vector &calls, CallId call_id) { + for (CallIdx i : calls) { + const Call &call = all_calls[i]; + if (call.id.caller == call_id.caller && call.id.funcid == call_id.funcid) { + return i; + } + } + return 0; +} + +struct CallProfile { + uint32_t hit; // number of calls + time_ns total; // duration of all calls + time_ns child; // duration of all child calls +}; + +static CallProfile get_call_profile(const std::vector &all_calls, const Call &call) { + CallProfile profile; + profile.hit = call.hit; + profile.total = call.total; + profile.child = 0; + + for (const CallIdx i : call.child_calls) { + profile.child += all_calls[i].total; + } + + return profile; +} + +static CallProfile get_calls_profile(const std::vector &all_calls, const std::vector &idxs) { + CallProfile profile; + profile.hit = 0; + profile.total = 0; + profile.child = 0; + + for (const auto idx : idxs) { + const CallProfile call_profile = get_call_profile(all_calls, all_calls[idx]); + profile.hit += call_profile.hit; + profile.total += call_profile.total; + profile.child += call_profile.child; + } + + return profile; +} + +static void native_hook(HSQUIRRELVM vm, SQInteger event_type, const SQChar *sourcename, SQInteger line, const SQChar *funcname) { + VMProfile &profile = vm_profiles[vm]; + + const time_ns time = get_clock(); + + if (event_type == 'l') { // line execution + // TODO reimplement if ever needed + } else if (event_type == 'c') { // function call + SQFunctionInfo fi; + sq_getfunctioninfo(vm, 0, &fi); + + if (profile.func_info.find(fi.funcid) == std::end(profile.func_info)) { + FuncInfo &info = profile.func_info[fi.funcid]; + info.name = fi.name; + info.source = fi.source; + } + + // + CallId call_id = {nullptr, fi.funcid}; + + std::vector *child_calls = &profile.root_calls; + + if (!profile.callstack.empty()) { + Call &call = profile.all_calls[profile.callstack.back()]; + + call_id.caller = call.id.funcid; + child_calls = &call.child_calls; + } + + // + CallIdx i = find_call(profile.all_calls, *child_calls, call_id); + + if (i == 0) { + i = ++profile.call_count; + child_calls->push_back(i); + + profile.all_calls.resize(profile.call_count + 1); // allocate call object + } + + Call &call = profile.all_calls[i]; + call.id = call_id; + call.start = time; + ++call.hit; + + profile.callstack.push_back(i); + } else if (event_type == 'r') { // returning from a function + if (!profile.callstack.empty()) { + Call &call = profile.all_calls[profile.callstack.back()]; + + const time_ns duration = time - call.start; + call.total += duration; + + profile.callstack.pop_back(); + } + } +} + +// +bool save_profile(HSQUIRRELVM vm, const char *path) { + const auto i = vm_profiles.find(vm); + + if (i == std::end(vm_profiles)) { + return false; + } + + const VMProfile &profile = i->second; + + // build a set of all functions (source + name) called during the profile + // note: funcid is not unique in GS, probably because all scripts use a custom context in which the script is reloaded + std::set ids; + + for (const auto &i : profile.func_info) { + ids.insert(i.second.source + ":" + i.second.name); + } + + // compute timings for each function + std::map func_profiles; + + for (const auto &id : ids) { + std::vector idxs; + + for (size_t i = 1; i < profile.all_calls.size(); ++i) { + const Call &call = profile.all_calls[i]; + + const FuncInfo &info = profile.func_info.find(call.id.funcid)->second; + if (id == info.source + ":" + info.name) { + idxs.push_back(i); + } + } + + func_profiles[id] = get_calls_profile(profile.all_calls, idxs); + } + + // output to CSV + std::ofstream csv(path); + csv << "function,total,children,self,hit,ntotal,nself" << std::endl; + + for (const auto &i : func_profiles) { + csv << i.first << ","; + + const CallProfile &call_profile = i.second; + + const time_ns self = call_profile.total - call_profile.child; + + csv << call_profile.total << ","; + csv << call_profile.child << ","; + csv << self << ","; + csv << call_profile.hit << ","; + csv << call_profile.total / call_profile.hit << ","; + csv << self / call_profile.hit; + + csv << std::endl; + } + + return true; +} + +// +SQInteger StartProfiler(HSQUIRRELVM vm) { + sq_setnativedebughook(vm, native_hook); + return 0; +} + +SQInteger SaveProfile(HSQUIRRELVM vm) { + __SQ_GETSTART(1) + __SQ_GETSTRING(path) + const bool res = save_profile(vm, path); + __SQ_GETEND + __SQ_RETURNBOOL(res) +} + +SQInteger StopProfiler(HSQUIRRELVM vm) { + sq_setnativedebughook(vm, nullptr); + vm_profiles.clear(); + return 0; +} + +// +void RegisterProfilerBinding(HSQUIRRELVM vm) { + GS::Script::sq_register(vm, StartProfiler, "StartProfiler", _SC(".")); + GS::Script::sq_register(vm, SaveProfile, "SaveProfile", _SC(".s")); + GS::Script::sq_register(vm, StopProfiler, "StopProfiler", _SC(".")); +} diff --git a/include/modules/script_squirrel/legacy/project_binding.cpp b/include/modules/script_squirrel/legacy/project_binding.cpp new file mode 100644 index 0000000..3f5519b --- /dev/null +++ b/include/modules/script_squirrel/legacy/project_binding.cpp @@ -0,0 +1,493 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/legacy/binding_helpers.h" + #include "project/project.h" + #include "scene3d/scene.h" + #include "ui/ui_camera.h" + #include "ui/ui.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger ProjectGetClock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(project, Project, typetag_Project) + __SQ_RETURNSAFEPTR(project->clock.c_ptr(), typetag_Clock) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectSetAll2DLayerOffset(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + + ListForeachPtr(ProjectLayer *, layer, project->layer_list) + if (layer->inst) + if (S2D::Scene *scene = layer->inst->instance_2d) + { + scene->offset_matrix = Matrix3::IdentityMatrix(); + scene->offset_matrix.m[0][2] = x / scene->GetCurrentCamera()->resolution.x; + scene->offset_matrix.m[1][2] = y / scene->GetCurrentCamera()->resolution.y; + } + + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectLayerGetScene(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(layer, ProjectLayer, typetag_ProjectLayer) + if (!layer->inst) + return sq_throwerror(vm, "No scene in project layer"); + __SQ_RETURNSAFEPTR(layer->inst, typetag_ProjectScene) +} +SQInteger ProjectLayerSetZOrder(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(layer, ProjectLayer, typetag_ProjectLayer) + __SQ_GETFLOAT(zorder) + __SQ_GETEND + layer->zorder = zorder; + __SQ_RETURN +} +SQInteger ProjectLayerGetZOrder(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(layer, ProjectLayer, typetag_ProjectLayer) + __SQ_RETURNFLOAT(layer->zorder) +} +SQInteger ProjectAddLayer(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSAFEPTR(instance, ProjectSceneInstance, typetag_ProjectScene) + __SQ_GETFLOAT(zorder) + __SQ_GETEND + __SQ_RETURNSAFEPTR(project->AddLayer(instance, zorder), typetag_ProjectLayer) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectNewScene3D(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(project, Project, typetag_Project) + __SQ_RETURNMANAGEDSAFEPTR(project->Instantiate(new S3D::Scene(project->vm)), typetag_ProjectScene) +} +SQInteger ProjectNewScene2D(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(project, Project, typetag_Project) + __SQ_RETURNMANAGEDSAFEPTR(project->Instantiate(new S2D::Scene(project->vm)), typetag_ProjectScene) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectGetSceneLayerList(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene) + __SQ_GETEND + + sq_newarray(vm, 0); + for (uint n = 0; n < project->layer_list.GetCount(); ++n) + { + ProjectLayer *layer = project->layer_list[n]; + if (layer->inst == scene) + { + CObject::Push(vm, (void *)layer, typetag_ProjectLayer); + sq_arrayappend(vm, -2); + } + } + return 1; +} +SQInteger ProjectInstantiateScene(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSTRING(path) + sq_collectgarbage(vm); + ProjectSceneInstance *project_scene = project->Instantiate(path); + __SQ_GETEND + __SQ_RETURNSAFEPTR(project_scene, typetag_ProjectScene) +} +SQInteger ProjectSceneIsActive(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene) + __SQ_GETEND + __SQ_RETURNBOOL(project && scene ? project->IsActive(*scene) : false) +} +SQInteger ProjectSceneActivate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene) + __SQ_GETBOOL(active) + __SQ_GETEND + project->Activate(*scene, active ? true : false); + __SQ_RETURN +} +SQInteger ProjectUnloadScene(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene) + __SQ_GETEND + project->Delete(scene); + __SQ_RETURN +} +SQInteger ProjectFindScene(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSTRING(path) + ProjectSceneInstance *inst = project->FindSceneInstance(path); + __SQ_GETEND + __SQ_RETURNSAFEPTR(inst, typetag_ProjectScene) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectSceneGetType(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene) + __SQ_RETURNINT(scene->GetType()) +} +SQInteger ProjectSceneGetInstance(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene) + + switch (scene->GetType()) + { + case ProjectSceneInstance::Type_Scene2d: + __SQ_RETURNSAFEPTR(scene->instance_2d, typetag_Scene2d) + case ProjectSceneInstance::Type_Scene3d: + __SQ_RETURNSAFEPTR(scene->instance_3d, typetag_Scene3d) + + default: break; + } + return sq_throwerror(vm, "Invalid project scene"); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectGetFileName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(project, Project, typetag_Project) + __SQ_RETURNSTRING(project->name.CutFilePath().toUtf8()) +} +SQInteger ProjectGetFilePath(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(project, Project, typetag_Project) + __SQ_RETURNSTRING(project->name.CutFileName().toUtf8()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectSceneSetGlobal(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene) + if (scene && (scene->GetType() == ProjectSceneInstance::Type_Scene3d)) + scene->instance_3d->SetAsScriptGlobalScene(); + __SQ_RETURN +} +SQInteger ProjectGetScriptInstance(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(project, Project, typetag_Project) + if (!project) + return sq_suspendvm(vm); + if (!project->script_unit->Self()) + return sq_throwerror(vm, "No script assigned to this project."); + __SQ_RETURNOBJECT(((Script::SquirrelObject *)project->script_unit->Self())->object); +} +SQInteger ProjectEnd(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(project, Project, typetag_Project) + if (project) + project->flags.Set(Project::ProjectFlagEnd); +// exit(0); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ProjectLoadFont(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSTRING(path) + FontEx *font = project->font_cache->LoadFont(path); + if (!font) + return sq_throwerror(vm, String::Format("Failed to load font '%s'.", path)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(font, typetag_Font) +} +SQInteger ProjectLoadFontAliased(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSTRING(path) + __SQ_GETSTRING(alias) + FontEx *font = project->font_cache->LoadFont(path, alias); + if (!font) + return sq_throwerror(vm, String::Format("Failed to load font '%s' under alias '%s'.", path, alias)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(font, typetag_Font) +} +SQInteger ProjectDeleteFontAlias(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSTRING(alias) + project->font_cache->DeleteAlias(alias); + __SQ_GETEND + __SQ_RETURN +} +SQInteger ProjectGetFont(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(project, Project, typetag_Project) + __SQ_GETSTRING(path) + FontEx *font = project->font_cache->GetAliasedFont(path); + if (!font) + return sq_throwerror(vm, String::Format("Font '%s' not found.", path)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(font, typetag_Font) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterProjectBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Project + Type: Project + Type: ProjectLayer +#*/ + +/*# + Section: ProjectGeneral + Desc: General project functions +#*/ + /*# + Func: ProjectGetClock + Proto: Clock:Project + Desc: Get the project clock object. + #*/ + sq_register(vm, ProjectGetClock, "ProjectGetClock", _SC(".x")); + /*# + Func: ProjectGetScriptInstance + Proto: Instance:Project + Desc: Get the project script instance. + #*/ + sq_register(vm, ProjectGetScriptInstance, "ProjectGetScriptInstance", _SC(".x")); + /*# + Func: ProjectEnd + Proto: void:Project + Desc: Exit project. + #*/ + sq_register(vm, ProjectEnd, "ProjectEnd", _SC(".x")); + +/*# + Section: ProjectFontManagement + Desc: UI Font management functions +#*/ + /*# + Func: ProjectLoadFont + Proto: Font:Project, string path + Desc: Load a TrueType font in the project font cache. + #*/ + sq_register(vm, ProjectLoadFont, "ProjectLoadFont", _SC(".xs")); + sq_register(vm, ProjectLoadFont, "ProjectLoadUIFont", _SC(".xs")); + /*# + Func: ProjectLoadFontAliased + Proto: Font:Project, string path, string alias + Desc: Load a TrueType font under a specific alias. + #*/ + sq_register(vm, ProjectLoadFontAliased, "ProjectLoadFontAliased", _SC(".xss")); + sq_register(vm, ProjectLoadFontAliased, "ProjectLoadUIFontAliased", _SC(".xss")); + /*# + Func: ProjectDeleteFontAlias + Proto: void:Project, string alias + Desc: Delete a font alias from the font cache. + #*/ + sq_register(vm, ProjectDeleteFontAlias, "ProjectDeleteFontAlias", _SC(".xs")); + sq_register(vm, ProjectDeleteFontAlias, "ProjectDeleteUIFontAlias", _SC(".xs")); + /*# + Func: ProjectGetFont + Proto: Font:Project, string name + Desc: Retrieve a font from its name. + #*/ + sq_register(vm, ProjectGetFont, "ProjectGetFont", _SC(".xs")); + sq_register(vm, ProjectGetFont, "ProjectGetUIFont", _SC(".xs")); + +/*# + Section: ProjectLayerManagement + Desc: Layer management functions +#*/ + /*# + Func: ProjectLayerGetScene + Proto: ProjectScene:ProjectLayer + Desc: Return the scene instance a layer is displaying. + #*/ + sq_register(vm, ProjectLayerGetScene, "ProjectLayerGetScene", _SC(".x")); + /*# + Func: ProjectAddLayer + Proto: ProjectLayer:Project,ProjectScene,float zorder + Desc: Create a new layer to display a project scene. + Note: A scene can be added to several layers at once. + #*/ + sq_register(vm, ProjectAddLayer, "ProjectAddLayer", _SC(".xxn")); + /*# + Func: ProjectLayerSetZOrder + Proto: void:ProjectLayer,float + Desc: Set layer Z order. + Note: Smaller Z values are closer to the viewer. + #*/ + sq_register(vm, ProjectLayerSetZOrder, "ProjectLayerSetZOrder", _SC(".xn")); + /*# + Func: ProjectLayerGetZOrder + Proto: float:ProjectLayer + Desc: Get layer Z order. + #*/ + sq_register(vm, ProjectLayerGetZOrder, "ProjectLayerGetZOrder", _SC(".x")); + + /*# + Func: ProjectSetAll2DLayerOffset + Proto: void:Project,float x,float y + Desc: Set the offset of all 2d layer in the current project stack. The offset is specified in the layer reference resolution. + #*/ + sq_register(vm, ProjectSetAll2DLayerOffset, "ProjectSetAll2DLayerOffset", _SC(".xnn")); + +/*# + Section: ProjectSceneManagement + Desc: Scene management functions +#*/ + /*# + Func: ProjectNewScene3D + Proto: ProjectScene:Project + Desc: Create a new scene 3D. + Note: You need to add the newly created scene to a project layer to display it. + Example: +local project_scene = ProjectNewScene3D(g_project) +ProjectAddLayer(g_project, project_scene, 0.5) // add the 3d scene to a project layer with Z offset of 0.5 + #*/ + sq_register(vm, ProjectNewScene3D, "ProjectNewScene", _SC(".x")); + sq_register(vm, ProjectNewScene3D, "ProjectNewScene3D", _SC(".x")); + /*# + Func: ProjectNewScene2D + Proto: ProjectScene:Project + Desc: Create a new scene 2D. + Note: You need to add the newly created scene to a project layer to display it. + Example: +local project_scene = ProjectNewScene2D(g_project) +ProjectAddLayer(g_project, project_scene, 0.5) // add the 2d scene to a project layer with Z offset of 0.5 + #*/ + sq_register(vm, ProjectNewScene2D, "ProjectNewScene2D", _SC(".x")); + + /*# + Func: ProjectFindScene + Proto: ProjectScene:Project,string path + Desc: Returns an instance of a specific scene in the project, returns an invalid object if no such instance could be found. + #*/ + sq_register(vm, ProjectFindScene, "ProjectFindScene", _SC(".xs")); + /*# + Func: ProjectGetSceneLayerList + Proto: Array:Project,ProjectScene + Desc: Return all the project layers displaying a specific scene instance. A scene might be displayed by several different layers (eg. in order to display a split-screen view). + #*/ + sq_register(vm, ProjectGetSceneLayerList, "ProjectGetSceneLayerList", _SC(".xx")); + + /*# + Func: ProjectSceneIsActive + Proto: bool:Project,ProjectScene + Desc: Return the active state of a project scene. + #*/ + sq_register(vm, ProjectSceneIsActive, "ProjectSceneIsActive", _SC(".xx")); + sq_register(vm, ProjectSceneIsActive, "ProjectIsSceneActive", _SC(".xx")); + /*# + Func: ProjectSceneActivate + Proto: void:Project,ProjectScene,bool + Desc: Activate or deactivate a project scene. When deactivated a scene is not updated or displayed anymore. + #*/ + sq_register(vm, ProjectSceneActivate, "ProjectSceneActivate", _SC(".xxb")); + sq_register(vm, ProjectSceneActivate, "ProjectActivateScene", _SC(".xxb")); + /*# + Func: ProjectInstantiateScene + Proto: ProjectScene:Project,string path + Desc: Instantiate a project scene. + Note: You need to add the project scene to a layer to display it. This function will detect the type of scene to instantiate, 2d or 3d, from the input file. + See: ProjectSceneGetType, ProjectDeleteScene + Example: +local project_scene = ProjectInstantiateScene(g_project, "scene_file.nms") +ProjectAddLayer(g_project, project_scene, 0.5) + #*/ + sq_register(vm, ProjectInstantiateScene, "ProjectInstantiateScene", _SC(".xs")); + /*# + Func: ProjectSceneSetGlobal + Proto: void:ProjectScene + Desc: Register scene as the global scene script object (g_scene). + Note: The project automatically updates g_scene before updating or displaying a scene. + #*/ + sq_register(vm, ProjectSceneSetGlobal, "ProjectSceneSetGlobal", _SC(".x")); + /*# + Func: ProjectDeleteScene + Proto: void:Project,ProjectScene + Desc: Delete a project scene. + Note: All layers displaying this scene will be destroyed as well. + #*/ + sq_register(vm, ProjectUnloadScene, "ProjectDeleteScene", _SC(".xx")); + sq_register(vm, ProjectUnloadScene, "ProjectUnloadScene", _SC(".xx")); + /*# + Func: ProjectSceneGetType + Proto: ProjectSceneType:ProjectScene + Desc: Get a project scene type. + #*/ + sq_register(vm, ProjectSceneGetType, "ProjectSceneGetType", _SC(".x")); + /*# + Func: ProjectSceneGetInstance + Proto: Scene:ProjectScene + Desc: Get the scene object of type Scene or UI from a project scene object. + Example: +local scene = ProjectSceneGetInstace(project_scene) // this project scene encapsulates a 3d scene +SceneAddLight(scene, "MyLight") + #*/ + sq_register(vm, ProjectSceneGetInstance, "ProjectSceneGetInstance", _SC(".x")); + + /*# + Func: ProjectGetFileName + Proto: String:Project + Desc: Return the project file name, without the project path. + See: ProjectGetFilePath + #*/ + sq_register(vm, ProjectGetFileName, "ProjectGetFileName", _SC(".x")); + /*# + Func: ProjectGetFilePath + Proto: String:Project + Desc: Return the project path. + See: ProjectGetFileName + #*/ + sq_register(vm, ProjectGetFilePath, "ProjectGetFilePath", _SC(".x")); + + /*# + Enum: ProjectSceneType + Values: ProjectSceneTypeScene2d,ProjectSceneTypeScene3d + #*/ + sq_pushstring(vm, "ProjectSceneTypeScene2d", -1); sq_pushinteger(vm, ProjectSceneInstance::Type_Scene2d); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ProjectSceneTypeScene3d", -1); sq_pushinteger(vm, ProjectSceneInstance::Type_Scene3d); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "NullItem", -1); CObject::Push(vm, NULL, typetag_Item); sq_newslot(vm, -3, true); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/raytracer_binding.cpp b/include/modules/script_squirrel/legacy/raytracer_binding.cpp new file mode 100644 index 0000000..f484d87 --- /dev/null +++ b/include/modules/script_squirrel/legacy/raytracer_binding.cpp @@ -0,0 +1,165 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "raytracer/raytracer_core.h" + #include "core/graphic_resource_factory.h" + #include "core/resource_factories.h" + #include "core/geometry.h" + #include "picture/pict_io.h" + + using namespace GS; + using namespace GS::Script; + using namespace GS::Raytrace; + + +//------------------------------------------------------------------------------ +SQInteger NewRaytracer(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_RETURNSAFEPTR(new Raytracer(f->graphic), typetag_Raytracer) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RaytracerSetScene(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ray, Raytracer, typetag_Raytracer) + __SQ_GETSAFEPTR(scn, S3D::Scene, typetag_Scene3d) + __SQ_GETEND + __SQ_RETURNBOOL((ray && scn) ? ray->SetScene(scn) : false) +} +SQInteger RaytracerTrace(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(ray, Raytracer, typetag_Raytracer) + __SQ_GETSTRING(file) + __SQ_GETINT(width) + __SQ_GETINT(height) + + bool r = false; + Picture output(width, height); + if (ray->Render(output, width, height)) + r = output.isValid() ? PictureIO::Get().TgaSave(output, file) : false; + + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger RaytracerSetInterlace(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(ray, Raytracer, typetag_Raytracer) + __SQ_GETBOOL(interlaced) + __SQ_GETBOOL(interlace_even) + __SQ_GETEND + + Configuration config = ray->GetConfiguration(); + config.interlaced = interlaced ? true : false; + config.interlace_even = interlace_even ? true : false; + ray->SetConfiguration(config); + + __SQ_RETURN +} +SQInteger RaytracerSetAntialias(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(ray, Raytracer, typetag_Raytracer) + __SQ_GETBOOL(trace_aa) + __SQ_GETINT(aa_sample) + __SQ_GETFLOAT(aa_threshold) + __SQ_GETBOOL(aa_jitter) + __SQ_GETEND + + Configuration config = ray->GetConfiguration(); + config.trace_aa = trace_aa ? true : false; + config.aa_sample = aa_sample; + config.aa_threshold = aa_threshold; + config.aa_jitter = aa_jitter ? true : false; + ray->SetConfiguration(config); + + __SQ_RETURN +} +SQInteger RaytracerSetGlobalIllum(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(ray, Raytracer, typetag_Raytracer) + __SQ_GETBOOL(trace_gi) + __SQ_GETINT(gi_sample) + __SQ_GETINT(indirect_gi_bounce) + __SQ_GETEND + + Configuration config = ray->GetConfiguration(); + config.trace_gi = trace_gi ? true : false; + config.gi_sample = gi_sample; + config.indirect_gi_bounce = indirect_gi_bounce; + ray->SetConfiguration(config); + + __SQ_RETURN +} +SQInteger RaytracerStartInterlacedSequence(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ray, Raytracer, typetag_Raytracer) + ray->StartInterlacedSequence(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterRaytracerBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Raytracer +#*/ + +/*# + Section: RaytracerGeneric + Desc: Generic functions +#*/ + /*# + Func: NewRaytracer + Proto: Raytracer:ResourceFactory + Desc: Create a new raytracer instance. + #*/ + sq_register(vm, NewRaytracer, "NewRaytracer", _SC(".x")); + /*# + Func: RaytracerSetAntialias + Proto: void:raytracer,bool enable,int sample_count,float threshold,bool jitter + Desc: Set the raytracer antialias output. The number of AA sample can be set and jitered AA selected. Default threshold: 0.015. + #*/ + sq_register(vm, RaytracerSetAntialias, "RaytracerSetAntialias", _SC(".xbinb")); + /*# + Func: RaytracerSetGlobalIllum + Proto: void:raytracer,bool enable,int sample_count,int max_indirect_bounce + Desc: Enable the raytracer global illumination. The number of GI sample can be set as well as a maximum number of indirect bounce. + #*/ + sq_register(vm, RaytracerSetGlobalIllum, "RaytracerSetGlobalIllum", _SC(".xbii")); + /*# + Func: RaytracerSetInterlace + Proto: void:raytracer,bool interlaced,bool even_frame + Desc: Set the raytracer interlace output. The frame parity is specified as the second parameter. + #*/ + sq_register(vm, RaytracerSetInterlace, "RaytracerSetInterlace", _SC(".xbb")); + /*# + Func: RaytracerStartInterlacedSequence + Proto: void:raytracer + Desc: Start an interlaced sequence. This function should be called when beginning a new sequence in order to ensure correct frame parity. + #*/ + sq_register(vm, RaytracerStartInterlacedSequence, "RaytracerStartInterlacedSequence", _SC(".x")); + /*# + Func: RaytracerSetScene + Proto: void:raytracer,scene + Desc: Set raytracer scene, this function might be a little slow as it setups a lot data to work with. + #*/ + sq_register(vm, RaytracerSetScene, "RaytracerSetScene", _SC(".xx")); + /*# + Func: RaytracerTrace + Proto: void:raytracer,string out_picture,int width,int height + Desc: Raytrace current scene to a Targa picture file. Note that when rendering interlaced sequences one of two calls to this function will return false to notify you that the current frame was only buffered and not saved. + #*/ + sq_register(vm, RaytracerTrace, "RaytracerTrace", _SC(".xsii")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/renderer_binding.cpp b/include/modules/script_squirrel/legacy/renderer_binding.cpp new file mode 100644 index 0000000..934e0c2 --- /dev/null +++ b/include/modules/script_squirrel/legacy/renderer_binding.cpp @@ -0,0 +1,1354 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "squirrel.h" + #include "binding_helpers.h" + #include "core/renderer.h" + #include "core/renderer_toolbox.h" + #include "core/raster_font.h" + #include "core/resource_factories.h" + #include "core/camera.h" + #include "scene3d/mitem.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include + #if __PLATFORM_NINTENDO_WII__ + #include "wii_gx/wii_gx.h" + #endif + #include "picture/pict.h" + #include "gpu/gpu_renderer.h" + + + using namespace GS; + using namespace GS::S3D; + using namespace GS::Script; + using namespace GS::Render; + + +//------------------------------------------------------------------------------ +SQInteger RendererRegistrySetKey(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETSTRING(key) + + GS::Variant value; + + HSQOBJECT o; + sq_getstackobj(vm, __SQ_STACKPOS, &o); + switch (sq_type(o)) + { + case OT_BOOL: + { __SQ_GETBOOL(v) value = asbool(v); } break; + case OT_INTEGER: + { __SQ_GETINT(v) value = (int)v; } break; + case OT_FLOAT: + { __SQ_GETFLOAT(v) value = v; } break; + case OT_STRING: + { __SQ_GETSTRING(s) value = s; } break; + + default: + break; + } + renderer->registry.CreateKey(key, &value); + __SQ_GETEND + __SQ_RETURN +} + +SQInteger RendererRegistryGetKey(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETSTRING(key) + __SQ_GETEND + + GS::Variant v; + if (NML::Tag *tag = renderer->registry.GetTag(key)) + v = tag->GetValue(); + else + return sq_throwerror(vm, "Registry key does not exists"); + + switch (v.GetType()) + { + case GS::Variant::VariantBool: __SQ_RETURNBOOL(v.b_value) + case GS::Variant::VariantInteger: __SQ_RETURNINT(v.i_value) + case GS::Variant::VariantFloat: __SQ_RETURNFLOAT(v.f_value) + case GS::Variant::VariantString: __SQ_RETURNSTRING(v.s_value.c_str()) + + default: break; + } + return sq_throwerror(vm, "Cannot return this key variant"); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererClearFrame(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETFLOAT(r) + __SQ_GETFLOAT(g) + __SQ_GETFLOAT(b) + __SQ_GETEND + render->Clear(r, g, b, 1, 10000); + __SQ_RETURN +} +SQInteger RendererResetStatistics(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->ResetStatistics(); + __SQ_RETURN +} +SQInteger RendererGetStatistics(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + + sq_newtable(vm); + + sq_pushstring(vm, "renderable_drawn", -1); + sq_pushinteger(vm, render->stats.renderable_drawn); + sq_newslot(vm, -3, false); + + sq_pushstring(vm, "list_drawn", -1); + sq_pushinteger(vm, render->stats.list_drawn); + sq_newslot(vm, -3, false); + + sq_pushstring(vm, "triangle_drawn", -1); + sq_pushinteger(vm, render->stats.triangle_drawn); + sq_newslot(vm, -3, false); + return 1; +} +SQInteger RendererGetGlobalAspectRatio(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + __SQ_RETURNFLOAT(render->GetGlobalAspectRatio()) +} +SQInteger RendererSetGlobalAspectRatio(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETFLOAT(ar) + __SQ_GETEND + __SQ_RETURNFLOAT(render->SetGlobalAspectRatio(ar)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererSetOutputTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETSAFEPTRALLOWNULL(texture, Texture, typetag_Texture) + render->SetOutputTexture(texture); + __SQ_GETEND + __SQ_RETURN +} +SQInteger RendererRenderQueue(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->BeginDrawList(); + render->RenderList(); + render->EndDrawList(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererSetWorldMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETMATRIX4(m) + __SQ_GETEND + render->SetWorldMatrix(m); + __SQ_RETURN +} +SQInteger RendererSetIdentityWorldMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererApplyCamera(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->ApplyCamera(); + __SQ_RETURN +} +SQInteger RendererGetViewMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + if (render->GetCamera() == NULL) + return sq_throwerror(vm, "No view item."); + __SQ_RETURNMATRIX4(render->GetCamera()->GetMatrix()) +} +SQInteger RendererSetViewMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETMATRIX4(m) + __SQ_GETEND + render->SetViewMatrix(m); + __SQ_RETURN +} +SQInteger RendererSetIdentityViewMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->SetViewMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + __SQ_RETURN +} +SQInteger RendererSetViewItemAndApplyView(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(view, MItem, typetag_Item) + __SQ_GETEND + + if (view->GetItemType() != Type_Camera) + return sq_throwerror(vm, "Item is not a camera"); + render->SetCamera((Core::Camera *)(view->GetBaseItem())); + render->ApplyCamera(); + + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererSetProjectionMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETMATRIX4(m) + __SQ_GETEND + render->SetProjectionMatrix(m); + __SQ_RETURN +} +SQInteger RendererSetIdentityProjectionMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->SetProjectionMatrix(Matrix4::IdentityMatrix()); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererSetAllMatricesToIdentity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->SetViewMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + render->SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix()); + render->SetProjectionMatrix(Matrix4::IdentityMatrix()); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererGetOutputWindowSize(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + uint w, h; + render->GetOutputWindow()->GetSize(w, h); + __SQ_RETURNVECTOR2(Vector2(float(w), float(h))) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererGetOutputDimensions(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + tVector2 dimensions = render->GetOutputDimensions(); + __SQ_RETURNVECTOR2(Vector2(float(dimensions.x), float(dimensions.y))) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererSetOutputDimensions(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETINT(width) + __SQ_GETINT(height) + + render->ResizeVideo(width, height); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererSetClipping(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETFLOAT(ox) + __SQ_GETFLOAT(oy) + __SQ_GETFLOAT(ex) + __SQ_GETFLOAT(ey) + __SQ_GETEND + tVector2 d = render->GetOutputDimensions(); + fRect r(ox * d.x, oy * d.y, ex * d.x, ey * d.y); + render->SetClippingRect(&r); + __SQ_RETURN +} +SQInteger RendererGetViewport(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + tVector2 dimensions = render->GetOutputDimensions(); + fRect viewport = render->GetViewport(); + __SQ_RETURNRECT(fRect(viewport.sx / dimensions.x, viewport.sy / dimensions.y, viewport.ex / dimensions.x, viewport.ey / dimensions.y)) +} +SQInteger RendererSetViewport(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETFLOAT(ox) + __SQ_GETFLOAT(oy) + __SQ_GETFLOAT(ex) + __SQ_GETFLOAT(ey) + __SQ_GETEND + tVector2 d = render->GetOutputDimensions(); + render->SetViewport(fRect(ox * d.x, oy * d.y, ex * d.x, ey * d.y)); + __SQ_RETURN +} +SQInteger RendererGetScreenViewport(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + __SQ_RETURNRECT(render->GetViewport()) +} +SQInteger RendererSetScreenViewport(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETFRECT(viewport) + __SQ_GETEND + render->SetViewport(viewport); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererDrawTriangle(HSQUIRRELVM vm) +{ + Vector4 vtx[3]; + Color col[3]; + __SQ_GETSTART(9) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTORTOALWAYS(vtx[0]) + __SQ_GETVECTORTOALWAYS(vtx[1]) + __SQ_GETVECTORTOALWAYS(vtx[2]) + __SQ_GETVECTORTOALWAYS(col[0]) + __SQ_GETVECTORTOALWAYS(col[1]) + __SQ_GETVECTORTOALWAYS(col[2]) + __SQ_GETINT(blend) + __SQ_GETINT(rword) + __SQ_GETEND + render->DrawTriangle(1, vtx, 0, col, 0, 0, Core::Material::BlendOperator(blend), Core::Material::RenderWord(rword)); + __SQ_RETURN +} +SQInteger RendererDrawTriangleTextured(HSQUIRRELVM vm) +{ + Vector4 vtx[3]; + Color col[3]; + Vector2 uv[3]; + + __SQ_GETSTART(13) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTORTOALWAYS(vtx[0]) + __SQ_GETVECTORTOALWAYS(vtx[1]) + __SQ_GETVECTORTOALWAYS(vtx[2]) + __SQ_GETSAFEPTRALLOWNULL(texture, Texture, typetag_Texture) + __SQ_GETVECTOR2(uv0); + uv[0] = uv0; + __SQ_GETVECTOR2(uv1); + uv[1] = uv1; + __SQ_GETVECTOR2(uv2); + uv[2] = uv2; + +// __SQ_GETUVTO(uv[0]) +// __SQ_GETUVTO(uv[1]) +// __SQ_GETUVTO(uv[2]) + __SQ_GETVECTORTOALWAYS(col[0]) + __SQ_GETVECTORTOALWAYS(col[1]) + __SQ_GETVECTORTOALWAYS(col[2]) + __SQ_GETINT(blend) + __SQ_GETINT(rword) + render->DrawTriangle(1, vtx, 0, col, uv, texture, Core::Material::BlendOperator(blend), Core::Material::RenderWord(rword)); + __SQ_GETEND + __SQ_RETURN +} +SQInteger RendererDrawTriangleShaded(HSQUIRRELVM vm) +{ + Vector4 vtx[3]; + Color col[3]; + Vector2 uv[3]; + + __SQ_GETSTART(14) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTORTOALWAYS(vtx[0]) + __SQ_GETVECTORTOALWAYS(vtx[1]) + __SQ_GETVECTORTOALWAYS(vtx[2]) + __SQ_GETSAFEPTRALLOWNULL(texture, Texture, typetag_Texture) + __SQ_GETUVTO(uv[0]) + __SQ_GETUVTO(uv[1]) + __SQ_GETUVTO(uv[2]) + __SQ_GETVECTORTOALWAYS(col[0]) + __SQ_GETVECTORTOALWAYS(col[1]) + __SQ_GETVECTORTOALWAYS(col[2]) + __SQ_GETINT(blend) + __SQ_GETINT(rword) + __SQ_GETSAFEPTR(shader, Shader, typetag_Shader) + render->DrawTriangle(1, vtx, 0, col, uv, texture, Core::Material::BlendOperator(blend), Core::Material::RenderWord(rword), shader); + __SQ_GETEND + __SQ_RETURN +} +SQInteger RendererDrawCross(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTOR(pos) + __SQ_GETEND + RendererToolbox::DrawCross(*render, pos); + __SQ_RETURN +} +SQInteger RendererDrawCrossColored(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTOR(pos) + __SQ_GETVECTOR(col) + __SQ_GETEND + Color color(col.x, col.y, col.z); + RendererToolbox::DrawCross(*render, pos, 1, &color); + __SQ_RETURN +} +SQInteger RendererDrawLine(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTOR(pos_a) + __SQ_GETVECTOR(pos_b) + __SQ_GETEND + Vector4 p[2] = { pos_a, pos_b }; + Color c[2] = { Color(1, 1, 1), Color(1, 1, 1) }; + render->DrawLine(1, p, c); + __SQ_RETURN +} +SQInteger RendererDrawLineColored(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTOR(pos_a) + __SQ_GETVECTOR(pos_b) + __SQ_GETVECTOR(col) + __SQ_GETEND + Vector4 p[2] = { pos_a, pos_b }; + Color c[2] = { col, col }; + render->DrawLine(1, p, c); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger RendererDrawLineEx(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTOR(pos_a) + __SQ_GETVECTOR(pos_b) + __SQ_GETINT(blend) + __SQ_GETINT(rword) + __SQ_GETEND + Vector4 p[2] = { pos_a, pos_b }; + Color c[2] = { Color(1, 1, 1), Color(1, 1, 1) }; + render->DrawLine(1, p, c, (Core::Material::BlendOperator)blend, (Core::Material::RenderWord)rword); + __SQ_RETURN +} +SQInteger RendererDrawLineColoredEx(HSQUIRRELVM vm) +{ + __SQ_GETSTART(7) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTOR(pos_a) + __SQ_GETVECTOR(pos_b) + __SQ_GETVECTOR(col_a) + __SQ_GETVECTOR(col_b) + __SQ_GETINT(blend) + __SQ_GETINT(rword) + __SQ_GETEND + Vector4 p[2] = { pos_a, pos_b }; + Color c[2] = { col_a, col_b }; + render->DrawLine(1, p, c, (Core::Material::BlendOperator)blend, (Core::Material::RenderWord)rword); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +#if 1 + +SQInteger RendererSetControlFlag(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETINT(flag) + __SQ_GETBOOL(set) + __SQ_GETEND + __LOG_W__ << "Obsolete function, please use the renderer registry.\n"; + __SQ_RETURN +} +SQInteger RendererGetControlFlag(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETINT(flag) + __SQ_GETEND + __LOG_W__ << "Obsolete function, please use the renderer registry.\n"; + __SQ_RETURNBOOL(false) +} +SQInteger RendererSetSystemWord(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETINT(flag) + __SQ_GETBOOL(set) + __SQ_GETEND + __LOG_W__ << "Obsolete function, please use the renderer registry.\n"; + __SQ_RETURN +} +SQInteger RendererGetSystemWord(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETINT(flag) + __SQ_GETEND + __LOG_W__ << "Obsolete function, please use the renderer registry.\n"; + __SQ_RETURNBOOL(false) +} + +#endif +//------------------------------------------------------------------------------ + +SQInteger LoadRasterFont(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(rf, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(nml_path) + __SQ_GETSTRING(map_base_path) + RasterFont *f = new RasterFont; + if (!f || !f->Load(*rf->render, nml_path, map_base_path)) + return sq_throwerror(vm, "Failed to create raster font."); + __SQ_GETEND + __SQ_RETURNMANAGEDSAFEPTR(f, typetag_RasterFont) +} +SQInteger RasterFontGetLineHeight(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(font, RasterFont, typetag_RasterFont) + __SQ_RETURNFLOAT(font->GetHeight()) +} +SQInteger RasterFontGetBaseline(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(font, RasterFont, typetag_RasterFont) + __SQ_RETURNFLOAT(font->GetBaseline()) +} +SQInteger RendererRenderQueueReset(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->DeleteRenderableList(); + __SQ_RETURN +} + +SQInteger RendererWrite(HSQUIRRELVM vm) +{ + __SQ_GETSTART(9) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(font, RasterFont, typetag_RasterFont) + __SQ_GETSTRING(text) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETFLOAT(k) + __SQ_GETBOOL(ar) + __SQ_GETINT(align) + __SQ_GETVECTORW(color) + + Renderer::WriterConfig cfg; + cfg.correct_ar = asbool(ar); + + Color c(color); + render->Write(*font, text, x, y, cfg, k, &c, (Renderer::WriterAlignment)align); + __SQ_GETEND + __SQ_RETURN +} + + +SQInteger RendererWriteMirrored(HSQUIRRELVM vm) +{ + __SQ_GETSTART(9) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(font, RasterFont, typetag_RasterFont) + __SQ_GETSTRING(text) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETFLOAT(k) + __SQ_GETBOOL(ar) + __SQ_GETINT(align) + __SQ_GETVECTORW(color) + + Renderer::WriterConfig cfg; + cfg.correct_ar = asbool(ar); + + Color c(color); + render->Write(*font, text, x, y, cfg, k, &c, (Renderer::WriterAlignment)align, true); + __SQ_GETEND + __SQ_RETURN +} +SQInteger RendererGrabDisplayToTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(tex, Texture, typetag_Texture) + __SQ_GETEND + render->GrabDisplay(tex); + __SQ_RETURN +} + +SQInteger RendererReadDepthPixels(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + GPU::Renderer *gpu_renderer = dynamic_cast(render); + + int w = gpu_renderer->resolve_fbo->depth_texture->GetWidth(); + int h = gpu_renderer->resolve_fbo->depth_texture->GetHeight(); + + int count = w * h; + + std::vector buffer(count); + if(gpu_renderer->gpu_config.enable_aa) + gpu_renderer->buffer_fbo->ReadDepthPixels(buffer.data()); + else + gpu_renderer->resolve_fbo->ReadDepthPixels(buffer.data()); + + sq_newarray(vm, 0); + + for (int i = 0; i < count; ++i) + { + sq_pushfloat(vm, buffer[i]); + sq_arrayappend(vm, -2); + } + return 1; +} + +SQInteger RendererGrabDisplayToPicture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(picture, Picture, typetag_Picture) + __SQ_GETEND + render->GrabDisplay(*picture); + __SQ_RETURN +} + +SQInteger RendererSetClippingPlane(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETVECTOR(p) + __SQ_GETVECTOR(n) + __SQ_GETEND + render->SetClippingPlane(p, n); + __SQ_RETURN +} +SQInteger RendererClearClippingPlane(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(render, Renderer, typetag_Renderer) + render->ClearClippingPlane(); + __SQ_RETURN +} + +SQInteger RendererTextureUpdate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(t, Texture, typetag_Texture) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + if ((t->GetWidth() != p->GetWidth()) || (t->GetHeight() != p->GetHeight())) + t->Create((const char *)p->GetData(), p->GetWidth(), p->GetHeight()); + else t->Blit((const char *)p->GetData(), p->GetWidth(), p->GetHeight()); + __SQ_GETEND + __SQ_RETURN +} + +//--------------------------------------- +SQInteger RendererSetFullScreen(HSQUIRRELVM vm) +//--------------------------------------- +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(render, Renderer, typetag_Renderer) + __SQ_GETBOOL(fullscreen) + __SQ_GETEND + render->SetFullscreen(fullscreen); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +// Spline and render-to-texture bindings +//------------------------------------------------------------------------------ +SQInteger RendererCreateRenderTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETSTRING(name) + __SQ_GETINT(width) + __SQ_GETINT(height) + __SQ_GETEND + + GPU::Renderer *gpu_renderer = dynamic_cast(renderer); + if (!gpu_renderer) + return sq_throwerror(vm, "Renderer is not a GPU renderer"); + + Render::Texture *tex = gpu_renderer->CreateRenderTexture(name, width, height); + if (tex) + __SQ_RETURNSAFEPTR(tex, typetag_Texture) + else + return sq_throwerror(vm, "Failed to create render texture"); +} + +SQInteger RendererClearTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(tex, Render::Texture, typetag_Texture) + __SQ_GETFLOAT(r) + __SQ_GETFLOAT(g) + __SQ_GETFLOAT(b) + __SQ_GETFLOAT(a) + __SQ_GETEND + + GPU::Renderer *gpu_renderer = dynamic_cast(renderer); + if (!gpu_renderer) + return sq_throwerror(vm, "Renderer is not a GPU renderer"); + + __LOG_W__ << "Received clear with color: " << r << "," << g << "," << b << "," << a << "\n"; + gpu_renderer->ClearTexture(tex, Color(r, g, b, a)); + + __SQ_RETURN +} + +SQInteger RendererBlitTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(dst, Render::Texture, typetag_Texture) + __SQ_GETSAFEPTR(src, Render::Texture, typetag_Texture) + __SQ_GETEND + + GPU::Renderer *gpu_renderer = dynamic_cast(renderer); + if (!gpu_renderer) + return sq_throwerror(vm, "Renderer is not a GPU renderer"); + + gpu_renderer->BlitTextureToTexture(src, dst); + __SQ_RETURN +} + +SQInteger RendererDrawSplineToTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(15) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETSAFEPTR(tex, Render::Texture, typetag_Texture) + + __LOG_W__ << "Reading points array...\n"; + + GPU::Renderer *gpu_renderer = dynamic_cast(renderer); + if (!gpu_renderer) + return sq_throwerror(vm, "Renderer is not a GPU renderer"); + + __LOG_W__ << "Getting points...\n"; + + // Get array of points - manually since it's an array + HSQOBJECT arr_obj; + sq_getstackobj(vm, __sq_stackpos, &arr_obj); + if (sq_type(arr_obj) != OT_ARRAY) + return sq_throwerror(vm, "Points must be an array"); + __SQ_GETUPDATESTACK + + __LOG_W__ << "Filling points...\n"; + + Array points; + sq_pushobject(vm, arr_obj); + SQInteger arr_size = sq_getsize(vm, -1); + points.Allocate((uint)arr_size); + + //__LOG_W__ << "Array size: " << arr_size << "\n"; + + for (SQInteger i = 0; i < arr_size; i++) + { + sq_pushinteger(vm, i); + sq_get(vm, -2); + + if (sq_gettype(vm, -1) != OT_ARRAY) + { + sq_pop(vm, 2); + return sq_throwerror(vm, "Each point must be [x,y] array"); + } + + sq_pushinteger(vm, 0); + sq_get(vm, -2); + SQFloat x; + sq_getfloat(vm, -1, &x); + sq_pop(vm, 1); + + sq_pushinteger(vm, 1); + sq_get(vm, -2); + SQFloat y; + sq_getfloat(vm, -1, &y); + sq_pop(vm, 2); + + points[(uint)i] = Vector2(x, y); + } + sq_pop(vm, 1); + + __LOG_W__ << "Got " << points.GetCount() << " points.\n"; + + __SQ_GETFLOAT(width) + + __SQ_GETFLOAT(r) + __SQ_GETFLOAT(g) + __SQ_GETFLOAT(b) + __SQ_GETFLOAT(a) + + __SQ_GETFLOAT(rBorder) + __SQ_GETFLOAT(gBorder) + __SQ_GETFLOAT(bBorder) + __SQ_GETFLOAT(aBorder) + + __SQ_GETFLOAT(borderWidth) + + __SQ_GETFLOAT(margin) + + __SQ_GETBOOL(clear) + + __SQ_GETEND + + if (!tex) + { + __LOG_E__ << "ERROR: Texture is NULL!\n"; + return sq_throwerror(vm, "Target texture is null"); + } + + const auto borderColor = Color(rBorder, gBorder, bBorder, aBorder); + gpu_renderer->DrawSplineToTexture( + tex, + points, + width, + Color(r, g, b, a), + 16, // samples per segment + clear, // don't clear - preserve existing content (composit mode) + true, // soft edge + &borderColor, + borderWidth, + margin + ); + + __LOG_W__ << "DrawSplineToTexture call completed successfully!\n"; + + __SQ_RETURN +} + +//--------------------------------------------------------- +void RegisterRendererBinding(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ +/*# + Topic: Renderer + Type: Renderer + Type: RasterFont +#*/ + +/*# + Section: RendererRegistry + Desc: Renderer registry functions. +#*/ + /*# + Func: RendererRegistrySetKey + Proto: void:Renderer,string key,value + Desc: Set renderer registry key value. + #*/ + sq_register(vm, RendererRegistrySetKey, "RendererRegistrySetKey", _SC(".xs.")); + /*# + Func: RendererRegistryGetKey + Proto: value:Renderer,string key + Desc: Get renderer registry key value. + #*/ + sq_register(vm, RendererRegistryGetKey, "RendererRegistryGetKey", _SC(".xs")); + +/*# + Section: RenderResource + Desc: Render resource functions +#*/ + /*# + Func: RendererTextureUpdate + Proto: void:Texture,Picture + Desc: Update texture from a picture, valid all changes to the renderer texture memory. + #*/ + sq_register(vm, RendererTextureUpdate, "RendererTextureUpdate", _SC(".xx")); + +/*# + Section: RenderViewport + Desc: Viewport functions +#*/ + /*# + Func: RendererGetGlobalAspectRatio + Proto: float:void + Desc: Get renderer global aspect ratio correction. + #*/ + sq_register(vm, RendererGetGlobalAspectRatio, "RendererGetGlobalAspectRatio", _SC(".x")); + /*# + Func: RendererSetGlobalAspectRatio + Proto: float:float + Desc: Set renderer global aspect ratio correction, returns the previous value. + #*/ + sq_register(vm, RendererSetGlobalAspectRatio, "RendererSetGlobalAspectRatio", _SC(".xn")); + /*# + Func: RendererSetViewItemAndApplyView + Proto: void:renderer,item + Desc: Change view item. + #*/ + sq_register(vm, RendererSetViewItemAndApplyView, "RendererSetViewItemAndApplyView", _SC(".xx")); + + /*# + Func: RendererSetWorldMatrix + Proto: void:Renderer,Matrix4 + Desc: Set the renderer current world matrix. + #*/ + sq_register(vm, RendererSetWorldMatrix, "RendererSetWorldMatrix", _SC(".xx")); + /*# + Func: RendererSetIdentityWorldMatrix + Proto: void:Renderer + Desc: Set the renderer current world matrix as the identity matrix. + #*/ + sq_register(vm, RendererSetIdentityWorldMatrix, "RendererSetIdentityWorldMatrix", _SC(".x")); + + /*# + Func: RendererApplyCamera + Proto: void:Renderer + Desc: Set the renderer view and projection matrices from the current camera. + #*/ + sq_register(vm, RendererApplyCamera, "RendererApplyCamera", _SC(".x")); + /*# + Func: RendererGetViewMatrix + Proto: Matrix4:Renderer + Desc: Get the renderer current view matrix. + #*/ + sq_register(vm, RendererGetViewMatrix, "RendererGetViewMatrix", _SC(".x")); + /*# + Func: RendererSetViewMatrix + Proto: void:Renderer,Matrix4 + Desc: Set the renderer current view matrix. + #*/ + sq_register(vm, RendererSetViewMatrix, "RendererSetViewMatrix", _SC(".xx")); + /*# + Func: RendererSetIdentityViewMatrix + Proto: void:Renderer + Desc: Set the renderer current view matrix as the identity matrix. + #*/ + sq_register(vm, RendererSetIdentityViewMatrix, "RendererSetIdentityViewMatrix", _SC(".x")); + /*# + Func: RendererSetProjectionMatrix + Proto: void:Renderer,Matrix4 + Desc: Set the renderer current projection matrix. + #*/ + sq_register(vm, RendererSetProjectionMatrix, "RendererSetProjectionMatrix", _SC(".xx")); + /*# + Func: RendererSetIdentityProjectionMatrix + Proto: void:Renderer + Desc: Set the renderer current projection matrix as the identity matrix. + #*/ + sq_register(vm, RendererSetIdentityProjectionMatrix, "RendererSetIdentityProjectionMatrix", _SC(".x")); + /*# + Func: RendererSetAllMatricesToIdentity + Proto: void:Renderer + Desc: Set all renderer drawing matrices to the identity matrix. + #*/ + sq_register(vm, RendererSetAllMatricesToIdentity, "RendererSetAllMatricesToIdentity", _SC(".x")); + + /*# + Func: RendererSetClipping + Proto: void:Renderer renderer,float start_x,float start_y,float end_x,float end_y + Desc: Set clipping rect in normalized coordinates. + #*/ + sq_register(vm, RendererSetClipping, "RendererSetClipping", _SC(".xnnnn")); + + /*# + Func: RendererSetFullScreen + Proto: void:Renderer renderer,bool + Desc: Set the fullscreen. + See: RendererGetOutputDimensions + #*/ + sq_register(vm, RendererSetFullScreen, "RendererSetFullScreen", _SC(".xb")); + /*# + Func: RendererSetScreenViewport + Proto: void:Renderer renderer,Rect viewport + Desc: Set the renderer viewport in screen coordinates. + See: RendererGetOutputDimensions + Example: +// Set a fullscreen viewport. +local d = RendererGetOutputDimensions(g_render) +RendererSetScreenViewport(g_render, Rect(0, 0, d.x, d.y)) + #*/ + sq_register(vm, RendererSetScreenViewport, "RendererSetScreenViewport", _SC(".xx")); + /*# + Func: RendererGetScreenViewport + Proto: Rect:Renderer renderer + Desc: Return the current viewport rect in screen coordinates. + Example: +local viewport = RendererGetScreenViewport(g_render) +print("Viewport size: " + viewport.GetWidth() + "x" + viewport.GetHeight()) // will return the current output dimensions + #*/ + sq_register(vm, RendererGetViewport, "RendererGetViewport", _SC(".x")); + + /*# + Func: RendererSetViewport + Proto: void:Renderer renderer,float start_x,float start_y,float end_x,float end_y + Desc: Set the renderer viewport in normalized coordinates. + See: RendererGetOutputDimensions + Example: +// Set a fullscreen viewport. +RendererSetViewport(g_render, 0, 0, 1, 1) + #*/ + sq_register(vm, RendererSetViewport, "RendererSetViewport", _SC(".xnnnn")); + /*# + Func: RendererGetViewport + Proto: Rect:Renderer renderer + Desc: Return the current viewport rectangle in normalized coordinates. + See: RendererGetOutputDimensions + Example: +local viewport = RendererGetViewport(g_render) +print("Viewport size: " + viewport.GetWidth() + "x" + viewport.GetHeight()) // default: 1.0x1.0 + #*/ + sq_register(vm, RendererGetViewport, "RendererGetViewport", _SC(".x")); + + /*# + Func: RendererGetOutputDimensions + Proto: Vector2:Renderer renderer + Desc: Get the renderer output dimensions in pixels. + #*/ + sq_register(vm, RendererGetOutputDimensions, "RendererGetOutputDimensions", _SC(".x")); + /*# + Func: RendererSetOutputDimensions + Proto: void:Renderer renderer, int width, int height + Desc: Set the renderer output dimensions in pixels. + #*/ + sq_register(vm, RendererSetOutputDimensions, "RendererSetOutputDimensions", _SC(".xii")); + + /*# + Func: RendererGetOutputWindowSize + Proto: Vector2:Renderer renderer + Desc: Get the renderer output dimensions in pixels. + #*/ + sq_register(vm, RendererGetOutputWindowSize, "RendererGetOutputWindowSize", _SC(".x")); + /*# + Func: RendererSetClippingPlane + Proto: void:renderer,Vector p,Vector n + Desc: Set user clipping plane. + #*/ + sq_register(vm, RendererSetClippingPlane, "RendererSetClippingPlane", _SC(".xxx")); + /*# + Func: RendererClearClippingPlane + Proto: void:renderer + Desc: Clear the user clipping plane. + #*/ + sq_register(vm, RendererClearClippingPlane, "RendererClearClippingPlane", _SC(".x")); + /*# + Func: RendererClearFrame + Proto: void:scene,float r,float g,float b + Desc: Clear viewport with a normalized float color. + #*/ + sq_register(vm, RendererClearFrame, "RendererClearFrame", _SC(".xnnn")); + /*# + Func: RendererSetOutputTexture + Proto: void:renderer,texture + Desc: Set output texture. + #*/ + sq_register(vm, RendererSetOutputTexture, "RendererSetOutputTexture", _SC(".xx")); + +/*# + Section: RenderRender + Desc: Rendering functions +#*/ + /*# + Func: RendererRenderQueue + Proto: void:renderer + Desc: Render queue. + #*/ + sq_register(vm, RendererRenderQueue, "RendererRenderQueue", _SC(".x")); + /*# + Func: RendererRenderQueueReset + Proto: void:renderer + Desc: Empty the renderer render queue. + Note: This is not done automatically so that you may render several viewpoints using the same render queue. + #*/ + sq_register(vm, RendererRenderQueueReset, "RendererRenderQueueReset", _SC(".x")); + /*# + Func: RendererDrawCross + Proto: void:renderer,vector origin + Desc: Draw a 3d cross. + #*/ + sq_register(vm, RendererDrawCross, "RendererDrawCross", _SC(".xx")); + /*# + Func: RendererDrawTriangle + Proto: void:Renderer,Vector v0,Vector v1,Vector v2,Color c0,Color c1,Color c2,MaterialBlendOperator blend_operator,MaterialRenderWord render_word + Desc: Draw a triangle. + Note: The triangle will be transformed by the current world, view and projection matrices. + #*/ + sq_register(vm, RendererDrawTriangle, "RendererDrawTriangle", _SC(".xxxxxxxii")); + /*# + Func: RendererDrawTriangleTextured + Proto: void:Renderer,Vector v0,Vector v1,Vector v2,Texture,UV uv0,UV uv1,UV uv2,Color c0,Color c1,Color c2,MaterialBlendOperator blend_operator,MaterialRenderWord render_word + Desc: Draw a textured triangle. + Note: The triangle will be transformed by the current world, view and projection matrices. + #*/ + sq_register(vm, RendererDrawTriangleTextured, "RendererDrawTriangleTextured", _SC(".xxxxxxxxxxxii")); + /*# + Func: RendererDrawTriangleShaded + Proto: void:Renderer,Vector v0,Vector v1,Vector v2,Texture,UV uv0,UV uv1,UV uv2,Color c0,Color c1,Color c2,MaterialBlendOperator blend_operator,MaterialRenderWord render_word,Shader shader + Desc: Draw a triangle using a specific shader. + Note: The triangle will be transformed by the current world, view and projection matrices. + #*/ + sq_register(vm, RendererDrawTriangleShaded, "RendererDrawTriangleShaded", _SC(".xxxxxxxxxxxiix")); + + /*# + Func: RendererDrawLine + Proto: void:renderer,vector start,vector end + Desc: Draw a line. + See: RendererDrawLineEx + Note: The line will be transformed by the current world, view and projection matrices. + Example: +// Work in world space, set identity matrix as the world matrix. +RendererSetWorldMatrix(g_renderer, Matrix4()) + +// Draw single line along the X axis from the origin. +RendererDrawLine(g_render, Vector(0, 0, 0), Vector(1, 0, 0)) + #*/ + sq_register(vm, RendererDrawLine, "RendererDrawLine", _SC(".xxx")); + /*# + Func: RendererDrawCrossColored + Proto: void:renderer,vector origin,color + Desc: Draw a 3d colored cross. + #*/ + sq_register(vm, RendererDrawCrossColored, "RendererDrawCrossColored", _SC(".xxx")); + /*# + Func: RendererDrawLineColored + Proto: void:renderer,vector start,vector end,color + Desc: Draw a colored line. + See: RendererDrawLineColoredEx + #*/ + sq_register(vm, RendererDrawLineColored, "RendererDrawLineColored", _SC(".xxxx")); + /*# + Func: RendererDrawLineEx + Proto: void:renderer,vector start,vector end,MaterialBlendOperator blend_operator,MaterialRenderWord render_word + Desc: Draw a line specifying the blend operator and material render word to use. + #*/ + sq_register(vm, RendererDrawLineEx, "RendererDrawLineEx", _SC(".xxxii")); + /*# + Func: RendererDrawLineColoredEx + Proto: void:renderer,vector start,vector end,Color start,Color end,MaterialBlendOperator blend_operator,MaterialRenderWord render_word + Desc: Draw a colored line specifying the blend operator and material render word to use. + #*/ + sq_register(vm, RendererDrawLineColoredEx, "RendererDrawLineColoredEx", _SC(".xxxxxii")); + +/*# + Section: RenderWriter + Desc: Raster writer functions +#*/ + /*# + Func: LoadRasterFont + Proto: RasterFont:RenderResourceFactory,String description_path,String texture_base_path + Desc: Load a font for the raster-based renderer writer. + Note: Raster fonts can be created by using the tool found in the GameStart Editor Tools menu. + Example: +local raster_font = LoadRasterFont(g_factory, "@core/fonts/profiler_base.nml", "@core/fonts/profiler_base") + #*/ + sq_register(vm, LoadRasterFont, "LoadRasterFont", _SC(".xss")); + /*# + Func: RendererWrite + Proto: void:renderer,RasterFont font,string text,float x,float y,float scale,bool correct_aspect_ratio,WriterAlign alignment,vector rgba + Desc: Write a text using the raster-based writer. + Note: The writer output primitives will be transformed by the current world, view and projection matrices. + See: LoadRasterFont + Example: +RendererWrite(g_render, raster_font, "Some text", 0.5, 0.5, 1, true, WriterAlignMiddle, Vector(1, 1, 1)) + #*/ + sq_register(vm, RendererWrite, "RendererWrite", _SC(".xxsnnnbix")); + + /*# + Func: RendererWriteMirrored + Proto: void:renderer,RasterFont font,string text,float x,float y,float scale,bool correct_aspect_ratio,WriterAlign alignment,vector rgba + Desc: Write a text using the raster-based writer. + Note: The writer output primitives will be transformed by the current world, view and projection matrices. + See: LoadRasterFont + Example: +RendererWriteMirrored(g_render, raster_font, "Some text", 0.5, 0.5, 1, true, WriterAlignMiddle, Vector(1, 1, 1)) + #*/ + sq_register(vm, RendererWriteMirrored, "RendererWriteMirrored", _SC(".xxsnnnbix")); + /*# + Func: RasterFontGetLineHeight + Proto: float:RasterFont + Desc: Return the raster font line height. + #*/ + sq_register(vm, RasterFontGetLineHeight, "RasterFontGetLineHeight", _SC(".x")); + /*# + Func: RasterFontGetBaseline + Proto: float:RasterFont + Desc: Return the raster font baseline. + #*/ + sq_register(vm, RasterFontGetBaseline, "RasterFontGetBaseline", _SC(".x")); + +/*# + Section: RenderObsolete + Desc: Obsolete functions +#*/ + +#if 1 + /*# + Func: RendererSetControlWord + Proto: void:renderer,RendererControlWord,bool set + Desc: Set renderer control word. + #*/ + sq_register(vm, RendererSetControlFlag, "RendererSetControlFlag", _SC(".xib")); + sq_register(vm, RendererSetControlFlag, "RendererSetControlWord", _SC(".xib")); + /*# + Func: RendererGetControlWord + Proto: bool:renderer,RendererControlWord + Desc: Get renderer control word. + #*/ + sq_register(vm, RendererGetControlFlag, "RendererGetControlFlag", _SC(".xi")); + sq_register(vm, RendererGetControlFlag, "RendererGetControlWord", _SC(".xi")); + /*# + Func: RendererSetSystemWord + Proto: void:Renderer,RendererSystemWord,bool set + Desc: Set renderer system word. + #*/ + sq_register(vm, RendererSetSystemWord, "RendererSetSystemWord", _SC(".xib")); + /*# + Func: RendererGetSystemWord + Proto: bool:Renderer,RendererSystemWord + Desc: Get renderer system word. + #*/ + sq_register(vm, RendererGetSystemWord, "RendererGetSystemWord", _SC(".xi")); +#endif + +/*# + Section: RenderDebug + Desc: Debugging functions +#*/ + /*# + Func: RendererGetStatistics + Proto: void:renderer + Desc: Return a renderer statistic object. + #*/ + sq_register(vm, RendererGetStatistics, "RendererGetStatistics", _SC(".x")); + /*# + Func: RendererResetStatistics + Proto: void:renderer + Desc: Reset internal statistic object. + #*/ + sq_register(vm, RendererResetStatistics, "RendererResetStatistics", _SC(".x")); + + /*# + Func: RendererGrabDisplayToPicture + Proto: void:Renderer,Picture + Desc: Grab the renderer frame buffer to a picture. + #*/ + sq_register(vm, RendererGrabDisplayToPicture, "RendererGrabDisplayToPicture", _SC(".xx")); + + /*# + Func: RendererGrabDisplayToTexture + Proto: void:Renderer,Texture + Desc: Grab the renderer frame buffer to a texture. + #*/ + sq_register(vm, RendererGrabDisplayToTexture, "RendererGrabDisplayToTexture", _SC(".xx")); + sq_register(vm, RendererReadDepthPixels, "RendererReadDepthPixels", _SC(".x")); + + sq_pushroottable(vm); + + /*# + Enum: MaterialBlendOperator + Values: MaterialBlendNone,MaterialBlendAdd,MaterialBlendAlpha + #*/ + using Core::Material; + + sq_pushstring(vm, "MaterialBlendNone", -1); sq_pushinteger(vm, Material::Blend_None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialBlendAdd", -1); sq_pushinteger(vm, Material::Blend_Add); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialBlendAlpha", -1); sq_pushinteger(vm, Material::Blend_Alpha); sq_newslot(vm, -3, true); + + /*# + Enum: MaterialRenderWord + Values: MaterialRenderNone,MaterialRenderDoubleSided,MaterialRenderNoZWrite,MaterialRenderNoZTest + #*/ + sq_pushstring(vm, "MaterialRenderNone", -1); sq_pushinteger(vm, Material::Render_None); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderDoubleSided", -1); sq_pushinteger(vm, Material::Render_DoubleSided); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderNoZWrite", -1); sq_pushinteger(vm, Material::Render_NoZWrite); sq_newslot(vm, -3, true); + sq_pushstring(vm, "MaterialRenderNoZTest", -1); sq_pushinteger(vm, Material::Render_NoZTest); sq_newslot(vm, -3, true); + +#if 1 + sq_pushstring(vm, "MaterialRenderDefault", -1); sq_pushinteger(vm, Material::Render_None); sq_newslot(vm, -3, true); + + /*# + Enum: RendererSystemWord + Values: RenderVSync + #*/ + sq_pushstring(vm, "RenderVSync", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + + /*# + Enum: RendererControlWord + Values: RenderMotionBlur,RenderShadowMapping,RenderBloom,RenderDepthOfField + #*/ + sq_pushstring(vm, "RenderMotionBlur", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RenderShadowMapping", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RenderBloom", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "RenderDepthOfField", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); +#endif + + /*# + Enum: WriterAlign + Values: WriterAlignLeft,WriterAlignRight,WriterAlignMiddle + #*/ + sq_pushstring(vm, "WriterAlignLeft", -1); sq_pushinteger(vm, Renderer::AlignLeft); sq_newslot(vm, -3, true); + sq_pushstring(vm, "WriterAlignRight", -1); sq_pushinteger(vm, Renderer::AlignRight); sq_newslot(vm, -3, true); + sq_pushstring(vm, "WriterAlignMiddle", -1); sq_pushinteger(vm, Renderer::AlignMiddle); sq_newslot(vm, -3, true); + +/*# + Section: RendererSpline + Desc: Spline and render-to-texture functions +#*/ + /*# + Func: RendererCreateRenderTexture + Proto: Texture:Renderer,string name,int width,int height + Desc: Create a new render-target texture (can be rendered to). + #*/ + sq_register(vm, RendererCreateRenderTexture, "RendererCreateRenderTexture", _SC(".xsii")); + /*# + Func: RendererClearTexture + Proto: void:Renderer,Texture,float r,float g,float b,float a + Desc: Clear a texture with a solid color (RGBA values 0..1). + #*/ + sq_register(vm, RendererClearTexture, "RendererClearTexture", _SC(".xxffff")); + /*# + Func: RendererBlitTexture + Proto: void:Renderer,Texture dst,Texture src + Desc: Copy source texture to destination texture. + #*/ + sq_register(vm, RendererBlitTexture, "RendererBlitTexture", _SC(".xxx")); + /*# + Func: RendererDrawSplineToTexture + Proto: void:Renderer,Texture,array points,float width,float r,float g,float b,float a, + float rBorder,float gBorder,float bBorder,float aBorder,float margin,bool clear + Desc: Draw an interpolated spline (Catmull-Rom) on a texture with given width (pixels) and color. + Points array format: [[x1,y1], [x2,y2], ...] in normalized coords [0..1]. + Example: RendererDrawSplineToTexture(renderer, tex, [[0.1,0.1], [0.5,0.8], [0.9,0.2]], 10.0, 1.0, 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 2.0, true) + #*/ + sq_register(vm, RendererDrawSplineToTexture, "RendererDrawSplineToTexture", _SC(".xxafffffffffffb")); + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/resource_factory_binding.cpp b/include/modules/script_squirrel/legacy/resource_factory_binding.cpp new file mode 100644 index 0000000..b73d000 --- /dev/null +++ b/include/modules/script_squirrel/legacy/resource_factory_binding.cpp @@ -0,0 +1,288 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "core/resource_factories.h" + #include "core/graphic_resource_factory.h" + #include "core/render_resource_factory.h" + #include "core/mixer_resource_factory.h" + #include "core/raster_font.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::Script; + using namespace GS::Render; + + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryLoadPicture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + Picture *p = f->graphic->LoadPicture(name); + __SQ_GETEND + __SQ_RETURNSAFEPTR(p, typetag_Picture) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryLoadRasterFont(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(base) + __SQ_GETSTRING(name) + RasterFont *font = new RasterFont; + if (!font) + return sq_throwerror(vm, "Failed to allocate raster font object."); + font->Load(*f->render, base, name); + __SQ_GETEND + __SQ_RETURNMANAGEDSAFEPTR(font, typetag_RasterFont) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryNewTexture(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + Texture *t = f->render->NewTexture(); + __SQ_RETURNSAFEPTR(t, typetag_Texture) +} +SQInteger ResourceFactoryLoadTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + Texture *t = f->render->LoadTexture(name); + if (!t) + return sq_throwerror(vm, String::Format("Texture '%s' not found.", name)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(t, typetag_Texture) +} +SQInteger ResourceFactoryLoadTextureEx(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + __SQ_GETBOOL(bypass_cache) + Texture *t = f->render->LoadTexture(name, asbool(bypass_cache)); + if (!t) + return sq_throwerror(vm, String::Format("Texture '%s' not found.", name)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(t, typetag_Texture) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryLoadShader(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + Render::Shader *s = f->render->LoadShader(name); + __SQ_GETEND + __SQ_RETURNSAFEPTR(s, typetag_Shader) +} +SQInteger ResourceFactoryLoadShaderEx(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + __SQ_GETBOOL(bypass_cache) + Render::Shader *s = f->render->LoadShader(name, asbool(bypass_cache)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(s, typetag_Shader) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryLoadGeometry(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + Render::Geometry *g = f->render->LoadGeometry(name); + __SQ_GETEND + __SQ_RETURNSAFEPTR(g, typetag_Geometry) +} +SQInteger ResourceFactoryLoadGeometryEx(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + __SQ_GETBOOL(bypass_cache) + Render::Geometry *g = f->render->LoadGeometry(name, asbool(bypass_cache)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(g, typetag_Geometry) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryLoadMaterial(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + Render::Material *m = f->render->LoadMaterial(name); + __SQ_GETEND + __SQ_RETURNSAFEPTR(m, typetag_Material) +} +SQInteger ResourceFactoryLoadMaterialEx(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + __SQ_GETBOOL(bypass_cache) + Render::Material *m = f->render->LoadMaterial(name, asbool(bypass_cache)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(m, typetag_Material) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryLoadSound(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(name) + Audio::Sound *s = f->audio->LoadSound(name); + __SQ_GETEND + __SQ_RETURNSAFEPTR(s, typetag_Sound) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger ResourceFactoryPurge(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(f, ResourceFactories, typetag_ResourceFactories) + uint purged = 0; + purged += f->graphic->PurgeCache(); + purged += f->render->PurgeCache(); +// purged += f->mixer->PurgeCache(); + __SQ_RETURNINT(purged) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterResourceFactoryBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Resource Factory + Desc: A resource factory caches all graphic and render resources used by a project. You can access your project resource factory from any script by using the global variable g_factory. + Type: ResourceFactory +#*/ + +/*# + Section: ResourceFactoryGeneral + Desc: Resource Factory General +#*/ + /*# + Func: ResourceFactoryPurge + Proto: int:ResourceFactory + Desc: Call this function to unload from memory all cached resources that are not currently in use. + Example: +local purged_count = ResourceFactoryPurge(g_factory) +print("Resource unloaded: " + purged_count) + #*/ + sq_register(vm, ResourceFactoryPurge, "ResourceFactoryPurge", _SC(".x")); + +/*# + Section: GraphicResourceFactory + Desc: Graphic Resources +#*/ + /*# + Func: ResourceFactoryLoadPicture + Proto: Picture:ResourceFactory,String name + Desc: Load a picture from a graphic resource factory, this function use the resource cache to prevent redundant loads of the same resource. + See: PictureLoad + #*/ + sq_register(vm, ResourceFactoryLoadPicture, "ResourceFactoryLoadPicture", _SC(".xs")); + +/*# + Section: RenderResourceFactory + Desc: Render Resources +#*/ + /*# + Func: ResourceFactoryLoadRasterFont + Proto: RasterFont:ResourceFactory,String name + Desc: Load a raster font from a resource factory. + #*/ + sq_register(vm, ResourceFactoryLoadRasterFont, "ResourceFactoryLoadRasterFont", _SC(".xss")); + + /*# + Func: ResourceFactoryNewTexture + Proto: Texture:ResourceFactory + Desc: Create a new texture from a resource factory. + #*/ + sq_register(vm, ResourceFactoryNewTexture, "ResourceFactoryNewTexture", _SC(".x")); + + /*# + Func: ResourceFactoryLoadShader + Proto: Shader:ResourceFactory,String name + Desc: Load a shader from a resource factory. + #*/ + sq_register(vm, ResourceFactoryLoadShader, "ResourceFactoryLoadShader", _SC(".xs")); + /*# + Func: ResourceFactoryLoadShaderEx + Proto: Shader:ResourceFactory,String name,bool bypass_cache + Desc: Load a shader from a resource factory, optionally bypassing the factory cache. + #*/ + sq_register(vm, ResourceFactoryLoadShaderEx, "ResourceFactoryLoadShaderEx", _SC(".xsb")); + + /*# + Func: ResourceFactoryLoadTexture + Proto: Texture:ResourceFactory,String name + Desc: Load a texture from a resource factory. + #*/ + sq_register(vm, ResourceFactoryLoadTexture, "ResourceFactoryLoadTexture", _SC(".xs")); + /*# + Func: ResourceFactoryLoadTextureEx + Proto: Texture:ResourceFactory,String name,bool bypass_cache + Desc: Load a texture from a resource factory, optionally bypassing the factory cache. + #*/ + sq_register(vm, ResourceFactoryLoadTextureEx, "ResourceFactoryLoadTextureEx", _SC(".xsb")); + + /*# + Func: ResourceFactoryLoadGeometry + Proto: Texture:ResourceFactory,String name + Desc: Load a geometry from a resource factory. + #*/ + sq_register(vm, ResourceFactoryLoadGeometry, "ResourceFactoryLoadGeometry", _SC(".xs")); + /*# + Func: ResourceFactoryLoadGeometryEx + Proto: Texture:ResourceFactory,String name,bool bypass_cache + Desc: Load a geometry from a resource factory, optionally bypassing the factory cache. + #*/ + sq_register(vm, ResourceFactoryLoadGeometryEx, "ResourceFactoryLoadGeometryEx", _SC(".xsb")); + + /*# + Func: ResourceFactoryLoadMaterial + Proto: Material:ResourceFactory,String name + Desc: Load a material from a resource factory. + #*/ + sq_register(vm, ResourceFactoryLoadMaterial, "ResourceFactoryLoadMaterial", _SC(".xs")); + + /*# + Func: ResourceFactoryLoadMaterialEx + Proto: Material:ResourceFactory,String name,bool bypass_cache + Desc: Load a material from a resource factory, optionally bypassing the factory cache. + #*/ + sq_register(vm, ResourceFactoryLoadMaterialEx, "ResourceFactoryLoadMaterialEx", _SC(".xsb")); + +/*# + Section: MixerResourceFactory + Desc: Mixer Resources +#*/ + /*# + Func: ResourceFactoryLoadSound + Proto: Sound:ResourceFactory,String name + Desc: Load a sound from a resource factory. + #*/ + sq_register(vm, ResourceFactoryLoadSound, "ResourceFactoryLoadSound", _SC(".xs")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/scene_binding.cpp b/include/modules/script_squirrel/legacy/scene_binding.cpp new file mode 100644 index 0000000..a1afd77 --- /dev/null +++ b/include/modules/script_squirrel/legacy/scene_binding.cpp @@ -0,0 +1,1744 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "scene3d/scene.h" + #include "scene3d/instance.h" + #include "scene3d/mlight.h" + #include "scene3d/mobject.h" + #include "scene3d/mcamera.h" + #include "scene3d/mtrigger.h" + #include "scene3d/mconstraint.h" + #include "scene3d/group.h" + #include "physic/physic_world.h" + #include "core/renderer.h" + #include "core/resource_factories.h" + #include "script/scripted_object.h" + #include "script/script_unit.h" + #include "metafile/nml_object.h" + #include "tools/scene_merge_object_list.h" + #include "core/cached_graphic_resource_factory.h" + + using namespace GS; + using namespace GS::S3D; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger GetSceneOrInstance(HSQUIRRELVM vm, int idx, Scene **scene, Instance **instance) +{ + *scene = NULL; + *instance = NULL; + + CObjectType type; + if (!CObject::GetType(vm, idx, type)) + return sq_throwerror(vm, "Invalid object, expected scene or instance."); + + switch (type) + { + case typetag_Scene3d: + CObject::Get(vm, idx, (void **)scene, typetag_Scene3d); + break; + + case typetag_Item: + { + MItem *item; + CObject::Get(vm, idx, (void **)&item, typetag_Item); + + if (item->GetItemType() != Type_Instance) + return sq_throwerror(vm, "Expected scene or instance."); + + *instance = (Instance *)item; + } + break; + + default: + return sq_throwerror(vm, "Expected scene or instance."); + } + if (!*scene && !*instance) + return sq_throwerror(vm, "Scene/instance object is null."); + + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +#define __SQ_GETSCENEORINSTANCE(__S, __I) \ + Scene *__S; \ + Instance *__I; \ + if (GetSceneOrInstance(vm, __SQ_STACKPOS, &__S, &__I) == -1) \ + return -1; \ + __SQ_GETUPDATESTACK +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SceneGetGroupList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + sq_newarray(vm, 0); + ListForeachPtr(Group *, g, scene->GetGroupList()) + { + CObject::Push(vm, (void *)g, typetag_Group); + sq_arrayappend(vm, -2); + } + return 1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SceneGroupActivate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(g, Group, typetag_Group) + __SQ_GETBOOL(v) + __SQ_GETEND + s->GroupMembersSetActive(g, asbool(v)); + __SQ_RETURN +} +SQInteger SceneSetupItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(i, MItem, typetag_Item) + __SQ_GETEND + i->Setup(s->physic_world); + __SQ_RETURN +} +SQInteger SceneForceUpdateMassShapePhysicItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(i, MItem, typetag_Item) + __SQ_GETEND + i->ForceUpdateMassShapePhysic(s->physic_world); + __SQ_RETURN +} +SQInteger SceneRenderSetup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETEND + s->RenderSetup(f, false); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SceneResetClock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(s, Scene, typetag_Scene3d) + s->GetClock()->Reset(); + __SQ_RETURN +} +SQInteger SceneSetFixedDeltaFrame(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETFLOAT(scale) + __SQ_GETEND + s->GetClock()->SetFixedDeltaFramef(scale); + __SQ_RETURN +} +SQInteger SceneSetClockScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Scene, typetag_Scene3d) + __SQ_GETFLOAT(scale) + __SQ_GETEND + s->GetClock()->SetScalef(scale); + __SQ_RETURN +} +SQInteger SceneGetClockScale(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(s, Scene, typetag_Scene3d) + __SQ_RETURNFLOAT(s->GetClock()->GetScalef()) +} +SQInteger SceneGetClock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(s, Scene, typetag_Scene3d) + __SQ_RETURNFLOAT(s->GetClock()->Getf()) +} +//------------------------------------------------------------------------------ + +/* +static void MergePhysicShape(MItem *to, MItem *from) +{ + if (!from->physic_item) + return; + + ListForeachPtr(nPhysicShape *, shape, from->physic_item->GetShapeList()) + { + nPhysicShape *new_shape = to->physic_item->AddShape(); + new_shape->SetMatrix(from->GetBaseItem()->GetMatrix() * shape->GetMatrix()); + + switch (shape->GetType()) + { + case nPhysicShape::TypeBox: + case nPhysicShape::TypeCapsule: + case nPhysicShape::TypeCone: + case nPhysicShape::TypeSphere: + new_shape->Set(shape->GetType(), shape->dimensions); + break; + + case nPhysicShape::TypeConvex: + case nPhysicShape::TypeMesh: + new_shape->Set(shape->GetType(), shape->path); + break; + } + } + + to->physic_item->SetPhysicMode(from->physic_item->GetPhysicMode()); +} +*/ +SQInteger SceneSetMotion(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSCENEORINSTANCE(scene, instance) + __SQ_GETSTRING(name) + __SQ_GETFLOAT(blend) + Automation::SourceGroup *group = NULL; + if (scene) + scene->SetMotion(name, &group, blend); + else instance->instance_group->SetMotion(name, &group, blend); + __SQ_GETEND + __SQ_RETURNMANAGEDSAFEPTR(group, typetag_AutomationSourceGroup) +} + +SQInteger SceneSetMotionAdd(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSCENEORINSTANCE(scene, instance) + __SQ_GETSTRING(name) + __SQ_GETFLOAT(blend) + Automation::SourceGroup *group = NULL; + if (scene) + scene->SetMotion(name, &group, blend, Automation::Player::SourceAdd); + else instance->instance_group->SetMotion(name, &group, blend, Automation::Player::SourceAdd); + __SQ_GETEND + __SQ_RETURNMANAGEDSAFEPTR(group, typetag_AutomationSourceGroup) +} + +SQInteger SceneGetFileName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNSTRING(scene->name.CutFilePath().toUtf8()) +} +SQInteger SceneGetFilePath(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNSTRING(scene->name.CutFileName().toUtf8()) +} + +SQInteger SceneSetGlobal(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->SetAsScriptGlobalScene(scene->GetVM()); + __SQ_RETURN +} + +SQInteger SceneGetAmbientIntensity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNFLOAT(scene->ambient_intensity) +} + +SQInteger SceneSetAmbientIntensity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETFLOAT(i) + __SQ_GETEND + scene->ambient_intensity = i; + __SQ_RETURN +} + +SQInteger SceneGetAmbientColor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNVECTOR(scene->ambient_color) +} + +SQInteger SceneSetAmbientColor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETVECTORTO(scene->ambient_color, scene) + __SQ_GETEND + __SQ_RETURN +} + +SQInteger SceneGetBackgroundColor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNVECTOR(scene->background_color) +} + +SQInteger SceneSetBackgroundColor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETVECTORTO(scene->background_color, scene) + __SQ_GETEND + __SQ_RETURN +} + +SQInteger SceneEnd(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->flags.Set(Scene::FlagEnd); + __SQ_RETURN +} + +SQInteger SceneRaytraceTriggerList(HSQUIRRELVM vm) +{ + Scene *scene; + if (!CObject::Get(vm, -4, (void **)&scene, typetag_Scene3d)) + return -1; + + Vector4 s, d; + GetVector(vm, -3, s); + GetVector(vm, -2, d); + + float l; + sq_getfloat(vm, -1, &l); + sq_pop(vm, 4); + + MItem *hit = NULL; + if (scene) + hit = (MItem *)scene->RaytraceTriggerList(s, d, l); + CObject::Push(vm, (void *)hit, typetag_Item); + return 1; +} + +SQInteger ScenePhysicAllocateCollisionNode(HSQUIRRELVM vm) +{ __ERR__(__LOG__ << "ScenePhysicAllocateCollisionNode is obsolete.\n", 0)} + +SQInteger ScenePhysicEnableDeactivation(HSQUIRRELVM vm) +{ + return 0; +} + +SQInteger SceneSetItemStatic(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETBOOL(v) + __SQ_GETEND + scene->SetItemStatic(item, asbool(v)); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +#define __SQ_GETSCENESCRIPTOBJECT(__SRC) GS::Script::ScriptedObject *scripted_object = __SRC->scripted_object; if (!scripted_object) return sq_throwerror(vm, "No script system in scene!"); + +SQInteger SceneGetScriptInstance(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSCENESCRIPTOBJECT(scene) + if (!scripted_object->GetUnitList().GetCount()) + return sq_throwerror(vm, "No script unit"); + Script::SquirrelObject *o = (Script::SquirrelObject *)scripted_object->GetUnitList()[0]->Self(); + __SQ_RETURNOBJECT(o->object); +} +SQInteger SceneGetScriptInstanceFromClass(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(_class) + __SQ_GETSCENESCRIPTOBJECT(scene) + + Script::Unit *_unit = 0; + ListForeachPtr(Script::Unit *, unit, scripted_object->GetUnitList()) + if (unit->script_class == _class) + { + _unit = unit; + break; + } + + __SQ_GETEND + + if (_unit) + { + if (!_unit->IsOpen()) + return sq_throwerror(vm, "Script unit is not open"); + + __SQ_RETURNOBJECT(((Script::SquirrelObject *)_unit->Self())->object); + } + return sq_throwerror(vm, "Script unit not found"); +} +SQInteger SceneSetScript(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(script_file) + __SQ_GETSTRING(script_class) + __SQ_GETSCENESCRIPTOBJECT(scene) + if (Script::Unit *unit = scripted_object->GetUnitList().GetCount() ? scripted_object->GetUnitList()[0] : scripted_object->AddUnit(scripted_object->NewUnit())) + { + unit->script_file = script_file; + unit->script_class = script_class; + } + __SQ_GETEND + __SQ_RETURN +} +SQInteger SceneRemoveAllScripts(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSCENESCRIPTOBJECT(scene) + + scripted_object->RemoveAllUnit(); + + __SQ_GETEND + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +SQInteger ScenePreloadResources(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETSTRING(path) + bool r = Scene::PreloadResources(*f->render, path); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} + +//----------------------------------------------------------------------------- +SQInteger SceneFromNML(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(path) + Group *group = NULL; + if (!scene->FromMetaFileStoreGroup(path, &group)) + return sq_throwerror(vm, "Failed to load scene."); + scene->InstanceSetup(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(group, typetag_Group) +} +SQInteger SceneFromNMLStoreGroup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(path) + __SQ_GETINT(flag) + Group *group = NULL; + if (!scene->FromMetaFileStoreGroup(path, &group, flag)) + return sq_throwerror(vm, "Failed to load scene."); + scene->InstanceSetup(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(group, typetag_Group) +} +//----------------------------------------------------------------------------- + +SQInteger SceneDeleteGroup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(group, Group, typetag_Group) + __SQ_GETEND + scene->DeleteGroupAndMembers(group); + __SQ_RETURN +} + +SQInteger SceneReset(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->Reset(); + __SQ_RETURN +} + +SQInteger SceneSetPhysicContactSolverIteration(HSQUIRRELVM vm) +{ return 0; } + +SQInteger SceneSetPhysicConstraintSolverIteration(HSQUIRRELVM vm) +{ return 0; } + +SQInteger SceneRecordLocation(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->RecordAllItemLocation(); + __SQ_RETURN +} + +SQInteger SceneGetPhysicFrequency(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNFLOAT(scene->physic_world ? 1.f / scene->physic_world->GetTimestep() : 0.f) +} + +SQInteger SceneSetPhysicFrequency(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETFLOAT(timestep) + __SQ_GETEND + if (scene->physic_world) + scene->physic_world->SetTimestep(1.f / timestep); + __SQ_RETURN +} + +SQInteger SceneSetGravity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETVECTOR(g) + __SQ_GETEND + if (scene->physic_world) + scene->physic_world->SetGravity(g); + __SQ_RETURN +} + +SQInteger SceneSave(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(path) + bool r = NML::SaveToFile(*scene, path); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +//------------------------------------------------------------------------------ + +SQInteger SceneFindConstraint(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSCENEORINSTANCE(scene, instance) + __SQ_GETSTRING(name) + __SQ_GETEND + MConstraint *c = scene->FindItemByType (name); + if (!c) + return sq_throwerror(vm, String::Format("Constraint '%s' not found.", name)); + __SQ_RETURNSAFEPTR(c, typetag_Constraint) +} +SQInteger SceneFindGroup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSCENEORINSTANCE(scene, instance) + __SQ_GETSTRING(name) + Group *group = scene ? scene->FindGroup(name) : instance->instance_group->GetGroup(name); + if (!group) + return sq_throwerror(vm, String::Format("Group '%s' not found.", name)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(group, typetag_Group) +} +SQInteger SceneFindItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSCENEORINSTANCE(scene, instance) + __SQ_GETSTRING(name) + MItem *item = scene ? scene->Item(name) : instance->instance_group->Item(name); + if (!item) + return sq_throwerror(vm, String::Format("Item '%s' not found.", name)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(item, typetag_Item) +} +SQInteger SceneFindItemChild(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSCENEORINSTANCE(scene, instance) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETSTRING(name) + MItem *child = scene ? scene->Item(name, item) : NULL; + if (!child) + return sq_throwerror(vm, String::Format("Child item '%s' not found", name)); + __SQ_GETEND + __SQ_RETURNSAFEPTR(child, typetag_Item) +} +//------------------------------------------------------------------------------ + +SQInteger SceneDeleteContent(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->Clear(true); + __SQ_RETURN +} + +SQInteger SceneFlushDeletionQueue(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->ProcessItemRemovalQueue(); + __SQ_RETURN +} + +SQInteger SceneSetRenderless(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETBOOL(v) + __SQ_GETEND + scene->flags.Raise(Scene::FlagRenderless, asbool(v)); + __SQ_RETURN +} +SQInteger ScenePushRenderable(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETEND + scene->PushRenderable(*renderer); + __SQ_RETURN +} +SQInteger SceneRenderUI(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETEND + scene->RenderUI(*renderer); + __SQ_RETURN +} + +SQInteger SceneUpdate(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->Update(); + __SQ_RETURN +} + +SQInteger SceneRegisterAsPropertyCallback(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(renderer, Renderer, typetag_Renderer) + __SQ_GETEND + renderer->SetEnvironmentInterface(scene->irenderer_environment); + __SQ_RETURN +} + +SQInteger ScenePrintItemList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + scene->DumpContentToLog(); + __SQ_RETURN +} + +SQInteger SceneAddObject(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + MObject *o = new MObject; + if (!o) + return sq_throwerror(vm, String::Format("Failed to allocate object '%s'.", name)); + o->name = name; + scene->AddItem(o, true); + o->Setup(scene->physic_world); + o->Reset(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(o, typetag_Object); +} + +SQInteger SceneDeleteObject(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(object, MObject, typetag_Object) + __SQ_GETEND + scene->QueueItemRemoval(object); + __SQ_RETURN +} + +SQInteger SceneAddTrigger(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + MTrigger *t = new MTrigger; + if (!t) + return sq_throwerror(vm, String::Format("Failed to allocate trigger '%s'.", name)); + t->name = name; + scene->AddItem(t, true); + t->Setup(scene->physic_world); + t->Reset(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(t, typetag_Trigger); +} + +SQInteger SceneDeleteTrigger(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(trigger, MTrigger, typetag_Trigger) + __SQ_GETEND + scene->QueueItemRemoval(trigger); + __SQ_RETURN +} + +SQInteger SceneAddCamera(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + MCamera *c = new MCamera; + if (!c) + return sq_throwerror(vm, String::Format("Failed to allocate camera '%s'.", name)); + c->name = name; + scene->AddItem(c, true); + c->Setup(scene->physic_world); + c->Reset(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(c, typetag_Camera); +} + +SQInteger SceneGetCurrentCamera(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNSAFEPTR((MCamera *)scene->current_camera, typetag_Camera) +} +SQInteger SceneSetCurrentCamera(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(camera, MCamera, typetag_Camera) + __SQ_GETEND + scene->current_camera = camera; + __SQ_RETURN +} + +SQInteger SceneAddLight(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + MLight *l = new MLight; + if (!l) + return sq_throwerror(vm, String::Format("Failed to create light '%s'.", name)); + l->name = name; + scene->AddItem(l, true); + l->Setup(scene->physic_world); + l->Reset(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(l, typetag_Light); +} + +SQInteger SceneDuplicateItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETEND + __SQ_RETURNSAFEPTR(scene && item ? scene->DuplicateItem(item) : NULL, typetag_Item) +} + +SQInteger SceneMergeItems(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + __SQ_GETSAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETINT(nb_item) + + if (nb_item > 0) + { + SharedList merge_list; + + // get the list of item + sq_pushnull(vm);//null iterator + for(int i=0; igraphic, out_i, out_g); + + if(out_g.IsValid()) + { + // Save merged geometry to disk. + String merged_name(scene->name.CutFileName()+name+String(".nmg")); + NML::SaveToFile(*out_g, merged_name); + + // Set geometry and setup merged object. + if (MObject *object = (MObject *)out_i.c_ptr()) + { + object->geometry = merged_name; + object->name = name; + object->RenderSetup(f); + __SQ_RETURNSAFEPTR(out_i.c_ptr(), typetag_Item) + } + } + } + } + __SQ_RETURNSAFEPTR(NULL, typetag_Item) +} + +SQInteger SceneGetItemList(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSCENEORINSTANCE(scene, instance) + __SQ_GETEND + + const SharedList *list = NULL; + if (scene) + list = &scene->GetItemList(); + else + list = &instance->instance_group->GetItemList(); + + sq_newarray(vm, 0); + ListForeachPtr(MItem *, i, *list) + { + // Skip items with no base item (e.g. const raints): they are not + // positionable, and exposing them as typetag_Item makes scripts crash + // when calling ItemGetWorldPosition/GetMatrix (MConstraint::GetBaseItem + // returns NULL -> null Item::GetMatrix() -> access violation -> paf memory error). + if (!i->GetBaseItem()) + continue; + + CObject::Push(vm, (void *)i, typetag_Item); + sq_arrayappend(vm, -2); + } + return 1; +} + +SQInteger SceneGetItemChildrenList(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETEND + + sq_newarray(vm, 0); + if (scene) + ListForeachPtr(MItem *, i, scene->GetItemList()) + if (i->GetBaseItem()->GetParent() == item->GetBaseItem()) + { + CObject::Push(vm, (void *)i, typetag_Item); + sq_arrayappend(vm, -2); + } + return 1; +} + +SQInteger SceneDeleteItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETEND + scene->QueueItemRemoval(item); + __SQ_RETURN +} + +SQInteger SceneDeleteLight(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(name) + scene->QueueItemRemoval(scene->FindItemByType (name)); + __SQ_GETEND + __SQ_RETURN +} + +SQInteger SceneDeleteAllLights(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + ListForeachPtr(MItem *, i, scene->GetItemList()) + if (i->GetItemType() == Type_Light) + scene->QueueItemRemoval(i); + __SQ_RETURN +} +SQInteger ItemSetActive(HSQUIRRELVM vm) { + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETBOOL(active) + __SQ_GETEND + item->mitem_flags.Raise(MItem::Flag_IsActive, active); + __SQ_RETURN +} +SQInteger SceneCollisionRaytrace(HSQUIRRELVM vm) +{ + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETVECTOR(from) + __SQ_GETVECTOR(direction) + __SQ_GETINT(mask) + __SQ_GETINT(shape_mask) + __SQ_GETFLOAT(max_distance) + __SQ_GETEND + + if (!scene->physic_world) + return sq_throwerror(vm, "No collision system in scene."); + + PhysicTrace result; + bool hit = scene && scene->physic_world->Raytrace(from, direction, result, mask, shape_mask, max_distance); + + sq_newtable(vm); + + sq_pushstring(vm, "hit", 3); + sq_pushbool(vm, hit); + sq_newslot(vm, -3, false); + + if (hit) + { + sq_pushstring(vm, "shape", 5); + CObject::Push(vm, (void *)result.s, typetag_ColShape); + sq_newslot(vm, -3, false); + + sq_pushstring(vm, "item", 4); + CObject::Push(vm, (void *)((MItem *)result.i->GetUserPointer()), typetag_Item); + sq_newslot(vm, -3, false); + + sq_pushstring(vm, "material", 8); + sq_pushstring(vm, result.m, result.m.Len()); + sq_newslot(vm, -3, false); + + sq_pushstring(vm, "p", 1); + PushVector(vm, result.p); + sq_newslot(vm, -3, false); + + sq_pushstring(vm, "n", 1); + PushVector(vm, result.n); + sq_newslot(vm, -3, false); + + sq_pushstring(vm, "d", 1); + sq_pushfloat(vm, Vector4::Dist(from, result.p)); + sq_newslot(vm, -3, false); + } + return 1; +} + +SQInteger SceneSetFog(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETBOOL(enable) + __SQ_GETCOLOR(color) + __SQ_GETFLOAT(n) + __SQ_GETFLOAT(f) + __SQ_GETEND + scene->fog_color = color; + scene->fog_near = enable ? n : 0; + scene->fog_far = enable ? f : 0; + __SQ_RETURN +} + +SQInteger SceneGetTimeOfDay(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNFLOAT(scene->time_of_day) +} +SQInteger SceneSetTimeOfDay(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETFLOAT(t) + __SQ_GETEND + scene->time_of_day = t; + __SQ_RETURN +} + +SQInteger SceneSetFlagDebugPhysic(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETBOOL(enable) + __SQ_GETEND + scene->flags.Raise(GS::S3D::Scene::FlagDebugPhysics, enable); + __SQ_RETURN +} + +SQInteger SceneSetSkyShader(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(s) + __SQ_GETEND + scene->skybox_shader = s; + __SQ_RETURN +} +SQInteger SceneSetSkyLayer(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSTRING(s) + __SQ_GETINT(n) + __SQ_GETEND + if ((n < 0) || (n > 1)) + return sq_throwerror(vm, "Invalid sky layer index."); + scene->skybox_layer[n] = s; + __SQ_RETURN +} + +SQInteger SceneGetFogColor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNCOLOR(scene->fog_color) +} + +SQInteger SceneGetFogNear(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNFLOAT(scene->fog_near) +} + +SQInteger SceneGetFogFar(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_RETURNFLOAT(scene->fog_far) +} + +//------------------------------------------------------------------------------ +SQInteger SceneItemActivate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETBOOL(active) + __SQ_GETEND + scene->QueueItemActivation(item, asbool(active)); + __SQ_RETURN +} +SQInteger SceneItemActivateHierarchy(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETSAFEPTR(item, MItem, typetag_Item) + __SQ_GETBOOL(active) + __SQ_GETEND + scene->QueueItemActivation(item, asbool(active), true); + __SQ_RETURN +} +//------------------------------------------------------------------------------ +SQInteger SceneProcessItemActivationQueue(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene3d) + __SQ_GETEND + scene->ProcessItemActivationQueue(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//----------------------------------------------h,v +void RegisterSceneBinding(HSQUIRRELVM vm) +//---------------------------------------------- +{ +/*# + Topic: Scene + Related: Camera,Object,Light,Trigger,Item + Type: Scene + Type: Record +#*/ + +/*# + Section: SceneClock + Desc: Clock +#*/ + /*# + Func: SceneResetClock + Proto: void:Scene + Desc: Reset engine clock. This function can be used to prevent the engine from taking a large clock step after a long script operation has been run. + Example: +function LoadLevelBlock(level_scene, block_path) +{ + // Import the level block scene into the level_scene. + SceneLoad(level_scene, block_path) + + // The load operation is known to take some time, + // so in order to prevent clock-dependent components + // from going nuts, we reset the level scene clock. + SceneResetClock(level_scene) +} + #*/ + sq_register(vm, SceneResetClock, "SceneResetClock", _SC(".x")); + /*# + Func: SceneSetClockScale + Proto: void:Scene,float + Desc: Set engine clock scale. All clock dependent components in the engine are affected by this scale. + #*/ + sq_register(vm, SceneSetClockScale, "SceneSetClockScale", _SC(".xn")); + /*# + Func: SceneGetClockScale + Proto: float:Scene + Desc: Get engine clock scale. + #*/ + sq_register(vm, SceneGetClockScale, "SceneGetClockScale", _SC(".x")); + /*# + Func: SceneSetFixedDeltaFrame + Proto: void:Scene,float + Desc: Force a constant fixed delta frame value. Note: All clock dependent components will become frame rate dependent. + Example: SceneSetFixedDeltaFrame(scene, 1.0 / 60.0) // Lock dt_clock to 60 frame per second (1/60th between 2 frames). + #*/ + sq_register(vm, SceneSetFixedDeltaFrame, "SceneSetFixedDeltaFrame", _SC(".xn")); + +/*# + Section: SceneMotion + Desc: Motion +#*/ + /*# + Func: SceneSetMotion + Proto: AnimationSourceGroup:Scene,string name,float blend + Desc: Set motion on all scene items, specify the blend duration, stop all current animation sources. + #*/ + sq_register(vm, SceneSetMotion, "SceneSetMotion", _SC(".xsn")); + /*# + Func: SceneSetMotionAdd + Proto: AnimationSourceGroup:Scene,string name,float blend + Desc: Set motion on all scene items, specify the blend duration, current sources are not stopped. + #*/ + sq_register(vm, SceneSetMotionAdd, "SceneSetMotionAdd", _SC(".xsn")); + +/*# + Section: SceneIO + Desc: I/O +#*/ + /*# + Func: ScenePreloadResources + Proto: bool:String path, RenderResourceFactory factory + Desc: Load all scene resources and their dependencies.
+ As long as the render factory cache is not explicitly emptied, all subsequent load requests will return a cached resource instance. + This function can be used to implement streaming by preloading scene instance resources and instantiating/deinstantiating level blocks on the fly without requiring a complete load. + + Example: +if (ScenePreloadResources("level/block_dark_street.nms", g_factory)) + print("Dark street resources loaded."); + #*/ + sq_register(vm, ScenePreloadResources, "ScenePreloadResources", _SC(".xs")); + /*# + Func: SceneLoad + Proto: bool:Scene,string + Desc: Append a scene to this scene, returns true on success, false otherwise. + See: SceneLoadAndStoreGroup + #*/ + sq_register(vm, SceneFromNML, "SceneLoad", _SC(".xs")); + sq_register(vm, SceneFromNML, "SceneFromFile", _SC(".xs")); + sq_register(vm, SceneFromNML, "SceneFromNML", _SC(".xs")); + /*# + Func: SceneLoadAndStoreGroup + Proto: Group:Scene scene_to_import_to,string path,ImportFlag import_flag + Desc: Append a scene to this scene, store all appended content (item, light, group, etc...) in a group. + + Example: +class LevelScene +{ + diablo_ai = 0 + diablo_fist = 0 + + function OnSetup(scene) + { + // Import the Diablo AI character into this scene. + diablo_ai = SceneLoadAndStoreGroup(scene, "enemy/ai/diablo.nms") + + // Grab item 'fist' from this specific copy of the Diablo scene. + diablo_fist = GroupFindItem(diablo_ai, "fist") + } +} + #*/ + sq_register(vm, SceneFromNMLStoreGroup, "SceneLoadAndStoreGroup", _SC(".xsi")); + sq_register(vm, SceneFromNMLStoreGroup, "SceneFromFileStoreGroup", _SC(".xsi")); + sq_register(vm, SceneFromNMLStoreGroup, "SceneFromNMLStoreGroup", _SC(".xsi")); + /*# + Func: SceneSave + Proto: bool:Scene,string + Desc: Save scene content to file. Returns true on success, false otherwise.
+ The created scene can be directly opened in the editor provided that it has been saved in the same directory as the source scene. If not, resource path remapping will be required. + #*/ + sq_register(vm, SceneSave, "SceneSave", _SC(".xs")); + +/*# + Section: SceneManagement + Desc: Management +#*/ + /*# + Func: SceneRenderSetup + Proto: void:Scene,ResourceFactory + Desc: Setup all scene render resources. + #*/ + sq_register(vm, SceneRenderSetup, "SceneRenderSetup", _SC(".xx")); + /*# + Func: SceneDeleteItem + Proto: void:Scene,item + Desc: Delete an item from scene. + #*/ + sq_register(vm, SceneDeleteItem, "SceneDeleteItem", _SC(".xx")); + /*# + Func: SceneEnd + Proto: void:Scene + Desc: Signal scene end. Calling this function when executing or previewing a scene will exit the viewer. + See: ProjectEnd + #*/ + sq_register(vm, SceneEnd, "SceneEnd", _SC(".x")); + /*# + Func: SceneSetGlobal + Proto: void:Scene + Desc: Assign a scene to the script VM global variable g_scene. The engine does this automatically before calling scene and item callbacks. + #*/ + sq_register(vm, SceneSetGlobal, "SceneSetGlobal", _SC(".x")); + + /*# + Func: SceneGetScriptInstance + Proto: instance:Scene + Desc: Return the script instance for a scene. The scene first script unit instance is returned. + See: SceneGetScriptInstanceFromClass + + Example: +local instance = SceneGetScriptInstance(g_scene) + +// Instance can be used to call the script assigned to the scene. +instance->TurnLightOn() + #*/ + sq_register(vm, SceneGetScriptInstance, "SceneGetScriptInstance", _SC(".x")); + /*# + Func: SceneGetScriptInstanceFromClass + Proto: Instance:Scene scene,string class_name + Desc: Return the script instance of a specific script for a scene. + + Example: +// Get the scene script instance of class SceneLightManager. +local instance = SceneGetScriptInstanceFromClass(g_scene, "SceneLightManager") + +// Instance can be used to call the SceneLightManager instance assigned to the scene. +instance->TurnLightOn() + #*/ + sq_register(vm, SceneGetScriptInstanceFromClass, "SceneGetScriptInstanceFromClass", _SC(".xs")); + + /*# + Func: SceneSetScript + Proto: void:Scene scene,string script_path,string script_class + Desc: Set the scene script file and class to instantiate on the scene script unit. Current script unit settings will be overwritten. + #*/ + sq_register(vm, SceneSetScript, "SceneSetScript", _SC(".xss")); + /*# + Func: SceneRemoveAllScripts + Proto: void:Scene scene + Desc: remove all scripts from this scene. + #*/ + sq_register(vm, SceneRemoveAllScripts, "SceneRemoveAllScripts", _SC(".x")); + + /*# + Func: SceneGetFileName + Proto: String:Scene + Desc: Return the scene file name, without the path. + See: SceneGetFilePath + #*/ + sq_register(vm, SceneGetFileName, "SceneGetFileName", _SC(".x")); + /*# + Func: SceneGetFilePath + Proto: String:Scene + Desc: Return the scene file path. + See: SceneGetFileName + #*/ + sq_register(vm, SceneGetFilePath, "SceneGetFilePath", _SC(".x")); + /*# + Func: SceneReset + Proto: void:Scene + Desc: Reset a scene object. Note: All items are move back to their default transformation if recorded. + See: SceneRecordLocation + #*/ + sq_register(vm, SceneReset, "SceneReset", _SC(".x")); + /*# + Func: SceneUpdate + Proto: void:Scene + Desc: Update scene, run all logic, physic and call script callbacks. + #*/ + sq_register(vm, SceneUpdate, "SceneUpdate", _SC(".x")); + /*# + Func: SceneSetRenderless + Proto: void:Scene,bool + Desc: Controls automatic rendering of the scene. If a scene is renderless it is up to the user to implement its rendering code. + See: ScenePushRenderable, RendererRenderQueue, RendererRenderQueueReset, SceneRegisterAsPropertyCallback + + Example: +class RenderLessScene +{ + function OnSetup(scene) + { + // Set the scene to be renderless. + SceneSetRenderless(scene, true) + } + + function OnRender(scene) + { + // Register the scene as the renderer property provider. + // Such properties as: ambient color, skybox and light rig are passed through this provider. + SceneRegisterAsPropertyCallback(scene, g_render) + + // Push scene renderable to the renderer. + ScenePushRenderable(scene, g_render) + + // Render renderable. + RendererRenderQueue(g_render) + + // Reset renderable so that it does not get drawn by the next render call. + RendererRenderQueueReset(g_render) + } +} + #*/ + sq_register(vm, SceneSetRenderless, "SceneSetRenderless", _SC(".xb")); + /*# + Func: ScenePushRenderable + Proto: void:Scene,Renderer + Desc: Push the scene renderable onto the renderer render queue. + #*/ + sq_register(vm, ScenePushRenderable, "ScenePushRenderable", _SC(".xx")); + /*# + Func: SceneRenderUI + Proto: void:Scene,Renderer + Desc: Render the ui of the scene. + #*/ + sq_register(vm, SceneRenderUI, "SceneRenderUI", _SC(".xx")); + + /*# + Func: SceneRecordLocation + Proto: void:Scene + Desc: For each item, record the current transformation as the default transformation. The default transformation is used to move items to their original transformation when a scene reset is performed. + See: SceneReset + #*/ + sq_register(vm, SceneRecordLocation, "SceneRecordLocation", _SC(".x")); + + /*# + Func: SceneSetItemStatic + Proto: void:Scene,Item,bool + Desc: Flag item as static. The item will be stored in a spatial structure such as a quadtree with other static items to improve culling performance. + Note: If a static item is moved culling errors will happen. + #*/ + sq_register(vm, SceneSetItemStatic, "SceneSetItemStatic", _SC(".xxb")); + + /*# + Func: SceneDeleteContent + Proto: void:Scene + Desc: Delete all scene content. + #*/ + sq_register(vm, SceneDeleteContent, "SceneDeleteContent", _SC(".x")); + /*# + Func: SceneFlushDeletionQueue + Proto: void:Scene + Desc: Immediately delete all items marked for deletion. + #*/ + sq_register(vm, SceneFlushDeletionQueue, "SceneFlushDeletionQueue", _SC(".x")); + + /*# + Func: SceneGetCurrentCamera + Proto: camera:scene + Desc: Get scene current camera. + #*/ + sq_register(vm, SceneGetCurrentCamera, "SceneGetCurrentCamera", _SC(".x")); + /*# + Func: SceneSetCurrentCamera + Proto: void:scene,camera + Desc: Set camera as scene current camera. + #*/ + sq_register(vm, SceneSetCurrentCamera, "SceneSetCurrentCamera", _SC(".xx")); + + /*# + Func: SceneAddCamera + Proto: camera:scene,string name + Desc: Create a new camera. + #*/ + sq_register(vm, SceneAddCamera, "SceneAddCamera", _SC(".xs")); + /*# + Func: SceneAddLight + Proto: Light:Scene,string name + Desc: Add a new light to scene. + #*/ + sq_register(vm, SceneAddLight, "SceneAddLight", _SC(".xs")); + /*# + Func: SceneDeleteLight + Proto: void:Scene,Light + Desc: Delete light from scene. + #*/ + sq_register(vm, SceneDeleteLight, "SceneDeleteLight", _SC(".xs")); + /*# + Func: SceneDeleteAllLights + Proto: void:Scene + Desc: Delete all lights from scene. + #*/ + sq_register(vm, SceneDeleteAllLights, "SceneDeleteAllLights", _SC(".x")); + /*# + Func: SceneAddObject + Proto: Object:Scene,string name + Desc: Add a new object to scene. + #*/ + sq_register(vm, SceneAddObject, "SceneAddObject", _SC(".xs")); + /*# + Func: SceneDeleteObject + Proto: void:Scene,Object + Desc: Delete object from scene. + #*/ + sq_register(vm, SceneDeleteObject, "SceneDeleteObject", _SC(".xx")); + /*# + Func: SceneAddTrigger + Proto: Trigger:Scene,string name + Desc: Add a new trigger to scene. + #*/ + sq_register(vm, SceneAddTrigger, "SceneAddTrigger", _SC(".xs")); + /*# + Func: SceneDeleteTrigger + Proto: void:Scene,Trigger + Desc: Delete trigger from scene. + #*/ + sq_register(vm, SceneDeleteTrigger, "SceneDeleteTrigger", _SC(".xx")); + + /*# + Func: SceneGetGroupList + Proto: array:Scene + Desc: Return an array containing all scene groups. + #*/ + sq_register(vm, SceneGetGroupList, "SceneGetGroupList", _SC(".x")); + /*# + Func: SceneGroupActivate + Proto: void:Scene,Group,bool active + Desc: Set group member items active flag, effectively stops all physic, collision and display operations from happening on all group items. + #*/ + sq_register(vm, SceneGroupActivate, "SceneGroupActivate", _SC(".xxb")); + /*# + Func: SceneItemActivate + Proto: void:Scene,Item,bool active + Desc: Set item active flag, when set to false this will stop all physic, collision and display operations from happening for this item. + #*/ + sq_register(vm, SceneItemActivate, "SceneItemActivate", _SC(".xxb")); + /*# + Func: SceneItemActivateHierarchy + Proto: void:Scene,Item,bool active + Desc: Set item active flag on an item and its children recursively. + #*/ + sq_register(vm, SceneItemActivateHierarchy, "SceneItemActivateHierarchy", _SC(".xxb")); + /*# + Func: SceneProcessItemActivationQueue + Proto: void:Scene + Desc: process the SceneProcessItemActivationQueue. + #*/ + sq_register(vm, SceneProcessItemActivationQueue, "SceneProcessItemActivationQueue", _SC(".x")); + /*# + Func: ItemSetActive + Proto: void:Scene,Item,bool active + Desc: Set item active flag, when set to false this will stop all physic, collision and display operations from happening for this item. + #*/ + sq_register(vm, ItemSetActive, "ItemSetActive", _SC(".xb")); + +/*# + Section: SceneEnvironment + Desc: Environment +#*/ + /*# + Func: SceneGetAmbientIntensity + Proto: float:Scene + Desc: Get the scene ambient intensity. + #*/ + sq_register(vm, SceneGetAmbientIntensity, "SceneGetAmbientIntensity", _SC(".x")); + /*# + Func: SceneSetAmbientIntensity + Proto: void:Scene,float + Desc: Set the scene ambient intensity. + #*/ + sq_register(vm, SceneSetAmbientIntensity, "SceneSetAmbientIntensity", _SC(".xn")); + /*# + Func: SceneGetAmbientColor + Proto: Vector:Scene + Desc: Get the scene ambient color. + #*/ + sq_register(vm, SceneGetAmbientColor, "SceneGetAmbientColor", _SC(".x")); + /*# + Func: SceneSetAmbientColor + Proto: void:Scene,Vector + Desc: Set the scene ambient color. + Example: SceneSetAmbientColor(g_scene, Vector(1.0, 0.0, 0.0)) // Pure red ambient. + #*/ + sq_register(vm, SceneSetAmbientColor, "SceneSetAmbientColor", _SC(".xx")); + /*# + Func: SceneGetBackgroundColor + Proto: Vector:Scene + Desc: Get the scene background color. + #*/ + sq_register(vm, SceneGetBackgroundColor, "SceneGetBackgroundColor", _SC(".x")); + /*# + Func: SceneSetBackgroundColor + Proto: void:Scene,Vector + Desc: Set the scene background color. + Example: SceneSetAmbientColor(g_scene, Vector(0.0, 1.0, 0.0)) // Pure green background. + #*/ + sq_register(vm, SceneSetBackgroundColor, "SceneSetBackgroundColor", _SC(".xx")); + /*# + Func: SceneGetFogColor + Proto: Vector:Scene + Desc: Return the fog color. + #*/ + sq_register(vm, SceneGetFogColor, "SceneGetFogColor", _SC(".x")); + /*# + Func: SceneGetFogNear + Proto: float:Scene + Desc: Return the fog Z near. + #*/ + sq_register(vm, SceneGetFogNear, "SceneGetFogNear", _SC(".x")); + /*# + Func: SceneGetFogFar + Proto: float:Scene + Desc: Return the fog Z far. + #*/ + sq_register(vm, SceneGetFogFar, "SceneGetFogFar", _SC(".x")); + /*# + Func: SceneSetFog + Proto: void:Scene,bool enable,Vector color,float z_near,float z_far + Desc: Control scene fog. + Example: +// Set a white fog starting 10 meters from the camera and fully covering view at 50 meters from the camera. +SceneSetFog(g_scene, true, Vector(1.0, 1.0, 1.0), Mtr(10), Mtr(50)) + #*/ + sq_register(vm, SceneSetFog, "SceneSetFog", _SC(".xbxnn")); + + /*# + Func: SceneSetFlagDebugPhysic + Proto: void:Scene, bool active + Desc: Activate/Deactivate the flag debug physic. + #*/ + sq_register(vm, SceneSetFlagDebugPhysic, "SceneSetFlagDebugPhysic", _SC(".xb")); + + /*# + Func: SceneGetTimeOfDay + Proto: float:Scene + Desc: Get time of day as a normalized value. + #*/ + sq_register(vm, SceneGetTimeOfDay, "SceneGetTimeOfDay", _SC(".x")); + /*# + Func: SceneSetTimeOfDay + Proto: void:Scene,float time + Desc: Set time of day as a normalized value. + #*/ + sq_register(vm, SceneSetTimeOfDay, "SceneSetTimeOfDay", _SC(".xn")); + /*# + Func: SceneSetSkyShader + Proto: void:Scene,string shader + Desc: Set sky shader name file. + #*/ + sq_register(vm, SceneSetSkyShader, "SceneSetSkyShader", _SC(".xs")); + /*# + Func: SceneSetSkyLayer + Proto: void:Scene,string picture_layer,int index_sky_layer + Desc: Set sky layer picture. + #*/ + sq_register(vm, SceneSetSkyLayer, "SceneSetSkyLayer", _SC(".xsi")); + +/*# + Section: SceneRender + Desc: Rendering +#*/ + /*# + Func: SceneRegisterAsPropertyCallback + Proto: void:Scene,Renderer + Desc: Register a scene as the renderer property callback. + #*/ + sq_register(vm, SceneRegisterAsPropertyCallback, "SceneRegisterAsPropertyCallback", _SC(".xx")); + +/*# + Section: SceneDebug + Desc: Debug/profile +#*/ + /*# + Func: ScenePrintItemList + Proto: void:Scene + Desc: Dump scene item list to log. + #*/ + sq_register(vm, ScenePrintItemList, "ScenePrintItemList", _SC(".x")); + +/*# + Section: SceneItem + Desc: Item management +#*/ + /*# + Func: SceneGetItemList + Proto: Array:Scene|Instance + Desc: Returns an array of all items in the scene. + #*/ + sq_register(vm, SceneGetItemList, "SceneGetItemList", _SC(".x")); + /*# + Func: SceneGetItemChildrenList + Proto: Array:Scene,Item + Desc: Returns an array of all the children items in the scene of a given parent item. + #*/ + sq_register(vm, SceneGetItemChildrenList, "SceneGetItemChildrenList", _SC(".xx")); + /*# + Func: SceneFindItem + Proto: Item:Scene|Instance,string + Desc: Find an item in scene. + #*/ + sq_register(vm, SceneFindItem, "SceneFindItem", _SC(".xs")); + /*# + Func: SceneFindItemChild + Proto: void:Scene|Instance,Item parent,string child_name + Desc: Find child item of a given item in scene. + #*/ + sq_register(vm, SceneFindItemChild, "SceneFindItemChild", _SC(".xxs")); + /*# + Func: SceneSetupItem + Proto: void:Scene,Item + Desc: Setup an item. You need to call ItemRenderSetup() to setup the render object of this item. + #*/ + sq_register(vm, SceneSetupItem, "SceneSetupItem", _SC(".xx")); + /*# + Func: SceneForceUpdateMassShapePhysicItem + Proto: void:Scene,Item + Desc:for to update the mass from the shape physic if the item and rigid is already created. + #*/ + sq_register(vm, SceneForceUpdateMassShapePhysicItem, "SceneForceUpdateMassShapePhysicItem", _SC(".xx")); + /*# + Func: SceneDuplicateItem + Proto: void:Scene,Item + Desc: Duplicate an item and all its properties, returns the new instance.
You need to call SceneSetupItem() and ItemRenderSetup() on the new instance if you use this function at runtime. + #*/ + sq_register(vm, SceneDuplicateItem, "SceneDuplicateItem", _SC(".xx")); + + /*# + Func: SceneMergeItems + Proto: Object:Scene, RenderResourceFactory factory, nb item, array item + Desc: Merge 2 items together. + #*/ + sq_register(vm, SceneMergeItems, "SceneMergeItems", _SC(".xsxia")); + +/*# + Section: SceneGroup + Desc: Group management +#*/ + /*# + Func: SceneDeleteGroup + Proto: void:Scene|Instance,Group + Desc: Delete a group and all its members from a scene. + #*/ + sq_register(vm, SceneDeleteGroup, "SceneDeleteGroup", _SC(".xx")); + /*# + Func: SceneFindGroup + Proto: Group:Scene|Instance,string name + Desc: Find a group in scene from its name. + #*/ + sq_register(vm, SceneFindGroup, "SceneFindGroup", _SC(".xs")); + +/*# + Section: ScenePhysic + Desc: Physic +#*/ + /*# + Func: ScenePhysicAllocateCollisionNode + Proto: void:Scene,int max_node, int max_contact + Desc: Allocate physic system internal structures. A collision node is used for each collision occurring during the collision detection phase. Many contacts can be generated for each collision occurring. + #*/ + sq_register(vm, ScenePhysicAllocateCollisionNode, "ScenePhysicAllocateCollisionNode", _SC(".xii")); + /*# + Func: ScenePhysicEnableDeactivation + Proto: void:Scene,bool + Desc: Enable or disable physic system item deactivation. + #*/ + sq_register(vm, ScenePhysicEnableDeactivation, "ScenePhysicEnableDeactivation", _SC(".xb")); + /*# + Func: SceneSetPhysicContactSolverIteration + Proto: void:Scene,int + Desc: Set the number of iteration used by the physic contact solver. + #*/ + sq_register(vm, SceneSetPhysicContactSolverIteration, "SceneSetPhysicContactSolverIteration", _SC(".xi")); + /*# + Func: SceneSetPhysicConstraintSolverIteration + Proto: void:Scene,int + Desc: Set the number of iteration used by the physic constraint solver. + #*/ + sq_register(vm, SceneSetPhysicConstraintSolverIteration, "SceneSetPhysicConstraintSolverIteration", _SC(".xi")); + /*# + Func: SceneSetPhysicFrequency + Proto: void:Scene,float + Desc: Set the physic system update frequency (default: 75 Hertz). + #*/ + sq_register(vm, SceneSetPhysicFrequency, "SceneSetPhysicFrequency", _SC(".xn")); + /*# + Func: SceneGetPhysicFrequency + Proto: float:Scene + Desc: Returns the physic system update frequency in Hertz. + #*/ + sq_register(vm, SceneGetPhysicFrequency, "SceneGetPhysicFrequency", _SC(".x")); + /*# + Func: SceneSetGravity + Proto: void:Scene,Vector + Desc: Set default physic system gravity (Default: Earth gravity: 0.0, -9.8, 0.0). + Note: This only affects the gravity for newly created items. In order to modify the gravity for a given item please use the item Physics functions. + #*/ + sq_register(vm, SceneSetGravity, "SceneSetGravity", _SC(".xx")); + /*# + Func: SceneFindConstraint + Proto: Constraint:Scene,string name + Desc: Find a constraint in scene from its name. + #*/ + sq_register(vm, SceneFindConstraint, "SceneFindConstraint", _SC(".xs")); + +/*# + Section: SceneCollision + Desc: Collision +#*/ + /*# + Func: SceneCollisionRaytrace + Proto: TraceResult:Scene,Vector from,Vector direction,int collision_mask,ShapeMask,float max_distance + Desc: Raytrace the collision system, collision shape type and collision ids can be filtered through bit mask usage. + #*/ + sq_register(vm, SceneCollisionRaytrace, "SceneCollisionRaytrace", _SC(".xxxiin")); + /*# + Func: SceneRaytraceTriggerList + Proto: Item:Scene,Vector ray_origin,Vector ray_direction,float ray_length + Desc: Raytrace scene triggers, return the trigger item hit. + #*/ + sq_register(vm, SceneRaytraceTriggerList, "SceneRaytraceTriggerList", _SC(".xxxn")); + + // Push defines. + sq_pushroottable(vm); + + /*# + Struct: TraceResult + Member: bool hit: true if the ray hit something, false otherwise. + Member: Item item: Item hit by the ray. + Member: ColShape shape: Collision shape hit by the ray. + Member: Material material: Material at hit point. + Member: Vector p: Hit point location in world space. + Member: Vector n: Hit point normal in world space. + Member: float d: Distance to hit point from ray origin. + #*/ + + /*# + Enum: ImportFlag + Values: ImportFlagCamera,ImportFlagLight,ImportFlagObject,ImportFlagTrigger,ImportFlagGroup,ImportFlagMotion,ImportFlagGlobals,ImportFlagCollision,ImportFlagPhysic,ImportFlagPath,ImportFlagAll + #*/ +#if 1 + sq_pushstring(vm, "FlagLoadCamera", -1); sq_pushinteger(vm, SceneIOCamera); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadLight", -1); sq_pushinteger(vm, SceneIOLight); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadObject", -1); sq_pushinteger(vm, SceneIOObject); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadTrigger", -1); sq_pushinteger(vm, SceneIOTrigger); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadGroup", -1); sq_pushinteger(vm, SceneIOGroup); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadSettings", -1); sq_pushinteger(vm, SceneIOSettings); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadGlobals", -1); sq_pushinteger(vm, SceneIOGlobals); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadMotion", -1); sq_pushinteger(vm, SceneIOMotion); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadCollision", -1); sq_pushinteger(vm, SceneIOCollision); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadPhysic", -1); sq_pushinteger(vm, SceneIOPhysic); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadPath", -1); sq_pushinteger(vm, SceneIOPath); sq_newslot(vm, -3, true); + sq_pushstring(vm, "FlagLoadAll", -1); sq_pushinteger(vm, SceneIOAll); sq_newslot(vm, -3, true); +#endif + sq_pushstring(vm, "ImportFlagCamera", -1); sq_pushinteger(vm, SceneIOCamera); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagLight", -1); sq_pushinteger(vm, SceneIOLight); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagObject", -1); sq_pushinteger(vm, SceneIOObject); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagTrigger", -1); sq_pushinteger(vm, SceneIOTrigger); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagInstance", -1); sq_pushinteger(vm, SceneIOInstance); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagGroup", -1); sq_pushinteger(vm, SceneIOGroup); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagSettings", -1); sq_pushinteger(vm, SceneIOSettings); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagGlobals", -1); sq_pushinteger(vm, SceneIOGlobals); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagMotion", -1); sq_pushinteger(vm, SceneIOMotion); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagCollision", -1); sq_pushinteger(vm, SceneIOCollision); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagPhysic", -1); sq_pushinteger(vm, SceneIOPhysic); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagPath", -1); sq_pushinteger(vm, SceneIOPath); sq_newslot(vm, -3, true); + sq_pushstring(vm, "ImportFlagAll", -1); sq_pushinteger(vm, SceneIOAll); sq_newslot(vm, -3, true); + + sq_pushstring(vm, "NullItem", -1); CObject::Push(vm, NULL, typetag_Item); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/sound_binding.cpp b/include/modules/script_squirrel/legacy/sound_binding.cpp new file mode 100644 index 0000000..7b6b64c --- /dev/null +++ b/include/modules/script_squirrel/legacy/sound_binding.cpp @@ -0,0 +1,44 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "squirrel.h" + #include "script_squirrel/legacy/binding_helpers.h" + #include "core/sound.h" + + using namespace GS::Audio; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger SoundGetDuration(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(s, Sound, typetag_Sound) + __SQ_RETURNINT(s->mixer_data.IsValid() ? s->mixer_data->Get()->duration.toMs() : -1) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterSoundBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Sound + Desc: A sound object stores audio data that can be played back by the sound mixer. + Type: Sound + Related: Mixer +#*/ + +/*# + Section: SoundGeneric + Desc: Generic functions +#*/ + /*# + Func: SoundGetDuration + Proto: int:sound + Desc: Returns the sound duration in milliseconds. + #*/ + sq_register(vm, SoundGetDuration, "SoundGetDuration", _SC(".x")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/squirrel_binding.cpp b/include/modules/script_squirrel/legacy/squirrel_binding.cpp new file mode 100644 index 0000000..5fb0330 --- /dev/null +++ b/include/modules/script_squirrel/legacy/squirrel_binding.cpp @@ -0,0 +1,549 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + + #include "squirrel.h" + #include "script_squirrel/cobject/uc_binding.h" + #include "script_squirrel/cobject/cobject.h" + #include "script_squirrel/cobject/vector_decl.h" + #include "script_squirrel/cobject/uv_decl.h" + + #include "squirrel_binding.h" + #include "binding_helpers.h" + + #if __PLATFORM_NINTENDO_WII__ + #include "platform/wii/script/wii_binding.h" + #endif + #include "geometry/bounding_box.h" + #include "color/color.h" + #include "geometry/rect.h" + #include "filesystem/filesystem.h" + #include "platform.h" + + +namespace GS { + namespace Script { + +//------------------------------------------------------------------------------ +static bool BindingError(HSQUIRRELVM vm, const char *msg) +{ +// if (sq_getforeignptr(vm)) +// ((Script::VM *)sq_getforeignptr(vm))->Kill(); + SquirrelVM::DumpCallStack(vm, String::Format("Binding error: %s", msg).c_str()); + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool CreateClassInstance(HSQUIRRELVM vm, const char *class_name, bool call) +{ + sq_pushroottable(vm); + sq_pushstring(vm, class_name, -1); + if (SQ_FAILED(sq_get(vm, -2))) + { + sq_pop(vm, 1); + return BindingError(vm, String::Format("Class '%s' is not declared.", class_name).c_str()); + } + if (call) + { + sq_pushroottable(vm); + if (SQ_FAILED(sq_call(vm, 1, SQTrue, SQTrue))) + { + sq_pop(vm, 1); + return BindingError(vm, String::Format("Failed to instantiate class '%s'.", class_name).c_str()); + } + } + else + sq_createinstance(vm, -1); + sq_remove(vm, -2); // Remove root table. + sq_remove(vm, -2); // Remove class. + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void PushColor(HSQUIRRELVM vm, const Color &c) +{ + if (!CreateClassInstance(vm, "Vector", true)) + BindingError(vm, "Failed to create Vector instance."); + SetTableKey("x", sq_pushfloat, -1, c.x); + SetTableKey("y", sq_pushfloat, -1, c.y); + SetTableKey("z", sq_pushfloat, -1, c.z); + SetTableKey("w", sq_pushfloat, -1, c.w); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void PushVector2(HSQUIRRELVM vm, const Vector2 &v) +{ + if (!CreateClassInstance(vm, "Vector2", true)) + BindingError(vm, "Failed to create Vector2 instance."); + SetTableKey("x", sq_pushfloat, -1, v.x); + SetTableKey("y", sq_pushfloat, -1, v.y); +} +void GetVector2(HSQUIRRELVM vm, SQInteger idx, Vector2 &v) +{ + SQFloat x, y; + GetTableKey("x", sq_getfloat, idx, x) + GetTableKey("y", sq_getfloat, idx, y) + v.Set(x, y); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void PushVector(HSQUIRRELVM vm, const Vector4 &v, bool push_w) +{ + push_Vector(vm, v); +} +void GetVector(HSQUIRRELVM v, SQInteger idx, Vector4 &vo, bool get_w) +{ + _CHECK_INST_PARAM_RAW(pv, idx, Vector4, Vector); + vo = *pv; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void PushUV(HSQUIRRELVM vm, const Vector2 &uv) +{ + if (!CreateClassInstance(vm, "UV", true)) + BindingError(vm, "Failed to create UV instance."); + SetTableKey("u", sq_pushfloat, -1, uv.x); + SetTableKey("v", sq_pushfloat, -1, uv.y); +} +void GetUV(HSQUIRRELVM v, SQInteger idx, Vector2 &uv) +{ + _CHECK_INST_PARAM_RAW(pv, idx, Vector2, UV); + uv = *pv; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void PushMinMax(HSQUIRRELVM vm, const MinMax &v) +{ + if (!CreateClassInstance(vm, "MinMax", true)) + BindingError(vm, "Failed to create MinMax instance."); + + sq_pushstring(vm, "min", -1); + sq_get(vm, -2); + SetTableKey("x", sq_pushfloat, -1, v.mn.x) + SetTableKey("y", sq_pushfloat, -1, v.mn.y) + SetTableKey("z", sq_pushfloat, -1, v.mn.z) + sq_pop(vm, 1); + + sq_pushstring(vm, "max", -1); + sq_get(vm, -2); + SetTableKey("x", sq_pushfloat, -1, v.mx.x) + SetTableKey("y", sq_pushfloat, -1, v.mx.y) + SetTableKey("z", sq_pushfloat, -1, v.mx.z) + sq_pop(vm, 1); +} +void GetMinMax(HSQUIRRELVM vm, SQInteger idx, MinMax &v) +{ + sq_pushstring(vm, "min", -1); + sq_get(vm, -2); + GetVector(vm, -1, v.mn); + sq_pop(vm, 1); + + sq_pushstring(vm, "max", -1); + sq_get(vm, -2); + GetVector(vm, -1, v.mx); + sq_pop(vm, 1); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void PushRect(HSQUIRRELVM vm, const fRect &r) +{ + if (!CreateClassInstance(vm, "Rect")) + BindingError(vm, "Failed to create Rect instance."); + SetTableKey("sx", sq_pushfloat, -1, r.sx); + SetTableKey("sy", sq_pushfloat, -1, r.sy); + SetTableKey("ex", sq_pushfloat, -1, r.ex); + SetTableKey("ey", sq_pushfloat, -1, r.ey); +} +void GetRect(HSQUIRRELVM vm, SQInteger idx, fRect &r) +{ + SQFloat sx, sy, ex, ey; + GetTableKey("sx", sq_getfloat, idx, sx) + GetTableKey("sy", sq_getfloat, idx, sy) + GetTableKey("ex", sq_getfloat, idx, ex) + GetTableKey("ey", sq_getfloat, idx, ey) + r.Set(sx, sy, ex, ey); +} +void PushRect(HSQUIRRELVM vm, const iRect &r) +{ PushRect(vm, r.AsFloat()); } +void GetRect(HSQUIRRELVM vm, SQInteger idx, iRect &r) +{ + fRect t; + GetRect(vm, idx, t); + r.Set(int(t.sx), int(t.sy), int(t.ex), int(t.ey)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void sq_register(HSQUIRRELVM v, SQFUNCTION f, const char *fname, const SQChar *mask) +{ + sq_pushroottable(v); + sq_pushstring(v, (const SQChar *)fname, -1); + sq_newclosure(v, f, 0); // Create a new function. + sq_setnativeclosurename(v, -1, fname); + sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, mask); + sq_newslot(v, -3, false); + sq_pop(v, 1); // Pop the root table. +} +//------------------------------------------------------------------------------ + + } // Script +} // GS + + using namespace GS; + using namespace GS::Script; + +//------------------------------------------ +SQInteger SQAssert(HSQUIRRELVM vm) +//------------------------------------------ +{ + __SQ_GETSTART(2) + __SQ_GETBOOL(c) + __SQ_GETSTRING(d) + if (!c) + return sq_throwerror(vm, d); + __SQ_GETEND + __SQ_RETURN +} + +//--------------------------------------- +SQInteger SQPow(HSQUIRRELVM vm) +//--------------------------------------- +{ + __SQ_GETSTART(2) + __SQ_GETFLOAT(v) + __SQ_GETFLOAT(p) + __SQ_GETEND + __SQ_RETURNFLOAT(pow(v, p)) +} + +//--------------------------------------- +SQInteger SQExp(HSQUIRRELVM vm) +//--------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETFLOAT(v) + __SQ_GETEND + __SQ_RETURNFLOAT(exp(v)) +} + +//--------------------------------------- +SQInteger SQMod(HSQUIRRELVM vm) +//--------------------------------------- +{ + __SQ_GETSTART(2) + __SQ_GETINT(v) + __SQ_GETINT(m) + __SQ_GETEND + __SQ_RETURNINT(v % m) +} + +//------------------------------------------ +SQInteger SQAbsMod(HSQUIRRELVM vm) +//------------------------------------------ +{ + __SQ_GETSTART(2) + __SQ_GETINT(v) + __SQ_GETINT(m) + __SQ_GETEND + v %= m; + if (v < 0) + v = m + v; + __SQ_RETURNINT(v) +} + +//----------------------------------------------- +SQInteger ObjectIsValid(HSQUIRRELVM vm) +//----------------------------------------------- +{ + void *p; + if (!CObject::Get(vm, -1, &p)) + return -1; + sq_pop(vm, 1); + __SQ_RETURNBOOL(asbool(p)); +} + +//---------------------------------------------- +SQInteger ObjectIsSame(HSQUIRRELVM vm) +//---------------------------------------------- +{ + void *a, *b; + if (!CObject::Get(vm, -2, &a) || !CObject::Get(vm, -1, &b)) + return -1; + sq_pop(vm, 2); + __SQ_RETURNBOOL(a == b); +} + +//---------------------------------------------- +SQInteger ShellExecute(HSQUIRRELVM vm) +//---------------------------------------------- +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(path) + __SQ_GETSTRING(parm) + + int r = -1; + +#if __PLATFORM_WINDOWS__ + if (path) + { + String cmd = parm ? String::Format("%s %s", path, parm).c_str() : path; + __LOG_H__ << "Execute command '" << cmd << "'\n\n"; + +#if 0 + char szBuffer[_MAX_PATH * 10 + 1]; + + DWORD dw; + HANDLE hIn, hOut; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + STARTUPINFO si; + + if (CreatePipe(&hIn, &hOut, NULL, sizeof(szBuffer) * 2)) + { + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.wShowWindow = SW_HIDE; + si.hStdOutput = hOut; + si.hStdError = hOut; + + //if (!CreateProcess("C:\\WINDOWS\\system32\\cmd.exe", (LPSTR)cmd.c_str(), NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) + if (!CreateProcess(NULL, (LPSTR)cmd.c_str(), NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) + __LOG_N__ << "Couldn't create process: " << GetLastError() << "\n"; + else + { + CloseHandle(hOut); + __LOG_N__ << "Reading ShellExecute...\n"; + + forever + { + if (ReadFile(hIn, szBuffer, sizeof(szBuffer) - 1, &dw, NULL) == 0) + { + if (GetLastError() == ERROR_NO_DATA) + Sleep(1); + + else if (GetLastError() == ERROR_BROKEN_PIPE) + { + GetExitCodeProcess(pi.hProcess, &dw); + r = dw; + break; + } + else + break; + } + else + if (dw > 0) + { + szBuffer[dw] = 0; + __LOG__ << szBuffer << "\n"; + } + + if ((GetExitCodeProcess(pi.hProcess, &dw) == 0) || (dw != STILL_ACTIVE)) + { + r = dw; + break; + } + } + } + CloseHandle(hIn); + } + else { + __LOG_N__ << "Couldn't create pipe: " << GetLastError() << "\n"; + } +#else + char psBuffer[256]; + FILE *iopipe; + + if ((iopipe = _popen(cmd.c_str(), "r" )) != 0) + while (!feof(iopipe)) + if (fgets(psBuffer, 256, iopipe)) + __LOG__ << psBuffer; + + r = _pclose(iopipe); +#endif + } +#elif __PLATFORM_OSX__ + __LOG_E__ << "ShellExecute(): STUB\n"; +#elif __PLATFORM_LINUX__ + r = path ? system(parm ? String::Format("%s %s", path, parm).c_str() : path) : -1; +#endif + + __SQ_GETEND + __SQ_RETURNINT(r) +} + + +//--------------------------------------- +SQInteger Sleep(HSQUIRRELVM vm) +//--------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETINT(ms) + __SQ_GETEND + Platform::Get().Sleep(ms); + __SQ_RETURN +} + +//------------------------------------------------------------ +void RegisterAllSquirrelBinding(HSQUIRRELVM vm) +//------------------------------------------------------------ +{ +/*# + Topic: Script +#*/ + +/*# + Section: ScriptDebug + Desc: Debugging +#*/ + /*# + Func: __Assert + Proto: void:bool,string + Desc: Assert an expression, throw an engine exception and suspend the VM if not verified. + #*/ + sq_register(vm, SQAssert, "__Assert", _SC(".bs")); + +/*# + Section: ScriptGeneric + Desc: Generic +#*/ + /*# + Func: SQPow + Proto: float:float value,float pow + Desc: Returns value raised to power. + #*/ + sq_register(vm, SQPow, "Pow", _SC(".ff")); + /*# + Func: SQExp + Proto: float:float value + Desc: Returns value in exponential . + #*/ + sq_register(vm, SQExp, "Exp", _SC(".f")); + /*# + Func: SQMod + Proto: int:int value,int divider + Desc: Returns integer modulo of a value. + #*/ + sq_register(vm, SQMod, "Mod", _SC(".ii")); + /*# + Func: SQAbsMod + Proto: int:int value,int divider + Desc: Returns integer modulo of the absolute of a given value. + #*/ + sq_register(vm, SQAbsMod, "AbsMod", _SC(".ii")); + /*# + Func: ObjectIsValid + Proto: bool:Object + Desc: Returns true if the given engine object is valid, false otherwise.
This function can be used to test the validity of all engine types like geometry, material, item, scene and others. + #*/ + sq_register(vm, ObjectIsValid, "ObjectIsValid", _SC(".x")); + /*# + Func: ObjectIsSame + Proto: bool:Object,Object + Desc: Returns true if two given engine object references are pointing to the same object. + #*/ + sq_register(vm, ObjectIsSame, "ObjectIsSame", _SC(".xx")); + +/*# + Topic: System +#*/ + +/*# + Section: SystemGeneric + Desc: Generic +#*/ + /*# + Func: ShellExecute + Proto: int:string path,string param + Desc: Execute an external program, returns its return code. + #*/ + sq_register(vm, ShellExecute, "ShellExecute", _SC(".ss")); + + + sq_register(vm, Sleep, "_Sleep", _SC(".i")); + + // Legacy support. +#if 1 + sq_register(vm, ObjectIsValid, "AIPathIsValid", _SC(".x")); + sq_register(vm, ObjectIsValid, "GeometryIsValid", _SC(".x")); + sq_register(vm, ObjectIsValid, "ItemIsValid", _SC(".x")); + sq_register(vm, ObjectIsValid, "MetatagIsValid", _SC(".x")); + sq_register(vm, ObjectIsValid, "TextureIsValid", _SC(".x")); + sq_register(vm, ObjectIsValid, "WidgetIsValid", _SC(".x")); + sq_register(vm, ObjectIsValid, "WindowIsValid", _SC(".x")); +#endif + + sq_pushroottable(vm); + + /*# + Enum: SystemConstant + Values: SystemClockFrequency + #*/ + sq_pushstring(vm, "SystemClockFrequency", -1); sq_pushinteger(vm, Platform::Get().GetClockFrequency()); sq_newslot(vm, -3, true); + + // Register engine types. + for (int n = 0; n < typetag_End; ++n) + { + String type_string = String::Format("EngineType%s", CObjectTypeToString((CObjectType)n)); + sq_pushstring(vm, type_string.TrimChar(' ').c_str(), -1); sq_pushinteger(vm, n); sq_newslot(vm, -3, true); + } + + // Newer faster bindings. + RegisterUCBinding(vm); + + // + RegisterClockBinding(vm); + RegisterMatrixBinding(vm); + RegisterAnimationBinding(vm); + RegisterAIBinding(vm); + RegisterSystemBinding(vm); + RegisterRendererBinding(vm); + RegisterMixerBinding(vm); + RegisterSceneBinding(vm); + RegisterInstanceBinding(vm); + RegisterGroupBinding(vm); + RegisterCameraBinding(vm); + RegisterObjectBinding(vm); + RegisterMaterialBinding(vm); + RegisterLightBinding(vm); + RegisterProfilerBinding(vm); + RegisterItemBinding(vm); + RegisterMotionBinding(vm); + RegisterCollisionBinding(vm); + RegisterPhysicBinding(vm); + RegisterPictureBinding(vm); + RegisterTextureBinding(vm); + RegisterSoundBinding(vm); + RegisterGeometryBinding(vm); + RegisterIOBinding(vm); + RegisterUIBinding(vm); + RegisterNMLBinding(vm); + RegisterResourceFactoryBinding(vm); + RegisterRaytracerBinding(vm); + RegisterProjectBinding(vm); + RegisterTriggerBinding(vm); + RegisterEmitterBinding(vm); + RegisterHashBinding(vm); + RegisterHTTPBinding(vm); + RegisterFontBinding(vm); + RegisterPlatformBinding(vm); + RegisterMaterialShaderBinding(vm); + +#if __PLATFORM_NINTENDO_WII__ + RegisterWiiBinding(vm); +#endif + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/squirrel_binding.h b/include/modules/script_squirrel/legacy/squirrel_binding.h index 0c9f968..642d617 100644 --- a/include/modules/script_squirrel/legacy/squirrel_binding.h +++ b/include/modules/script_squirrel/legacy/squirrel_binding.h @@ -27,7 +27,6 @@ void RegisterFontBinding(HSQUIRRELVM); void RegisterGroupBinding(HSQUIRRELVM); void RegisterHashBinding(HSQUIRRELVM); void RegisterHTTPBinding(HSQUIRRELVM); -void RegisterWebSocketBinding(HSQUIRRELVM); void RegisterInstanceBinding(HSQUIRRELVM); void RegisterIOBinding(HSQUIRRELVM); void RegisterItemBinding(HSQUIRRELVM); diff --git a/include/modules/script_squirrel/legacy/system_binding.cpp b/include/modules/script_squirrel/legacy/system_binding.cpp new file mode 100644 index 0000000..c25038c --- /dev/null +++ b/include/modules/script_squirrel/legacy/system_binding.cpp @@ -0,0 +1,254 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + +#ifdef __PLATFORM_WINDOWS__ + #define WIN32_LEAN_AND_MEAN + #define NOGDI + #include +#endif + + #include "squirrel_binding.h" + #include "binding_helpers.h" + #include "filesystem/filesystem.h" + #include "filesystem/io_memory.h" + #include "filesystem/io_cfile.h" + #include "filesystem/io_handle.h" + #include "rand/rand.h" + #include "platform.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger SystemGetClock(HSQUIRRELVM vm) { + __SQ_RETURNINT(Platform::Get().GetClock()) } +SQInteger SystemGarbageCollect(HSQUIRRELVM vm) { + sq_collectgarbage(vm); + __SQ_RETURN +} +SQInteger SystemGetClockFrequency(HSQUIRRELVM vm) +{ __SQ_RETURNINT(Platform::Get().GetClockFrequency()) } +SQInteger SystemGetLocale(HSQUIRRELVM vm) +{ __SQ_RETURNSTRING(/*Platform::Get().GetLocale()*/"STUB") } +SQInteger SystemGetPlatform(HSQUIRRELVM vm) +{ __SQ_RETURNSTRING(Platform::Get().GetName()) } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SystemSeedRand(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETINT(seed)) + Random::Seed(seed); + __SQ_RETURN +} +SQInteger SystemRand(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETINT(range)) + __SQ_RETURNINT(Random::Rand(range)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SystemShowCursor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETBOOL(show)) +#ifdef __PLATFORM_WINDOWS__ + ShowCursor(show); +#endif + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SystemSleep(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETINT(ms)) + Platform::Get().Sleep(ms); + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +SQInteger SystemSetProcessAffinity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETINT(num_thread)) + HANDLE process = GetCurrentProcess(); + DWORD_PTR processAffinityMask = 1 << 0; + for (int i = 1; i < num_thread; ++i) + processAffinityMask |= (1 << i); + + BOOL success = SetProcessAffinityMask(process, processAffinityMask); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SystemMountLocalPath(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSTRING(mount_point) + __SQ_GETSTRING(local_path) + bool r = Platform::Get().io->Mount(new IO::CFile(local_path), mount_point); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger SystemHasMountPoint(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(mount_point) + bool r = asbool(Platform::Get().io->GetIOSystem(mount_point)); + __SQ_GETEND + __SQ_RETURNBOOL(r) +} +SQInteger GetPathFromMountPoint(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(mount_point) + __SQ_GETEND + IO::Base* base = Platform::Get().io->GetIOSystem(mount_point); + if(base == NULL) + __SQ_RETURNSTRING("") + else + __SQ_RETURNSTRING(base->MapToAbsolute("")) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SystemLoadBindingPlugin(HSQUIRRELVM vm) +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(shared_lib_path) + + SquirrelVM *sq = (SquirrelVM *)sq_getforeignptr(vm); + int code_error = 0; + Script::BindingPluginManager::Plugin *plugin = sq->binding_plugins.LoadPlugin(shared_lib_path, &code_error); + + if (plugin == NULL) + return sq_throwerror(vm, "Failed to load binding library."); + + else + { + Script::IScriptBinding *binding = sq->binding_plugins.CreatePluginInterface(plugin); + binding->RegisterBinding(*sq); + } + + __SQ_GETEND + __SQ_RETURNBOOL(true) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterSystemBinding(HSQUIRRELVM vm) +{ +/*# + Topic: System +#*/ + +/*# + Section: System + Desc: System functions +#*/ + /*# + Func: SystemSleep + Proto: void:int + Desc: Sleep the current thread for a specified number of milliseconds. + #*/ + sq_register(vm, SystemSleep, "SystemSleep", _SC(".i")); + + /*# + Func: SystemSetProcessAffinity + Proto: void:int + Desc: Set the number of thread affinity for the process simulator. + #*/ + sq_register(vm, SystemSetProcessAffinity, "SystemSetProcessAffinity", _SC(".i")); + + /*# + Func: SystemGetClock + Proto: int: + Desc: Return the raw system clock. + #*/ + sq_register(vm, SystemGetClock, "SystemGetClock", _SC(".")); + /*# + Func: SystemGarbageCollect + Proto: void: + Desc: garbage collect. + #*/ + sq_register(vm, SystemGarbageCollect, "SystemGarbageCollect", _SC(".")); + /*# + Func: SystemGetClockFrequency + Proto: int: + Desc: Return the system clock frequency. + #*/ + sq_register(vm, SystemGetClockFrequency, "SystemGetClockFrequency", _SC(".")); + /*# + Func: SystemGetLocale + Proto: string: + Desc: Return the system language description in a string ("FR","EN","ES","NL","IT"). + #*/ + sq_register(vm, SystemGetLocale, "SystemGetLocale", _SC(".")); + /*# + Func: SystemGetPlatform + Proto: string: + Desc: Return the current platform ("Win32", "Linux32", "Wii"). + #*/ + sq_register(vm, SystemGetPlatform, "SystemGetPlatform", _SC(".")); + + /*# + Func: SystemRand + Proto: int:int range + Desc: Return a random number between [0;range]. + #*/ + sq_register(vm, SystemRand, "SystemRand", _SC(".n")); + /*# + Func: SystemSeedRand + Proto: void:int seed + Desc: Initialize the random number sequence with a given seed. + #*/ + sq_register(vm, SystemSeedRand, "SystemSeedRand", _SC(".n")); + + /*# + Func: SystemShowCursor + Proto: void:bool show + Desc: Show/hide the platform cursor. + #*/ + sq_register(vm, SystemShowCursor, "SystemShowCursor", _SC(".b")); + + /*# + Func: SystemMountLocalPath + Proto: bool:String local_path,String mount_point + Desc: Mount a local path under a specific mount point. + Example: SystemMountLocalPath("d:/test/", "@test/") // "d:/test/a.jpg" can now be accessed as "@test/a.jpg". + #*/ + sq_register(vm, SystemMountLocalPath, "SystemMountLocalPath", _SC(".ss")); + /*# + Func: SystemHasMountPoint + Proto: bool:string mount_point + Desc: Returns true if the specified mount point exists. + #*/ + sq_register(vm, SystemHasMountPoint, "SystemHasMountPoint", _SC(".s")); + /*# + Func: GetPathFromMountPoint + Proto: string:string mount_point + Desc: Returns path if the specified mount point exists. + #*/ + sq_register(vm, GetPathFromMountPoint, "GetPathFromMountPoint", _SC(".s")); + + /*# + Func: SystemLoadBindingPlugin + Proto: bool:string library_path + Desc: Load a script binding API from a shared library. + #*/ + sq_register(vm, SystemLoadBindingPlugin, "SystemLoadBindingPlugin", _SC(".s")); + + /*# + Enum: HardwareButton + Values: HardwareButtonHome,HardwareButtonMenu,HardwareButtonBack + #*/ + sq_pushstring(vm, "HardwareButtonHome", -1); sq_pushinteger(vm, 0); sq_newslot(vm, -3, true); + sq_pushstring(vm, "HardwareButtonMenu", -1); sq_pushinteger(vm, 1); sq_newslot(vm, -3, true); + sq_pushstring(vm, "HardwareButtonBack", -1); sq_pushinteger(vm, 2); sq_newslot(vm, -3, true); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/texture_binding.cpp b/include/modules/script_squirrel/legacy/texture_binding.cpp new file mode 100644 index 0000000..4cc310b --- /dev/null +++ b/include/modules/script_squirrel/legacy/texture_binding.cpp @@ -0,0 +1,158 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "core/render_data.h" + #include "core/graphic_resource_factory.h" + #include "picture/pict.h" + + using namespace GS::Render; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger TextureSetWrapping(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(t, Texture, typetag_Texture) + __SQ_GETBOOL(wrap_u) + __SQ_GETBOOL(wrap_v) + __SQ_GETEND + t->SetWrapping(wrap_u ? TextureParm::WrapRepeat : TextureParm::WrapClamp, wrap_v ? TextureParm::WrapRepeat : TextureParm::WrapClamp); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger TextureSetStreamState(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(t, Texture, typetag_Texture) + __SQ_GETINT(stream_state) + __SQ_GETEND + __SQ_RETURN +} +SQInteger TextureRewindStream(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(t, Texture, typetag_Texture) + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger TextureGetWidth(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(t, Texture, typetag_Texture) + __SQ_RETURNINT(t->GetWidth()) +} +SQInteger TextureGetHeight(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(t, Texture, typetag_Texture) + __SQ_RETURNINT(t->GetHeight()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger TextureUpdate(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(t, Texture, typetag_Texture) + __SQ_GETSAFEPTR(p, GS::Picture, typetag_Picture) + __SQ_GETEND + //__SQ_RETURNBOOL(t->Create((const char *)p->GetData(), p->GetWidth(), p->GetHeight())) + t->Blit((const char *)p->GetData(), p->GetWidth(), p->GetHeight()); + __SQ_RETURN +} +SQInteger TextureRelease(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(t, Texture, typetag_Texture) + t->Free(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterTextureBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Texture + Type: Texture +#*/ + +/*# + Section: TextureStream + Desc: Data streaming +#*/ + /*# + Func: TextureSetStreamState + Proto: void:texture,StreamState state + Desc: Set the texture stream state. + #*/ + sq_register(vm, TextureSetStreamState, "TextureSetStreamState", _SC(".xi")); + /*# + Func: TextureRewindStream + Proto: void:texture + Desc: Rewind texture stream. + #*/ + sq_register(vm, TextureRewindStream, "TextureRewindStream", _SC(".x")); + +/*# + Section: TextureSampling + Desc: Texture sampling +#*/ + /*# + Func: TextureSetWrapping + Proto: void:Texture,bool wrap_u, bool wrap_v + Desc: Set the texture U and V wrap modes. + #*/ + sq_register(vm, TextureSetWrapping, "TextureSetWrapping", _SC(".xbb")); + +/*# + Section: TextureGeneric + Desc: Generic +#*/ + /*# + Func: TextureGetWidth + Proto: int:texture + Desc: Return the texture width. + #*/ + sq_register(vm, TextureGetWidth, "TextureGetWidth", _SC(".x")); + /*# + Func: TextureGetHeight + Proto: int:texture + Desc: Return the texture height. + #*/ + sq_register(vm, TextureGetHeight, "TextureGetHeight", _SC(".x")); + + /*# + Func: TextureUpdate + Proto: bool:Texture,Picture + Desc: Update the texture data from a picture object. + #*/ + sq_register(vm, TextureUpdate, "TextureUpdate", _SC(".xx")); + /*# + Func: TextureRelease + Proto: void:Texture + Desc: Release the renderer data for a given texture. A subsequent call to TextureUpdate will then recreate the renderer object. + #*/ + sq_register(vm, TextureRelease, "TextureRelease", _SC(".x")); + + sq_pushroottable(vm); + + /*# + Enum: StreamState + Values: StreamPlaying,StreamPaused + #*/ +#if __ENABLE_DAV__ + sq_pushstring(vm, "StreamPlaying", -1); sq_pushinteger(vm, TextureStreamInterface::Stream_Playing); sq_newslot(vm, -3, true); + sq_pushstring(vm, "StreamPaused", -1); sq_pushinteger(vm, TextureStreamInterface::Stream_Paused); sq_newslot(vm, -3, true); +#endif + + sq_pushstring(vm, "NullTexture", -1); CObject::Push(vm, NULL, typetag_Texture); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/trigger_binding.cpp b/include/modules/script_squirrel/legacy/trigger_binding.cpp new file mode 100644 index 0000000..a6f2310 --- /dev/null +++ b/include/modules/script_squirrel/legacy/trigger_binding.cpp @@ -0,0 +1,84 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "binding_helpers.h" + #include "scene3d/mtrigger.h" + + using namespace GS::S3D; + using namespace GS::Core; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +SQInteger TriggerGetItemList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(t, MTrigger, typetag_Trigger) + sq_newarray(vm, 0); + ListForeachPtr(Trigger::ItemInTrigger *, i, t->items_in_trigger) + if (i->inside) + { + CObject::Push(vm, (void *)i, typetag_Item); + sq_arrayappend(vm, -2); + } + return 1; +} +SQInteger TriggerTestItem(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(t, MTrigger, typetag_Trigger) + __SQ_GETSAFEPTR(i, MItem, typetag_Item) + __SQ_GETEND + + ListForeachPtr(Trigger::ItemInTrigger *, _i, t->items_in_trigger) + if (_i->inside && (i == (MItem *)_i->item->mitem)) + __SQ_RETURNBOOL(true) + + __SQ_RETURNBOOL(false) +} +SQInteger TriggerPosInside(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(t, MTrigger, typetag_Trigger) + __SQ_GETVECTOR(p) + __SQ_GETEND + + __SQ_RETURNBOOL(t->IsInside(p)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void RegisterTriggerBinding(HSQUIRRELVM vm) +{ +/*# + Topic: Trigger + Type: Trigger + Related: Item +#*/ + +/*# + Section: TriggerGeneral + Desc: Trigger general functions. +#*/ + /*# + Func: TriggerGetItemList + Proto: array:Item + Desc: Return an array of items currently inside this trigger. + #*/ + sq_register(vm, TriggerGetItemList, "TriggerGetItemList", _SC(".x")); + /*# + Func: TriggerTestItem + Proto: bool:Item trigger,Item item + Desc: Test if a given item is currently inside this trigger. + #*/ + sq_register(vm, TriggerTestItem, "TriggerTestItem", _SC(".xx")); + /*# + Func: TriggerPosInside + Proto: bool:Item trigger,Vector p + Desc: Test if a given p is currently inside this trigger. + #*/ + sq_register(vm, TriggerPosInside, "TriggerPosInside", _SC(".xx")); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/legacy/ui_binding.cpp b/include/modules/script_squirrel/legacy/ui_binding.cpp new file mode 100644 index 0000000..1a7fed0 --- /dev/null +++ b/include/modules/script_squirrel/legacy/ui_binding.cpp @@ -0,0 +1,2639 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "squirrel_binding.h" + #include "binding_helpers.h" + #include "script_squirrel/cobject/matrix_decl.h" + #include "ui/ui.h" + #include "ui/ui_ace_manager.h" + #include "ui/ui_cursor.h" + #include "ui/ui_camera.h" + #include "ui/widget_canvas.h" + #include "ui/widget_check.h" + #include "ui/widget_sizer.h" + #include "ui/widget_spacer.h" + #include "ui/widget_staticcontainer.h" + #include "ui/ui_window.h" + #include "scene3d/scene.h" + #include "core/renderer.h" + #include "script/scripted_object.h" + #include "script/script_unit.h" + +#include "picture/pict_io.h" + using namespace GS; + using namespace GS::S2D; + using namespace GS::Script; + + +static CObjectType item_derived_types[] = { typetag_UIItem, typetag_UISprite, typetag_Window, typetag_Undefined }; +static CObjectType sprite_derived_types[] = { typetag_UISprite, typetag_Window, typetag_Undefined }; + +Widget *GetWidget(HSQUIRRELVM vm , int idx); +#define __SQ_ASSERTSPRITEISWINDOW(__V__) if (__V__->GetItemType() != S2D::Item::Type_Window) return sq_throwerror(vm, "Sprite is not a window"); + +// + +SQInteger WebcamTextureBlit(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTRALLOWNULL(t, Render::Texture, typetag_Texture) + __SQ_GETINT(i) + t->Blit((char*)(i), 640, 480, 0U, 0U, Render::Texture::FormatRGBA8); + + __SQ_GETEND + __SQ_RETURN +} + +//----------------------------------------------------------------------------- +SQInteger UIFromNML(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene2d) + __SQ_GETSTRING(path) + Group *group = NULL; + if (!scene->FromMetaFileStoreGroup(path, &group)) + return sq_throwerror(vm, "Failed to load scene."); +// scene->InstanceSetup(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(group, typetag_Group) +} +SQInteger UIFromNMLStoreGroup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene2d) + __SQ_GETSTRING(path) + __SQ_GETINT(flag) + Group *group = NULL; + if (!scene->FromMetaFileStoreGroup(path, &group, flag)) + return sq_throwerror(vm, "Failed to load scene."); +// scene->InstanceSetup(); + __SQ_GETEND + __SQ_RETURNSAFEPTR(group, typetag_Group) +} +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +SQInteger WindowCompare(HSQUIRRELVM vm) +{ + Sprite *wa, *wb; + if (!CObject::Get(vm, -2, (void **)&wa, typetag_Window)) + return -1; + if (!CObject::Get(vm, -1, (void **)&wb, typetag_Window)) + return -1; + sq_pop(vm, 2); + + sq_pushbool(vm, wa == wb ? true : false); + return 1; +} + +SQInteger SceneGetUI(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(scene, S3D::Scene, typetag_Scene3d) + __SQ_RETURNSAFEPTR(scene->ui.c_ptr(), typetag_Scene2d) +} + +SQInteger UIRenderSetup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETSAFEPTR(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETEND + ui->RenderSetup(f); + __SQ_RETURN +} +SQInteger UISetVirtualResolution(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETINT(w) + __SQ_GETINT(h) + __SQ_GETEND + ui->GetDefaultCamera()->resolution.Set((float)w, (float)h); + __SQ_RETURN +} + +SQInteger UIGetVirtualResolution(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_RETURNVECTOR2(Vector2(ui->GetDefaultCamera()->resolution.x, ui->GetDefaultCamera()->resolution.y)) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UIGetScreenToUIMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_RETURNMATRIX3(ui->GetScreenToUIMatrix()) +} +SQInteger UIGetUIToScreenMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_RETURNMATRIX3(ui->GetUIToScreenMatrix()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UIItemCastToSprite(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, Item, typetag_UIItem) + if (i->GetItemType() != Item::Type_Sprite) + return sq_throwerror(vm, "UI item cannot be cast to sprite."); + __SQ_RETURNSAFEPTR((Sprite *)i, typetag_UISprite) +} +SQInteger UIItemCastToWindow(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(i, Item, typetag_UIItem) + if (i->GetItemType() != Item::Type_Window) + return sq_throwerror(vm, "UI item cannot be cast to window."); + __SQ_RETURNSAFEPTR((Window *)i, typetag_Window) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UILockToSprite(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETSAFEPTR(sprite, Sprite, typetag_Window) + __SQ_GETEND + ui->Lock(sprite); + __SQ_RETURN +} +SQInteger UIUnlock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ui, Scene, typetag_Scene2d) + ui->Unlock(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UISetCommandList(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETSTRING(list) + ACEManager::Get()->LoadACECommandList(list, ui); + __SQ_GETEND + __SQ_RETURN +} +SQInteger UIIsCommandListDone(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_RETURNBOOL(ui->IsCommandListDone()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UICursorGetWindowBelow(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(cursor, Cursor, typetag_UICursor) + Window *w = NULL; + if (Item *i = cursor->current_state.item) + w = i->GetItemType() == Item::Type_Window ? (Window *)i : NULL; + if (w == NULL) + __SQ_RETURNNULL + __SQ_RETURNSAFEPTR(w, typetag_Window) +} +SQInteger UICursorGetSpriteBelow(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(cursor, Cursor, typetag_UICursor) + Sprite *s = NULL; + if (Item *i = cursor->current_state.item) + s = i->GetItemType() == Item::Type_Sprite ? (Sprite *)i : NULL; + if (s == NULL) + __SQ_RETURNNULL + __SQ_RETURNSAFEPTR(s, typetag_UISprite) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UISetGlobalFadeEffect(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETFLOAT(fade) + __SQ_GETEND + ui->SetGlobalFadeEffect(fade); + __SQ_RETURN +} + +SQInteger UISetGlobalFadeColor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETINT(r) + __SQ_GETINT(g) + __SQ_GETINT(b) + __SQ_GETEND + ui->global_fade_color.x = (float)r / 255.f; + ui->global_fade_color.y = (float)g / 255.f; + ui->global_fade_color.z = (float)b / 255.f; + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +SQInteger UIWindowCentre(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types) + __SQ_GETEND + Vector2 pos = (ui->GetCurrentCamera()->resolution - item->GetSize()) * 0.5f + item->GetPivot(); + item->SetPosition(pos.x, pos.y); + __SQ_RETURN +} +SQInteger WindowSetParent(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(w, Sprite, typetag_Window) + __SQ_GETSAFEPTRALLOWNULL(p, Sprite, typetag_Window) + __SQ_GETEND + w->SetParent(p); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowSetCommandList(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types) + __SQ_GETSTRING(list) + ACEManager::Get()->LoadACECommandList(list, sprite); + __SQ_GETEND + __SQ_RETURN +} +SQInteger WindowIsCommandListDone(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types)) + __SQ_RETURNBOOL(sprite->IsCommandListDone()) +} +SQInteger WindowResetCommandList(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types)) + sprite->ResetCommandList(); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowSetPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + item->SetPosition(x, y); + __SQ_RETURN +} +SQInteger WindowSetRotation(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types) + __SQ_GETFLOAT(a) + __SQ_GETEND + item->SetRotation(a); + __SQ_RETURN +} +SQInteger WindowSetScale(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + item->SetScale(x, y); + __SQ_RETURN +} +SQInteger WindowSetPivot(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + item->SetPivot(x, y); + __SQ_RETURN +} +SQInteger WindowSetSize(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + item->SetSize(x, y); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowGetPosition(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNVECTOR2(item->GetPosition()) +} +SQInteger WindowGetPivot(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNVECTOR2(item->GetPivot()) +} +SQInteger WindowGetSize(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNVECTOR2(item->GetSize()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowGetRect(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNRECT(item->GetRect()) +} +SQInteger WindowGetScreenRect(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNRECT(item->GetScreenRect()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowGetName(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNSTRING(item->name.c_str()) +} +SQInteger WindowGetTitle(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(w, Sprite, typetag_Window) + __SQ_ASSERTSPRITEISWINDOW(w) + + Widget *title = ((Window *)w)->GetTitleWidget(); + if (title->GetType() != WidgetTypeText) + return sq_throwerror(vm, "Window title widget is not a text widget."); + + TextWidget *text = (TextWidget *)title; + __SQ_RETURNSTRING(text->GetText()) +} +SQInteger WindowSetTitle(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(w, Sprite, typetag_Window) + __SQ_GETSTRING(title_string) + + __SQ_ASSERTSPRITEISWINDOW(w) + + Widget *title = ((Window *)w)->GetTitleWidget(); + if (title->GetType() != WidgetTypeText) + return sq_throwerror(vm, "Window title widget is not a text widget."); + + TextWidget *text = (TextWidget *)title; + text->SetText(title_string); + + __SQ_GETEND + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowGetParent(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNSAFEPTR(item->GetParent(), typetag_UIItem) +} + +SQInteger WindowGetChild(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Sprite, typetag_Window) + __SQ_GETINT(id) + __SQ_GETEND + __SQ_RETURNSAFEPTR(s->GetItemType() == S2D::Item::Type_Window ? ((Window *)s)->GetWidget(id) : NULL, typetag_Widget) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowSetZOrder(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types) + __SQ_GETFLOAT(z) + __SQ_GETEND + item->SetZOrder(z); + __SQ_RETURN +} +SQInteger WindowGetZOrder(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(item, S2D::Item, item_derived_types)) + __SQ_RETURNFLOAT(item->GetZOrder()) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowSetFlip(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types) + __SQ_GETBOOL(u) + __SQ_GETBOOL(v) + __SQ_GETEND + sprite->sprite_flags.Raise(Sprite::FlagFlipU, asbool(u)); + sprite->sprite_flags.Raise(Sprite::FlagFlipV, asbool(v)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowSetOpacity(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types) + __SQ_GETFLOAT(o) + __SQ_GETEND + sprite->opacity = o; + __SQ_RETURN +} +SQInteger WindowGetOpacity(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types)) + __SQ_RETURNFLOAT(sprite->opacity) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowGetStyle(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types)) + __SQ_RETURNINT(sprite->sprite_flags.Get()) +} +SQInteger WindowSetStyle(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types) + __SQ_GETINT(v) + __SQ_GETEND + sprite->sprite_flags = v; + __SQ_RETURN +} +SQInteger WindowAddStyle(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types) + __SQ_GETINT(v) + __SQ_GETEND + sprite->sprite_flags.Set(v); + __SQ_RETURN +} +SQInteger WindowRemoveStyle(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(sprite, Sprite, sprite_derived_types) + __SQ_GETINT(v) + __SQ_GETEND + sprite->sprite_flags.Remove(v); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WindowGetBackgroundPicture(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(w, Sprite, typetag_Window) + __SQ_ASSERTSPRITEISWINDOW(w) + __SQ_RETURNSAFEPTR(((Window *)w)->background_picture, typetag_Picture) +} +SQInteger WindowSetBackgroundPicture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(w, Sprite, typetag_Window) + __SQ_ASSERTSPRITEISWINDOW(w) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETEND + ((Window *)w)->background_picture = p; + __SQ_RETURN +} +SQInteger WindowSetBackgroundColor(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(w, Sprite, typetag_Window) + __SQ_ASSERTSPRITEISWINDOW(w) + __SQ_GETINT(icolor) + __SQ_GETEND + ((Window *)w)->background_color = Color(uint(icolor)); + __SQ_RETURN +} +SQInteger UIDeleteWindow(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETSAFEPTR(s, Sprite, typetag_Window) + __SQ_GETEND + ui->RemoveItem(s); + __SQ_RETURN +} +SQInteger UIDeleteAllItems(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ui, Scene, typetag_Scene2d) + ui->DeleteAllItems(); + __SQ_RETURN +} +SQInteger UIAddSprite(HSQUIRRELVM vm) +{ + __SQ_GETSTART(7) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene2d) + __SQ_GETINT(idx) + __SQ_GETSAFEPTRALLOWNULL(t, Render::Texture, typetag_Texture) + __SQ_GETFLOAT(px) + __SQ_GETFLOAT(py) + __SQ_GETFLOAT(sx) + __SQ_GETFLOAT(sy) + Sprite *s = new Sprite; + if (!s) + return sq_throwerror(vm, "Failed to allocate sprite."); + s->name = String::Format("%d", idx); + s->SetPosition(px, py); + s->SetSize(sx, sy); + s->RenderSetup(); + s->render_data->texture = t; + scene->AddItem(s, true); + __SQ_GETEND + __SQ_RETURNSAFEPTR(s, typetag_Window) +} +SQInteger UIAddNamedSprite(HSQUIRRELVM vm) +{ + __SQ_GETSTART(7) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene2d) + __SQ_GETSTRING(name) + __SQ_GETSAFEPTRALLOWNULL(t, Render::Texture, typetag_Texture) + __SQ_GETFLOAT(px) + __SQ_GETFLOAT(py) + __SQ_GETFLOAT(sx) + __SQ_GETFLOAT(sy) + Sprite *s = new Sprite; + s->name = name; + s->SetPosition(px, py); + s->SetSize(sx, sy); + scene->AddItem(s, true); + __SQ_GETEND + __SQ_RETURNSAFEPTR(s, typetag_Window) +} +SQInteger SpriteSetTexture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(s, Sprite, typetag_Window) + __SQ_GETSAFEPTRALLOWNULL(t, Render::Texture, typetag_Texture) + if (!s->render_data) + return sq_throwerror(vm, "Sprite not setup, please call SpriteRenderSetup() before changing its texture."); + s->render_data->texture = t; + __SQ_GETEND + __SQ_RETURN +} +SQInteger SpriteSetUVOrigin(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(s, Sprite, typetag_Window) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + s->uv_origin.Set(x, y); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger SpriteRenderSetup(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(s, Sprite, sprite_derived_types) + __SQ_GETSAFEPTRALLOWNULL(f, Core::ResourceFactories, typetag_ResourceFactories) + __SQ_GETEND + s->RenderSetup(f); + __SQ_RETURN +} + +SQInteger SpriteSetTextureMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETCOBJECTBASE(s, Sprite, sprite_derived_types) + __SQ_GETMATRIX3(m) + __SQ_GETEND + s->uv_matrix = m; + __SQ_RETURN +} +SQInteger UIAddNamedWindow(HSQUIRRELVM vm) +{ + __SQ_GETSTART(6) + __SQ_GETSAFEPTR(scene, Scene, typetag_Scene2d) + __SQ_GETSTRING(name) + __SQ_GETFLOAT(px) + __SQ_GETFLOAT(py) + __SQ_GETFLOAT(sx) + __SQ_GETFLOAT(sy) + Window *w = new Window; + w->name = name; + w->SetPosition(px, py); + w->SetSize(sx, sy); + scene->AddItem(w, true); + __SQ_GETEND + __SQ_RETURNSAFEPTR(w, typetag_Window) +} +SQInteger UIAddNamedBitmapWindow(HSQUIRRELVM vm) +{ + __SQ_GETSTART(7) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETSTRING(name) + __SQ_GETSAFEPTRALLOWNULL(bitmap, Picture, typetag_Picture) + __SQ_GETFLOAT(px) + __SQ_GETFLOAT(py) + __SQ_GETFLOAT(sx) + __SQ_GETFLOAT(sy) + Window *w = new Window; + w->name = name; + w->SetPosition(px, py); + w->SetSize(sx, sy); + w->background_picture = bitmap; + ui->AddItem(w, true); + __SQ_GETEND + __SQ_RETURNSAFEPTR(w, typetag_Window) +} +SQInteger WindowGetCacheTexture(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(w, Sprite, typetag_Window) + __SQ_ASSERTSPRITEISWINDOW(w) + __SQ_RETURNSAFEPTR(((Window *)w)->GetCache(), typetag_Texture); +} + +SQInteger WindowSetBaseWidget(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(sprite, Sprite, typetag_Window) + Widget *widget = GetWidget(vm, __sq_stackpos); + __SQ_GETUPDATESTACK + __SQ_GETEND + + if (sprite->GetItemType() == S2D::Item::Type_Window) + if (Window *window = (Window *)sprite) + window->SetBaseWidget(widget); + + __SQ_RETURN +} + +SQInteger WindowForceLayout(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(w, Sprite, typetag_Window) +// wnd->Render(NULL); + __SQ_RETURN +} + +SQInteger WindowInvalidate(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(wnd, Sprite, typetag_Window) + __SQ_ASSERTSPRITEISWINDOW(wnd) + ((Window *)wnd)->Invalidate(); + __SQ_RETURN +} + +SQInteger UISetSkin(HSQUIRRELVM vm) +{ + Scene *sys; + if (!CObject::Get(vm, -16, (void **)&sys, typetag_Scene2d)) + return sq_throwerror(vm, "Invalid UI"); + + Core::ResourceFactories *f; + if (!CObject::Get(vm, -15, (void **)&f, typetag_ResourceFactories)) + return sq_throwerror(vm, "Invalid resource factory."); + + const char *l, *r, *t, *b, *tl, *tr, *bl, *br; + sq_getstring(vm, -14, &t); + sq_getstring(vm, -13, &l); + sq_getstring(vm, -12, &r); + sq_getstring(vm, -11, &b); + sq_getstring(vm, -10, &tl); + sq_getstring(vm, -9, &tr); + sq_getstring(vm, -8, &bl); + sq_getstring(vm, -7, &br); + + SQInteger skin_color; + sq_getinteger(vm, -6, &skin_color); + + SQInteger skin_title_color, skin_title_top, skin_title_bottom, skin_title_size; + sq_getinteger(vm, -5, &skin_title_color); + sq_getinteger(vm, -4, &skin_title_top); + sq_getinteger(vm, -3, &skin_title_bottom); + sq_getinteger(vm, -2, &skin_title_size); + + const char *skin_title_font; + sq_getstring(vm, -1, &skin_title_font); + + sys->window_skin = new WindowSkin; + + sys->window_skin->top = f->graphic->LoadPicture(t); + sys->window_skin->left = f->graphic->LoadPicture(l); + sys->window_skin->right = f->graphic->LoadPicture(r); + sys->window_skin->bottom = f->graphic->LoadPicture(b); + sys->window_skin->top_left = f->graphic->LoadPicture(tl); + sys->window_skin->top_right = f->graphic->LoadPicture(tr); + sys->window_skin->bottom_left = f->graphic->LoadPicture(bl); + sys->window_skin->bottom_right = f->graphic->LoadPicture(br); + + sys->window_skin->color = skin_color; + sys->window_skin->title_color = skin_title_color; + sys->window_skin->title_top = skin_title_top; + sys->window_skin->title_bottom = skin_title_bottom; + sys->window_skin->title_size = skin_title_size; +// sys->window_skin->title_font = skin_title_font; + + sq_pop(vm, 15); + + sq_pushbool(vm, true); + return 1; +} + +SQInteger UIAddCanvasWidget(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETINT(id) + __SQ_GETINT(w) + __SQ_GETINT(h) + __SQ_GETEND + __SQ_RETURNSAFEPTR(new CanvasWidget((int)id, (int)w, (int)h), typetag_CanvasWidget) +} + +SQInteger CanvasWidgetLock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(c, CanvasWidget, typetag_CanvasWidget) + __SQ_RETURNSAFEPTR(c->Lock(), typetag_Picture) +} + +SQInteger CanvasWidgetUnlock(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(c, CanvasWidget, typetag_CanvasWidget) + c->Unlock(); + __SQ_RETURN +} + +SQInteger UIAddSpacerWidget(HSQUIRRELVM vm) +{ + Scene *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_Scene2d)) + return -1; + SQInteger id; + sq_getinteger(vm, -1, &id); + sq_pop(vm, 2); + + SpacerWidget *wd = NULL; + if (ws) + wd = new SpacerWidget((int)id); + CObject::Push(vm, wd, typetag_SpacerWidget); + return 1; +} + +SQInteger UIAddHorizontalSizerWidget(HSQUIRRELVM vm) +{ + Scene *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_Scene2d)) + return -1; + SQInteger id; + sq_getinteger(vm, -1, &id); + sq_pop(vm, 2); + + SizerWidget *wd = NULL; + if (ws) + wd = new HSizerWidget((int)id); + CObject::Push(vm, wd, typetag_SizerWidget); + return 1; +} + +SQInteger UIAddVerticalSizerWidget(HSQUIRRELVM vm) +{ + Scene *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_Scene2d)) + return -1; + SQInteger id; + sq_getinteger(vm, -1, &id); + sq_pop(vm, 2); + + SizerWidget *wd = NULL; + if (ws) + wd = new VSizerWidget((int)id); + CObject::Push(vm, wd, typetag_SizerWidget); + return 1; +} + +SQInteger UIAddContainerWidget(HSQUIRRELVM vm) +{ + Scene *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_Scene2d)) + return -1; + SQInteger id; + sq_getinteger(vm, -1, &id); + sq_pop(vm, 2); + + ContainerWidget *wd = NULL; + if (ws) + wd = new ContainerWidget((int)id); + CObject::Push(vm, wd, typetag_ContainerWidget); + return 1; +} + +Widget *GetWidget(HSQUIRRELVM vm , int idx) +{ + Widget *wdg = NULL; + CObjectType type; + + if (!CObject::GetType(vm, idx, type)) + return NULL; + + switch (type) + { + case typetag_Widget: + CObject::Get(vm, idx, (void **)&wdg, typetag_Widget); + break; + case typetag_SizerWidget: + CObject::Get(vm, idx, (void **)&wdg, typetag_SizerWidget); + break; + case typetag_CheckWidget: + CObject::Get(vm, idx, (void **)&wdg, typetag_CheckWidget); + break; + case typetag_ContainerWidget: + CObject::Get(vm, idx, (void **)&wdg, typetag_ContainerWidget); + break; + case typetag_SpacerWidget: + CObject::Get(vm, idx, (void **)&wdg, typetag_SpacerWidget); + break; + case typetag_TextWidget: + CObject::Get(vm, idx, (void **)&wdg, typetag_TextWidget); + break; + case typetag_CanvasWidget: + CObject::Get(vm, idx, (void **)&wdg, typetag_CanvasWidget); + break; + case typetag_BitmapWidget: + CObject::Get(vm, idx, (void **)&wdg, typetag_BitmapWidget); + break; + + default: + sq_throwerror(vm, "Object is not a widget"); + return NULL; + } + + if (!wdg) + { + sq_throwerror(vm, "Widget is null"); + return NULL; + } + return wdg; +} + +#define __SQ_GETWIDGET(__VAR__) Widget *__VAR__ = GetWidget(vm, __sq_stackpos); __SQ_GETUPDATESTACK if (!__VAR__) return -1; + +SQInteger CastToWidget(HSQUIRRELVM vm) +{ + Widget *wdg = GetWidget(vm, -1); + if (!wdg) + return -1; + sq_pop(vm, 1); + __SQ_RETURNSAFEPTR(wdg, typetag_Widget) +} + +SQInteger UIDeleteWidget(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETWIDGET(w) + __SQ_GETEND + if (ui && w) _safe_delete(w); + __SQ_RETURN +} + +SQInteger SizerAddWidget(HSQUIRRELVM vm) +{ + SizerWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_SizerWidget)) + return -1; + CObjectType widget_type; + if (!CObject::GetType(vm, -1, widget_type)) + return -1; + + Widget *wdg = GetWidget(vm, -1); + if (!wdg) + return -1; + sq_pop(vm, 2); + + if (ws && wdg) + ws->Add(wdg); + + CObject::Push(vm, wdg, widget_type); + return 1; +} + +SQInteger ContainerAddWidget(HSQUIRRELVM vm) +{ + ContainerWidget *ws; + if (!CObject::Get(vm, -6, (void **)&ws, typetag_ContainerWidget)) + return -1; + + CObjectType widget_type; + if (!CObject::GetType(vm, -5, widget_type)) + return -1; + Widget *wdg = GetWidget(vm, -5); + if (!wdg) + return -1; + + float sx, sy, w, h; + sq_getfloat(vm, -4, &sx); + sq_getfloat(vm, -3, &sy); + sq_getfloat(vm, -2, &w); + sq_getfloat(vm, -1, &h); + sq_pop(vm, 6); + + if (ws && wdg) + { + iRect cell_rect((int)sx, (int)sy, (int)(sx + w), (int)(sy + h)); + ws->Add(wdg, cell_rect); + } + CObject::Push(vm, wdg, widget_type); + return 1; +} + +SQInteger ContainerWidgetSetPosition(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(ws, ContainerWidget, typetag_ContainerWidget) + __SQ_GETWIDGET(wdg) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETEND + + ContainerCell *cell = ws->GetCell(wdg); + if (!cell) + return sq_throwerror(vm, "Widget not in container"); + + cell->cell_rect.Offset(int(x - cell->cell_rect.sx), int(y - cell->cell_rect.sy)); + ws->Invalidate(); + + __SQ_RETURN +} + +//------------------------------------------------------------------------------ +SQInteger WidgetSetEventHandler(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + Widget *widget = GetWidget(vm, __sq_stackpos); + __SQ_GETUPDATESTACK + if (!widget) + return sq_throwerror(vm, "Null widget"); + __SQ_GETINT(event) + __SQ_GETOBJECT(handler) + __SQ_GETEND + widget->GetEventTable()->SetHandler((EventCode)event, new Script::SquirrelObject(*GetVMObject(vm), handler)); + __SQ_RETURN +} +SQInteger WidgetSetEventHandlerWithContext(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + Widget *widget = GetWidget(vm, __sq_stackpos); + __SQ_GETUPDATESTACK + if (!widget) + return sq_throwerror(vm, "Null widget"); + __SQ_GETINT(event) + __SQ_GETOBJECT(context) + __SQ_GETOBJECT(handler) + __SQ_GETEND + widget->GetEventTable()->SetHandler((EventCode)event, new Script::SquirrelObject(*GetVMObject(vm), handler), new Script::SquirrelObject(*GetVMObject(vm), context)); + __SQ_RETURN +} + +SQInteger WindowSetEventHandler(HSQUIRRELVM vm) +{ + __SQ_GETSTART(3) + __SQ_GETSAFEPTR(window, Sprite, typetag_Window) + __SQ_GETINT(event) + __SQ_GETOBJECT(handler) + __SQ_GETEND + window->GetEventTable()->SetHandler((EventCode)event, new Script::SquirrelObject(*GetVMObject(vm), handler)); + __SQ_RETURN +} +SQInteger WindowSetEventHandlerWithContext(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(window, Sprite, typetag_Window) + __SQ_GETINT(event) + __SQ_GETOBJECT(context) + __SQ_GETOBJECT(handler) + __SQ_GETEND + window->GetEventTable()->SetHandler((EventCode)event, new Script::SquirrelObject(*GetVMObject(vm), handler), new Script::SquirrelObject(*GetVMObject(vm), context)); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +SQInteger WidgetSetSensitive(HSQUIRRELVM vm) +{ + Widget *w = GetWidget(vm, -2); + if (!w) + return -1; + SQBool bs; + sq_getbool(vm, -1, &bs); + + w->GetEventTable()->Enable(bs ? true : false); + sq_pop(vm, 2); + return 0; +} + +SQInteger WidgetSetHAlign(HSQUIRRELVM vm) +{ + Widget *w = GetWidget(vm, -2); + if (!w) + return -1; + SQInteger a; + sq_getinteger(vm, -1, &a); + sq_pop(vm, 2); + + w->SetHAlign((Widget::Align)a); + return 0; +} + +SQInteger WidgetSetVAlign(HSQUIRRELVM vm) +{ + Widget *wdg = GetWidget(vm, -2); + if (!wdg) + return -1; + SQInteger a; + sq_getinteger(vm, -1, &a); + sq_pop(vm, 2); + + wdg->SetVAlign((Widget::Align)a); + return 0; +} + +SQInteger WidgetSetHidden(HSQUIRRELVM vm) +{ + Widget *wdg = GetWidget(vm, -2); + if (!wdg) + return -1; + SQBool hidden; + sq_getbool(vm, -1, &hidden); + sq_pop(vm, 2); + + wdg->SetHidden(hidden ? true : false); + return 0; +} + +SQInteger WidgetGetRect(HSQUIRRELVM vm) +{ + Widget *wdg = GetWidget(vm, -1); + if (!wdg) + return -1; + sq_pop(vm, 1); + + iRect rect(-1, -1, -1, -1); + rect = wdg->GetRect(); + PushRect(vm, rect); + return 1; +} + +SQInteger WidgetIsHidden(HSQUIRRELVM vm) +{ + Widget *wdg = GetWidget(vm, -1); + if (!wdg) + return -1; + sq_pop(vm, 1); + __SQ_RETURNBOOL(wdg->IsHidden()) +} + +SQInteger WidgetSetFormattingSize(HSQUIRRELVM vm) +{ + Widget *wdg = GetWidget(vm, -3); + if (!wdg) + return -1; + SQFloat h, v; + sq_getfloat(vm, -2, &h); + sq_getfloat(vm, -1, &v); + sq_pop(vm, 3); + + wdg->SetFormattingSize(Vector2(h, v)); + return 0; +} + +//------------------------------------------------------------------------------ +SQInteger UIAddBitmapWidget(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Sprite, typetag_Scene2d) + __SQ_GETINT(id) + __SQ_GETEND + __SQ_RETURNSAFEPTR(new BitmapWidget((int)id), typetag_BitmapWidget) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +#define __SQ_CHECKWIDGETTYPE(__Type) if (w->GetType() != __Type) return sq_throwerror(vm, "Invalid widget cast."); +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger WidgetToBitmap(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(w, Widget, typetag_Widget) + __SQ_CHECKWIDGETTYPE(WidgetTypeBitmap) + __SQ_RETURNSAFEPTR((BitmapWidget *)w, typetag_BitmapWidget) +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger BitmapSetPicture(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(w, BitmapWidget, typetag_BitmapWidget) + __SQ_GETSAFEPTR(p, Picture, typetag_Picture) + __SQ_GETEND + w->SetPicture(p); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +SQInteger UIAddTextWidget(HSQUIRRELVM vm) +{ + __SQ_GETSTART(4) + __SQ_GETSAFEPTR(ws, Scene, typetag_Scene2d) + __SQ_GETINT(id) + __SQ_GETSTRING(text) + __SQ_GETSAFEPTR(font, FontEx, typetag_Font) + TextWidget *wd = new TextWidget(id, text, font); + __SQ_GETEND + __SQ_RETURNSAFEPTR(wd, typetag_TextWidget) +} + +SQInteger UIAddCheckWidget(HSQUIRRELVM vm) +{ + Scene *ws; + if (!CObject::Get(vm, -5, (void **)&ws, typetag_Scene2d)) + return -1; + SQInteger id; + sq_getinteger(vm, -4, &id); + const char *text; + sq_getstring(vm, -3, &text); + const char *font_name; + sq_getstring(vm, -2, &font_name); + SQBool initial_state; + sq_getbool(vm, -1, &initial_state); + + CheckWidget *wd = NULL; + if (ws) + { +// wd = new CheckWidget(*ws, (int)id, text, Scene::GetFontCache().GetFont(font_name)); + if (wd) + wd->SetState(initial_state ? true : false); + } + sq_pop(vm, 5); // Take care of the strings. + CObject::Push(vm, wd, typetag_CheckWidget); + return 1; +} + +SQInteger CheckWidgetSetState(HSQUIRRELVM vm) +{ + CheckWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_CheckWidget)) + return -1; + SQBool state; + sq_getbool(vm, -1, &state); + sq_pop(vm, 2); + + if (ws) + ws->SetState(state ? true : false); + return 0; +} + +SQInteger CheckWidgetGetState(HSQUIRRELVM vm) +{ + CheckWidget *ws; + if (!CObject::Get(vm, -1, (void **)&ws, typetag_CheckWidget)) + return -1; + sq_pop(vm, 1); + + bool state = false; + if (ws) + state = ws->GetState(); + sq_pushbool(vm, state); + return 1; +} + +SQInteger CheckWidgetSetLabel(HSQUIRRELVM vm) +{ + CheckWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_CheckWidget)) + return -1; + + const char *label = NULL; + sq_getstring(vm, -1, &label); + if (ws) + ws->GetLabel().SetText(label); + sq_pop(vm, 2); // Take care of the string. + return 0; +} + +SQInteger CheckWidgetSetLabelFont(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ws, CheckWidget, typetag_CheckWidget) + __SQ_GETSAFEPTR(font, FontEx, typetag_Font) + __SQ_GETEND + ws->GetLabel().SetFont(font); + __SQ_RETURN +} + +SQInteger CheckWidgetSetLabelSize(HSQUIRRELVM vm) +{ + CheckWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_CheckWidget)) + return -1; + SQInteger size; + sq_getinteger(vm, -1, &size); + sq_pop(vm, 2); + + if (ws) + ws->GetLabel().SetFontSize((int)size); + return 0; +} + +SQInteger CheckWidgetGetText(HSQUIRRELVM vm) +{ + CheckWidget *ws; + if (!CObject::Get(vm, -1, (void **)&ws, typetag_CheckWidget)) + return -1; + sq_pop(vm, 1); + + TextWidget *wt = NULL; + if (ws) + wt = &ws->GetLabel(); + CObject::Push(vm, wt, typetag_TextWidget); + return 1; +} + +SQInteger WidgetToText(HSQUIRRELVM vm) +{ + Widget *ws; + if (!CObject::Get(vm, -1, (void **)&ws, typetag_Widget)) + return -1; + sq_pop(vm, 1); + + TextWidget *wt = NULL; + if (ws) + wt = (TextWidget *)ws; + CObject::Push(vm, wt, typetag_TextWidget); + return 1; +} + +SQInteger WidgetToCheck(HSQUIRRELVM vm) +{ + Widget *ws; + if (!CObject::Get(vm, -1, (void **)&ws, typetag_Widget)) + return -1; + sq_pop(vm, 1); + + CheckWidget *wt = NULL; + if (ws) + wt = (CheckWidget *)ws; + CObject::Push(vm, wt, typetag_CheckWidget); + return 1; +} + +SQInteger TextSetAlignment(HSQUIRRELVM vm) +{ + TextWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_TextWidget)) + return -1; + SQInteger a; + sq_getinteger(vm, -1, &a); + sq_pop(vm, 2); + + if (ws) + ws->SetTextAlignment((TextState::Alignment)a); + return 0; +} + +SQInteger TextSetFormat(HSQUIRRELVM vm) +{ + TextWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_TextWidget)) + return -1; + SQInteger f; + sq_getinteger(vm, -1, &f); + sq_pop(vm, 2); + + if (ws) + ws->SetTextFormat((TextState::Format)f); + return 0; +} + +SQInteger TextSetSize(HSQUIRRELVM vm) +{ + TextWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_TextWidget)) + return -1; + SQInteger s; + sq_getinteger(vm, -1, &s); + sq_pop(vm, 2); + + if (ws) + ws->SetFontSize((int)s); + return 0; +} + +SQInteger TextSetColor(HSQUIRRELVM vm) +{ + TextWidget *ws; + if (!CObject::Get(vm, -5, (void **)&ws, typetag_TextWidget)) + return -1; + SQInteger r, g, b, a; + sq_getinteger(vm, -4, &r); + sq_getinteger(vm, -3, &g); + sq_getinteger(vm, -2, &b); + sq_getinteger(vm, -1, &a); + sq_pop(vm, 5); + + if (ws) + ws->SetFontColor((float)r / 255.f, (float)g / 255.f, (float)b / 255.f, (float)a / 255.f); + return 0; +} + +SQInteger TextSetText(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ws, TextWidget, typetag_TextWidget) + __SQ_GETSTRING(txt) + ws->SetText(txt); + __SQ_GETEND + __SQ_RETURN +} + +SQInteger SizerSetDrawDelimiter(HSQUIRRELVM vm) +{ + sq_pop(vm, 2); + return 0; +} + +SQInteger SizerSetBorderSize(HSQUIRRELVM vm) +{ + SizerWidget *ws; + if (!CObject::Get(vm, -5, (void **)&ws, typetag_SizerWidget)) + return -1; + + SQInteger t, b, l, r; + sq_getinteger(vm, -4, &l); + sq_getinteger(vm, -3, &t); + sq_getinteger(vm, -2, &r); + sq_getinteger(vm, -1, &b); + sq_pop(vm, 5); + + if (ws) + ws->SetBorderSize((float)t, (float)b, (float)l, (float)r); + return 0; +} + +void IterateTextParameters(HSQUIRRELVM vm, int idx, TextState &state) +{ + sq_pushnull(vm); + while (sq_next(vm, idx - 1) != SQ_ERROR) + { + const char *key; + if (sq_getstring(vm, -2, &key) != SQ_ERROR) + { + if (!strcmp(key, "size")) + { + SQInteger size; + sq_getinteger(vm, -1, &size); + state.SetSize(size); + } + else if (!strcmp(key, "color")) + { + SQInteger icolor; + if (sq_getinteger(vm, -1, &icolor) != SQ_ERROR) + { + Color color((uint)icolor); + state.color.x = uint(color.w * 255.f); + state.color.y = uint(color.z * 255.f); + state.color.z = uint(color.y * 255.f); + state.color.w = uint(color.x * 255.f); + } + } + else if (!strcmp(key, "align")) + { + const char *v; + if (sq_getstring(vm, -1, &v) != SQ_ERROR) + { + if (!strcmp(v, "left")) + state.alignment = TextState::Left; + else if (!strcmp(v, "right")) + state.alignment = TextState::Right; + else if (!strcmp(v, "center")) + state.alignment = TextState::Center; + else if (!strcmp(v, "justify")) + state.alignment = TextState::Justify; + else + __LOG_W__ << "unknown text alignment command '" << v << "'.\n"; + } + } + else if (!strcmp(key, "format")) + { + const char *v; + if (sq_getstring(vm, -1, &v) != SQ_ERROR) + { + if (!strcmp(v, "standard")) + state.format = TextState::Line; + else if (!strcmp(v, "paragraph")) + state.format = TextState::Paragraph; + else if (!strcmp(v, "column")) + state.format = TextState::Column; + else + __LOG_W__ << "unknown text format command '" << v << "'.\n"; + } + } + else if (!strcmp(key, "tracking")) + { + SQFloat tracking; + sq_getfloat(vm, -1, &tracking); + state.SetTracking(tracking); + } + else if (!strcmp(key, "leading")) + { + SQFloat leading; + sq_getfloat(vm, -1, &leading); + state.SetLeading(leading); + } + else + __LOG_W__ << "unknown text attribute '" << key << "'.\n"; + } + sq_pop(vm, 2); // pop key/value. + } + sq_pop(vm, 1); // pop iterator. +} + +SQInteger TextSetParameters(HSQUIRRELVM vm) +{ + TextWidget *ws; + if (!CObject::Get(vm, -2, (void **)&ws, typetag_TextWidget)) + return -1; + + TextState state; + ws->GetTextState(state); + IterateTextParameters(vm, -1, state); + ws->SetTextState(state); + + sq_pop(vm, 2); + return 0; +} + +//------------------------------------------------------------------------------ +#define __SQ_GETUISCENESCRIPTOBJECT(__SRC) Script::ScriptedObject *scripted_object = __SRC->scripted_object; if (!scripted_object) return sq_throwerror(vm, "No script system in scene!"); + +SQInteger UIGetScriptInstance(HSQUIRRELVM vm) +{ + __SQ_GETSINGLESAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETUISCENESCRIPTOBJECT(ui) + if (!scripted_object->GetUnitList().GetCount()) + return sq_throwerror(vm, "No script unit"); + Script::SquirrelObject *o = (Script::SquirrelObject *)scripted_object->GetUnitList()[0]->Self(); + __SQ_RETURNOBJECT(o->object); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UICreateCursor(HSQUIRRELVM vm) +{ + __SQ_GETSINGLE(__SQ_GETINT(cursor_id)) + Cursor *cursor = new Cursor; + if (!cursor) + return sq_throwerror(vm, "Failed to create a new UI cursor"); + cursor->id = cursor_id; + __SQ_RETURNMANAGEDSAFEPTR(cursor, typetag_UICursor) +} +SQInteger UISetCursorState(HSQUIRRELVM vm) +{ + __SQ_GETSTART(5) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETSAFEPTR(cursor, Cursor, typetag_UICursor) + __SQ_GETFLOAT(x) + __SQ_GETFLOAT(y) + __SQ_GETBOOL(down) + __SQ_GETEND + cursor->current_state.x = x; + cursor->current_state.y = y; + cursor->current_state.down = asbool(down); + ui->UpdateCursor(cursor); + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SQInteger UISetGlobalMatrix(HSQUIRRELVM vm) +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(ui, Scene, typetag_Scene2d) + __SQ_GETMATRIX3(mtx) + __SQ_GETEND + ui->offset_matrix = mtx; + __SQ_RETURN +} +//------------------------------------------------------------------------------ + +//--------------------------------------------------- +void RegisterUIBinding(HSQUIRRELVM vm) +//--------------------------------------------------- +{ +/*# + Topic: UI + Type: Sprite + Type: Window + Type: Widget + Type: Check + Type: Container + Type: UI + Type: Canvas + Type: Sizer + Type: TextWidget + Type: Bitmap +#*/ + +/*# + Section: SceneIO + Desc: I/O +#*/ + /*# + Func: UILoad + Proto: bool:UI,string + Desc: Append a scene to this scene, returns true on success, false otherwise. + See: UILoadAndStoreGroup + #*/ + sq_register(vm, UIFromNML, "UILoad", _SC(".xs")); + /*# + Func: UILoadAndStoreGroup + Proto: UIGroup:UI scene_to_import_to,string path,ImportFlag import_flag + Desc: Append a scene to this scene, store all appended content in a group. + + Example: +class LevelScene +{ + diablo_ai = 0 + diablo_fist = 0 + + function OnSetup(scene) + { + // Import the Diablo AI character into this scene. + diablo_ai = SceneLoadAndStoreGroup(scene, "enemy/ai/diablo.nms") + } +} + #*/ + sq_register(vm, UIFromNMLStoreGroup, "UILoadAndStoreGroup", _SC(".xsi")); + +/*# + Section: UIManagement + Desc: UI Management +#*/ + /*# + Func: UIRenderSetup + Proto: void:UI,ResourceFactory + Desc: Setup UI render resources. + #*/ + sq_register(vm, UIRenderSetup, "UIRenderSetup", _SC(".xx")); + /*# + Func: UISetGlobalMatrix + Proto: void:UI,Matrix3 + Desc: Set the UI global transformation matrix. + #*/ + sq_register(vm, UISetGlobalMatrix, "UISetGlobalMatrix", _SC(".xx")); + sq_register(vm, UISetGlobalMatrix, "UISetOffsetMatrix", _SC(".xx")); + /*# + Func: UIGetScriptInstance + Proto: Instance:UI + Desc: Return the UI script instance. + #*/ + sq_register(vm, UIGetScriptInstance, "UIGetScriptInstance", _SC(".x")); + /*# + Func: SceneGetUI + Proto: UI:Scene + Desc: Return the scene UI interface. + #*/ + sq_register(vm, SceneGetUI, "SceneGetUI", _SC(".x")); + /*# + Func: UISetVirtualResolution + Proto: void:UI,int width,int height + Desc: Set the UI system virtual resolution in pixels. + #*/ + sq_register(vm, UISetVirtualResolution, "UISetInternalResolution", _SC(".xnn")); // compat + sq_register(vm, UISetVirtualResolution, "UISetVirtualResolution", _SC(".xnn")); + /*# + Func: UIGetVirtualResolution + Proto: Vector2:UI + Desc: Get the UI system virtual resolution in pixels. + #*/ + sq_register(vm, UIGetVirtualResolution, "UIGetInternalResolution", _SC(".x")); // compat + sq_register(vm, UIGetVirtualResolution, "UIGetVirtualResolution", _SC(".x")); + + /*# + Func: UIGetScreenToUIMatrix + Proto: Matrix3:UI + Desc: Return the UI to normalized screen coordinates transformation matrix.
+ This matrix can be used to transform a normalized screen coordinate to a scene coordinate expressed in pixels. + See: UIGetVirtualResolution + Example: +// With a virtual resolution of 1920x1080 pixels. +local scene_coord = Vector2(0.5, 1) * UIGetScreenToUIMatrix(ui) + +// scene_coord now contains Vector2(960.0, 1080.0) + #*/ + sq_register(vm, UIGetScreenToUIMatrix, "UIGetScreenToUIMatrix", _SC(".x")); + /*# + Func: UIGetUIToScreenMatrix + Proto: Matrix3:UI + Desc: Return the normalized screen to UI coordinates transformation matrix.
+ This matrix can be used to transform a scene coordinate expressed in pixels to a normalized screen coordinate between 0 and 1. + See: UIGetVirtualResolution + Example: +// With a virtual resolution of 1920x1080 pixels. +local norm_screen = Vector2(1920, 1080) * UIGetUIToScreenMatrix(ui) + +// norm_screen now contains Vector2(1.0, 1.0) + #*/ + sq_register(vm, UIGetUIToScreenMatrix, "UIGetUIToScreenMatrix", _SC(".x")); + +/*# + Section: UISkin + Desc: UI Skin and Appearance +#*/ + /*# + Func: UISetSkin + Proto: void:UI,GraphicResourceFactory,string bmp_top,string bmp_left,string bmp_right,string bmp_bottom,string bmp_top_left,string bmp_top_right,string bmp_bottom_left,string bmp_bottom_right,int hex_font_color,int hex_title_color,int space_title_top,int space_title_bottom,int title_font_size,string title_font + Desc: Set the UI window system skin. + #*/ + sq_register(vm, UISetSkin, "UISetSkin", _SC(".xxssssssssnnnnns")); + +/*# + Section: UIIO + Desc: UI Cursor +#*/ + /*# + Func: UICreateCursor + Proto: UICursor:int cursor_id + Desc: Create a new UI system cursor. + #*/ + sq_register(vm, UICreateCursor, "UICreateCursor", _SC(".i")); + /*# + Func: UISetCursorState + Proto: void:UI,UICursor,float x,float y,bool down + Desc: Set the current cursor state, the UI system will process cursor events and perform calls to the corresponding handlers. Note: This call will trigger cursor related events immediately. + #*/ + sq_register(vm, UISetCursorState, "UISetCursorState", _SC(".xxnnb")); + /*# + Func: UICursorGetWindowBelow + Proto: Window:UICursor cursor + Desc: Return the window under the cursor, returns null is there is no such window. + #*/ + sq_register(vm, UICursorGetWindowBelow, "UICursorGetWindowBelow", _SC(".x")); + /*# + Func: UICursorGetSpriteBelow + Proto: Sprite:UICursor cursor + Desc: Return the sprite under the cursor, returns null is there is no such sprite. + #*/ + sq_register(vm, UICursorGetSpriteBelow, "UICursorGetSpriteBelow", _SC(".x")); + /*# + Func: UILock + Proto: void:UI,Sprite|Window + Desc: Lock UI to a given sprite/window. All UI cursor events are sent to this sprite/window exclusively until the lock is released. + #*/ + sq_register(vm, UILockToSprite, "UILock", _SC(".xx")); + sq_register(vm, UILockToSprite, "UILockToSprite", _SC(".xx")); + /*# + Func: UIUnlock + Proto: void:UI + Desc: Release the UI sprite/window lock. + #*/ + sq_register(vm, UIUnlock, "UIUnlock", _SC(".x")); + +/*# + Section: UIGlobal + Desc: UI Global Effects +#*/ + /*# + Func: UISetCommandList + Proto: void:UI,string command_list + Desc: Set the UI system ACE command list. + #*/ + sq_register(vm, UISetCommandList, "UISetCommandList", _SC(".xs")); + /*# + Func: UIIsCommandListDone + Proto: bool:UI + Desc: Returns true if the UI system command list unit is not executing, false otherwise. + #*/ + sq_register(vm, UIIsCommandListDone, "UIIsCommandListDone", _SC(".x")); + /*# + Func: UISetGlobalFadeEffect + Proto: void:UI,float fade + Desc: Set the global fade effect intensity (0.0 is fully faded, 1.0 is no effect). + #*/ + sq_register(vm, UISetGlobalFadeEffect, "UISetGlobalFadeEffect", _SC(".xn")); + /*# + Func: UISetGlobalFadeColor + Proto: void:UI,float r,float g,float b + Desc: Set the global fade effect color. + #*/ + sq_register(vm, UISetGlobalFadeColor, "UISetGlobalFadeColor", _SC(".xnnn")); + /*# + Func: UIDeleteAllItems + Proto: void:UI + Desc: Delete all window and sprite in scene. + #*/ + sq_register(vm, UIDeleteAllItems, "UIDeleteAllItems", _SC(".x")); + +/*# + Section: UIItem + Desc: UI Item +#*/ + /*# + Func: UIItemCastToSprite + Proto: Sprite:UIItem item + Desc: Cast an UI item to a UI sprite. + #*/ + sq_register(vm, UIItemCastToSprite, "UIItemCastToSprite", _SC(".x")); + /*# + Func: UIItemCastToWindow + Proto: Window:UIItem item + Desc: Cast an UI item to a UI window. + #*/ + sq_register(vm, UIItemCastToWindow, "UIItemCastToWindow", _SC(".x")); + +/*# + Section: UISprite + Desc: UI Sprite +#*/ + /*# + Func: UIAddSprite + Proto: Window:UI,int id,Texture,float origin_x,float origin_y,float width,float height + Desc: Create a new sprite. Note: This a legacy wrapper where the id integer is converted to a string and used as the sprite name. + #*/ + sq_register(vm, UIAddSprite, "UIAddSprite", _SC(".xixnnnn")); + /*# + Func: UIAddNamedSprite + Proto: Window:UI,string name,Texture,float origin_x,float origin_y,float width,float height + Desc: Create a new sprite. + #*/ + sq_register(vm, UIAddNamedSprite, "UIAddNamedSprite", _SC(".xsxnnnn")); + /*# + Func: UIDeleteSprite + Proto: void:UI,Sprite + Desc: Delete a sprite. + #*/ + sq_register(vm, UIDeleteWindow, "UIDeleteSprite", _SC(".xx")); + + /*# + Func: SpriteGetZOrder + Proto: float:Sprite + Desc: Get the sprite Z-order. + #*/ + sq_register(vm, WindowGetZOrder, "SpriteGetZOrder", _SC(".x")); + /*# + Func: SpriteSetZOrder + Proto: void:Sprite,float + Desc: Set the sprite Z-order. + #*/ + sq_register(vm, WindowSetZOrder, "SpriteSetZOrder", _SC(".xn")); + /*# + Func: SpriteSetUVOrigin + Proto: void:Sprite,float u,float v + Desc: Set the sprite UV origin in pixels. + #*/ + sq_register(vm, SpriteSetUVOrigin, "SpriteSetUVOrigin", _SC(".xnn")); + /*# + Func: SpriteSetTexture + Proto: void:Window,Texture + Desc: Set the sprite texture. + #*/ + sq_register(vm, SpriteSetTexture, "SpriteSetTexture", _SC(".xx")); + /*# + Func: WebcamTextureBlit + Proto: void:Texture, pointer with a int + Desc: blit the webcam texture to the texture. + #*/ + sq_register(vm, WebcamTextureBlit, "WebcamTextureBlit", _SC(".xi")); + /*# + Func: SpriteSetTextureMatrix + Proto: void:Window,Matrix3 + Desc: Set the sprite texture matrix. Note: Do not forget to enable the transform UV style on the sprite for the matrix to be used. + #*/ + sq_register(vm, SpriteSetTextureMatrix, "SpriteSetTextureMatrix", _SC(".xx")); + /*# + Func: SpriteRenderSetup + Proto: void:Sprite,ResourceFactory + Desc: Setup the sprite render data. + #*/ + sq_register(vm, SpriteRenderSetup, "SpriteRenderSetup", _SC(".xx")); + + /*# + Func: SpriteGetRect + Proto: Rect:Sprite + Desc: Return the sprite rect. + #*/ + sq_register(vm, WindowGetRect, "SpriteGetRect", _SC(".x")); + /*# + Func: SpriteGetScreenRect + Proto: Rect:Sprite + Desc: Return the sprite rect in the virtual screen coordinate system. + #*/ + sq_register(vm, WindowGetScreenRect, "SpriteGetScreenRect", _SC(".x")); + + /*# + Func: SpriteSetCommandList + Proto: void:Sprite,string command_list + Desc: Set the sprite command list. + #*/ + sq_register(vm, WindowSetCommandList, "SpriteSetCommandList", _SC(".xs")); + /*# + Func: SpriteResetCommandList + Proto: void:Sprite + Desc: Reset the sprite ACE unit. + #*/ + sq_register(vm, WindowResetCommandList, "SpriteResetCommandList", _SC(".x")); + /*# + Func: SpriteIsCommandListDone + Proto: bool:Sprite + Desc: Returns true if the sprite ACE unit is idle, false otherwise. + #*/ + sq_register(vm, WindowIsCommandListDone, "SpriteIsCommandListDone", _SC(".x")); + + /*# + Func: SpriteGetName + Proto: string:Sprite + Desc: Get the sprite name. + #*/ + sq_register(vm, WindowGetName, "SpriteGetName", _SC(".x")); + + /*# + Func: SpriteGetParent + Proto: Window|Sprite:Sprite + Desc: Get the sprite parent. + #*/ + sq_register(vm, WindowGetParent, "SpriteGetParent", _SC(".x")); + /*# + Func: SpriteSetParent + Proto: void:Sprite,Window|Sprite + Desc: Set the sprite parent window or sprite. + #*/ + sq_register(vm, WindowSetParent, "SpriteSetParent", _SC(".xx")); + + /*# + Func: SpriteGetPosition + Proto: Vector2:Sprite + Desc: Get the sprite position as a vector. + #*/ + sq_register(vm, WindowGetPosition, "SpriteGetPosition", _SC(".x")); + /*# + Func: SpriteSetPosition + Proto: void:Sprite,float x,float y + Desc: Set the sprite position. + #*/ + sq_register(vm, WindowSetPosition, "SpriteSetPosition", _SC(".xnn")); + /*# + Func: SpriteSetRotation + Proto: void:Sprite,float angle + Desc: Set the sprite rotation (use the Deg() or Rad() macros to specify the unit). + #*/ + sq_register(vm, WindowSetRotation, "SpriteSetRotation", _SC(".xn")); + /*# + Func: SpriteGetSize + Proto: Vector2:Sprite + Desc: Get the sprite size as a vector. + #*/ + sq_register(vm, WindowGetSize, "SpriteGetSize", _SC(".x")); + /*# + Func: SpriteSetSize + Proto: void:sprite,float width,float height + Desc: Set the sprite size. + #*/ + sq_register(vm, WindowSetSize, "SpriteSetSize", _SC(".xnn")); + /*# + Func: SpriteGetPivot + Proto: Vector2:Sprite + Desc: Get the sprite pivot. + #*/ + sq_register(vm, WindowGetPivot, "SpriteGetPivot", _SC(".x")); + /*# + Func: SpriteSetPivot + Proto: void:Sprite,float pivot_x,float pivot_y + Desc: Set the sprite pivot. + #*/ + sq_register(vm, WindowSetPivot, "SpriteSetPivot", _SC(".xnn")); + /*# + Func: SpriteSetScale + Proto: void:Sprite,float scale_x,float scale_y + Desc: Set the sprite scale. + #*/ + sq_register(vm, WindowSetScale, "SpriteSetScale", _SC(".xnn")); + /*# + Func: SpriteGetOpacity + Proto: float:sprite + Desc: Get the sprite opacity. + #*/ + sq_register(vm, WindowGetOpacity, "SpriteGetOpacity", _SC(".x")); + /*# + Func: SpriteSetOpacity + Proto: void:Sprite,float opacity + Desc: Set the sprite opacity. + #*/ + sq_register(vm, WindowSetOpacity, "SpriteSetOpacity", _SC(".xn")); + /*# + Func: SpriteSetFlip + Proto: void:Sprite,bool flip_horizontal,bool flip_vertical + Desc: Flip the sprite on one or both axises. + #*/ + sq_register(vm, WindowSetFlip, "SpriteSetFlip", _SC(".xbb")); + /*# + Func: SpriteGetStyle + Proto: SpriteStyle:Sprite + Desc: Get the sprite style bitflag. + #*/ + sq_register(vm, WindowGetStyle, "SpriteGetStyle", _SC(".x")); + /*# + Func: SpriteSetStyle + Proto: void:Sprite,SpriteStyle style + Desc: Set the sprite style bitflag. + #*/ + sq_register(vm, WindowSetStyle, "SpriteSetStyle", _SC(".xi")); + /*# + Func: SpriteAddStyle + Proto: void:Sprite,SpriteStyle style + Desc: Add a style to the sprite style bitflag. + #*/ + sq_register(vm, WindowAddStyle, "SpriteAddStyle", _SC(".xi")); + /*# + Func: SpriteRemoveStyle + Proto: void:Sprite,SpriteStyle style + Desc: Remove a style from the sprite style bitflag. + #*/ + sq_register(vm, WindowRemoveStyle, "SpriteRemoveStyle", _SC(".xi")); + + /*# + Func: UISpriteCentre + Proto: void:UI,Sprite + Desc: Centre a sprite on screen. + #*/ + sq_register(vm, UIWindowCentre, "UISpriteCentre", _SC(".x")); + + /*# + Func: SpriteSetEventHandler + Proto: void:Sprite,UIEvent event,function callback + Desc: Set a native Squirrel function as the callback function to a specific UI event. + #*/ + sq_register(vm, WindowSetEventHandler, "SpriteSetEventHandler", _SC(".xnc")); + /*# + Func: SpriteSetEventHandlerWithContext + Proto: void:Sprite,UIEvent event,instance context,function callback + Desc: Set a native Squirrel function as the callback function to a specific UI event, the calling context can be specified (eg. a class instance to callback to one of its member function). + #*/ + sq_register(vm, WindowSetEventHandlerWithContext, "SpriteSetEventHandlerWithContext", _SC(".xn.c")); + +/*# + Section: UIWindow + Desc: UI Window +#*/ + /*# + Func: UIAddNamedWindow + Proto: Window:UI,string name,float origin_x,float origin_y,float width,float height + Desc: Create a new named window. + #*/ + sq_register(vm, UIAddNamedWindow, "UIAddNamedWindow", _SC(".xsnnnn")); + /*# + Func: UIAddNamedBitmapWindow + Proto: Window:UI,String name,Picture,float origin_x,float origin_y,float width,float height + Desc: Create a new named bitmap window. + #*/ + sq_register(vm, UIAddNamedBitmapWindow, "UIAddNamedBitmapWindow", _SC(".xsxnnnn")); + /*# + Func: UIDeleteWindow + Proto: void:UI,Window + Desc: Delete a window. + #*/ + sq_register(vm, UIDeleteWindow, "UIDeleteWindow", _SC(".xx")); + + /*# + Func: WindowGetZOrder + Proto: float:Window + Desc: Get the window Z-order. + #*/ + sq_register(vm, WindowGetZOrder, "WindowGetZOrder", _SC(".x")); + /*# + Func: WindowSetZOrder + Proto: void:Window,float + Desc: Set the window Z-order. + #*/ + sq_register(vm, WindowSetZOrder, "WindowSetZOrder", _SC(".xn")); + /*# + Func: WindowSetTitle + Proto: void:window,string title + Desc: Set the window title. + #*/ + sq_register(vm, WindowSetTitle, "WindowSetTitle", _SC(".xs")); + /*# + Func: WindowGetTitle + Proto: string:window + Desc: Get the window title. + #*/ + sq_register(vm, WindowGetTitle, "WindowGetTitle", _SC(".x")); + /*# + Func: WindowSetBaseWidget + Proto: void:window,widget + Desc: Set the window base widget. + #*/ + sq_register(vm, WindowSetBaseWidget, "WindowSetBaseWidget", _SC(".xx")); + + /*# + Func: WindowGetRect + Proto: Rect:Window + Desc: Return the window rect. + #*/ + sq_register(vm, WindowGetRect, "WindowGetRect", _SC(".x")); + /*# + Func: WindowGetScreenRect + Proto: Rect:Window + Desc: Return the window rect in the virtual screen coordinate system. + #*/ + sq_register(vm, WindowGetScreenRect, "WindowGetScreenRect", _SC(".x")); + + /*# + Func: WindowSetCommandList + Proto: void:window,string command_list + Desc: Set the window command list. + #*/ + sq_register(vm, WindowSetCommandList, "WindowSetCommandList", _SC(".xs")); + /*# + Func: WindowResetCommandList + Proto: void:window + Desc: Reset the window ACE unit. + #*/ + sq_register(vm, WindowResetCommandList, "WindowResetCommandList", _SC(".x")); + /*# + Func: WindowIsCommandListDone + Proto: bool:window + Desc: Returns true if the window ACE unit is idle, false otherwise. + #*/ + sq_register(vm, WindowIsCommandListDone, "WindowIsCommandListDone", _SC(".x")); + + /*# + Func: WindowGetName + Proto: string:window + Desc: Get the window name. + #*/ + sq_register(vm, WindowGetName, "WindowGetName", _SC(".x")); + + /*# + Func: WindowGetChild + Proto: widget:window,int id + Desc: Get a window widget from its id. + #*/ + sq_register(vm, WindowGetChild, "WindowGetChild", _SC(".xn")); + /*# + Func: WindowGetParent + Proto: Window|Sprite:Window + Desc: Get the window parent. + #*/ + sq_register(vm, WindowGetParent, "WindowGetParent", _SC(".x")); + /*# + Func: WindowSetParent + Proto: void:Window,Window|Sprite + Desc: Set the window parent window or sprite. + #*/ + sq_register(vm, WindowSetParent, "WindowSetParent", _SC(".xx")); + + /*# + Func: WindowGetPosition + Proto: Vector2:Window + Desc: Get the window position as a vector. + #*/ + sq_register(vm, WindowGetPosition, "WindowGetPosition", _SC(".x")); + /*# + Func: WindowSetPosition + Proto: void:Window,float x,float y + Desc: Set the window position. + #*/ + sq_register(vm, WindowSetPosition, "WindowSetPosition", _SC(".xnn")); + /*# + Func: WindowSetRotation + Proto: void:Window,float angle + Desc: Set the window rotation (use the Deg() or Rad() macros to specify the unit). + #*/ + sq_register(vm, WindowSetRotation, "WindowSetRotation", _SC(".xn")); + /*# + Func: WindowGetSize + Proto: Vector2:Window + Desc: Get the window size as a vector. + #*/ + sq_register(vm, WindowGetSize, "WindowGetSize", _SC(".x")); + /*# + Func: WindowSetSize + Proto: void:Window,float width,float height + Desc: Set the window size. + #*/ + sq_register(vm, WindowSetSize, "WindowSetSize", _SC(".xnn")); + /*# + Func: WindowGetPivot + Proto: Vector2:Window + Desc: Get the window pivot. + #*/ + sq_register(vm, WindowGetPivot, "WindowGetPivot", _SC(".x")); + /*# + Func: WindowSetPivot + Proto: void:Window,float pivot_x,float pivot_y + Desc: Set the window pivot. + #*/ + sq_register(vm, WindowSetPivot, "WindowSetPivot", _SC(".xnn")); + /*# + Func: WindowSetScale + Proto: void:Window,float scale_x,float scale_y + Desc: Set the window scale. + #*/ + sq_register(vm, WindowSetScale, "WindowSetScale", _SC(".xnn")); + /*# + Func: WindowGetOpacity + Proto: float:Window + Desc: Get the window opacity. + #*/ + sq_register(vm, WindowGetOpacity, "WindowGetOpacity", _SC(".x")); + /*# + Func: WindowSetOpacity + Proto: void:Window,float opacity + Desc: Set the window opacity. + #*/ + sq_register(vm, WindowSetOpacity, "WindowSetOpacity", _SC(".xn")); + /*# + Func: WindowSetFlip + Proto: void:Window,bool flip_horizontal,bool flip_vertical + Desc: Flip the window on one or both axises. + #*/ + sq_register(vm, WindowSetFlip, "WindowSetFlip", _SC(".xbb")); + /*# + Func: WindowGetStyle + Proto: SpriteStyle:Window + Desc: Get the window style bitflag. + #*/ + sq_register(vm, WindowGetStyle, "WindowGetStyle", _SC(".x")); + /*# + Func: WindowSetStyle + Proto: void:Window,SpriteStyle style + Desc: Set the window style bitflag. + #*/ + sq_register(vm, WindowSetStyle, "WindowSetStyle", _SC(".xn")); + /*# + Func: WindowAddStyle + Proto: void:Window,SpriteStyle style + Desc: Add a style to the window style bitflag. + #*/ + sq_register(vm, WindowAddStyle, "WindowAddStyle", _SC(".xn")); + /*# + Func: WindowRemoveStyle + Proto: void:Window,SpriteStyle style + Desc: Remove a style from the window style bitflag. + #*/ + sq_register(vm, WindowRemoveStyle, "WindowRemoveStyle", _SC(".xn")); + + /*# + Func: WindowGetBackgroundPicture + Proto: Picture:Window + Desc: Get the window background picture. + #*/ + sq_register(vm, WindowGetBackgroundPicture, "WindowGetBackgroundPicture", _SC(".x")); + /*# + Func: WindowSetBackgroundPicture + Proto: void:Window,Picture + Desc: Set the window background picture. + #*/ + sq_register(vm, WindowSetBackgroundPicture, "WindowSetBackgroundPicture", _SC(".xx")); + /*# + Func: WindowSetBackgroundColor + Proto: void:Window,int hex_color + Desc: Set the window background color. + #*/ + sq_register(vm, WindowSetBackgroundColor, "WindowSetBackgroundColor", _SC(".xn")); + + /*# + Func: UIWindowCentre + Proto: void:UI,Window + Desc: Centre the window on screen. + #*/ + sq_register(vm, UIWindowCentre, "UIWindowCentre", _SC(".xx")); + + /*# + Func: WindowForceLayout + Proto: void:Window + Desc: Force a complete update of the window layout. + #*/ + sq_register(vm, WindowForceLayout, "WindowForceLayout", _SC(".x")); + /*# + Func: WindowInvalidate + Proto: void:Window + Desc: Force a complete update of the window layout and content. + #*/ + sq_register(vm, WindowInvalidate, "WindowInvalidate", _SC(".x")); + /*# + Func: WindowGetCacheTexture + Proto: texture:Window + Desc: Returns the texture object that is used to display the window via the engine renderer. + #*/ + sq_register(vm, WindowGetCacheTexture, "WindowGetCacheTexture", _SC(".x")); + + /*# + Func: WindowSetEventHandler + Proto: void:Window,UIEvent event,function callback + Desc: Set a native Squirrel function as the callback function to a specific UI event. + #*/ + sq_register(vm, WindowSetEventHandler, "WindowSetEventHandler", _SC(".xnc")); + /*# + Func: WindowSetEventHandlerWithContext + Proto: void:Window,UIEvent event,instance context,function callback + Desc: Set a native Squirrel function as the callback function to a specific UI event, the calling context can be specified (eg. a class instance to callback to one of its member function). + #*/ + sq_register(vm, WindowSetEventHandlerWithContext, "WindowSetEventHandlerWithContext", _SC(".xn.c")); + + /*# + Func: WindowRenderSetup + Proto: void:Window,ResourceFactory + Desc: Setup the window render data. + #*/ + sq_register(vm, SpriteRenderSetup, "WindowRenderSetup", _SC(".xx")); + +/*# + Section: UIWidget + Desc: UI Widget +#*/ + /*# + Func: UIDeleteWidget + Proto: void:UI,Widget + Desc: Delete a widget. + #*/ + sq_register(vm, UIDeleteWidget, "UIDeleteWidget", _SC(".xx")); + /*# + Func: UIAddCanvasWidget + Proto: Widget:UI,int id,int width,int height + Desc: Create a new canvas widget. + #*/ + sq_register(vm, UIAddCanvasWidget, "UIAddCanvasWidget", _SC(".xnnn")); + /*# + Func: UIAddHorizontalSizerWidget + Proto: Widget:UI,int id + Desc: Create a new horizontal sizer widget. + #*/ + sq_register(vm, UIAddHorizontalSizerWidget, "UIAddHorizontalSizerWidget", _SC(".xn")); + /*# + Func: UIAddVerticalSizerWidget + Proto: Widget:UI,int id + Desc: Create a new vertical sizer widget. + #*/ + sq_register(vm, UIAddVerticalSizerWidget, "UIAddVerticalSizerWidget", _SC(".xn")); + /*# + Func: UIAddContainerWidget + Proto: Widget:UI,int id + Desc: Create a new container widget. + #*/ + sq_register(vm, UIAddContainerWidget, "UIAddContainerWidget", _SC(".xn")); + /*# + Func: UIAddSpacerWidget + Proto: Widget:UI,int id + Desc: Create a new spacer widget. + #*/ + sq_register(vm, UIAddSpacerWidget, "UIAddSpacerWidget", _SC(".xn")); + /*# + Func: UIAddBitmapWidget + Proto: Widget:UI,int id + Desc: Create a new bitmap widget. + #*/ + sq_register(vm, UIAddBitmapWidget, "UIAddBitmapWidget", _SC(".xn")); + /*# + Func: UIAddTextWidget + Proto: TextWidget:UI,int id,string text,Font font + Desc: Create a new static text widget. + #*/ + sq_register(vm, UIAddTextWidget, "UIAddTextWidget", _SC(".xnsx")); + /*# + Func: UIAddCheckWidget + Proto: Widget:UI,int id,string text,string font,bool initial_state + Desc: Create a new checkbox widget. + #*/ + sq_register(vm, UIAddCheckWidget, "UIAddCheckWidget", _SC(".xnssb")); + +/*# + Section: CanvasWidget + Desc: Widget Canvas, a freely drawable widget +#*/ + /*# + Func: CanvasWidgetLock + Proto: picture:canvas + Desc: Lock the widget returning a user drawable picture object. + #*/ + sq_register(vm, CanvasWidgetLock, "CanvasWidgetLock", _SC(".x")); + /*# + Func: CanvasWidgetUnlock + Proto: void:canvas + Desc: Unlock this widget canvas.
Note: The picture object obtained through CanvasWidgetLock is not valid after calling this function. + #*/ + sq_register(vm, CanvasWidgetUnlock, "CanvasWidgetUnlock", _SC(".x")); + +/*# + Section: SizerWidget + Desc: Widget Sizer +#*/ + /*# + Func: SizerSetDrawDelimiter + Proto: void:sizer,bool draw + Desc: Draw/hide sizer delimiter. + #*/ + sq_register(vm, SizerSetDrawDelimiter, "SizerSetDrawDelimiter", _SC(".xb")); + /*# + Func: SizerSetBorderSize + Proto: void:sizer,int left,int top,int right,int bottom + Desc: Set sizer border size. + #*/ + sq_register(vm, SizerSetBorderSize, "SizerSetBorderSize", _SC(".xnnnn")); + /*# + Func: SizerAddWidget + Proto: void:sizer,widget + Desc: Add a widget to a sizer. + #*/ + sq_register(vm, SizerAddWidget, "SizerAddWidget", _SC(".xx")); + +/*# + Section: ContainerWidget + Desc: Widget Container +#*/ + /*# + Func: ContainerAddWidget + Proto: void:container,widget,float origin_x,float origin_y,float width,float height + Desc: Add a widget at specified position to the container. + #*/ + sq_register(vm, ContainerAddWidget, "ContainerAddWidget", _SC(".xxnnnn")); + /*# + Func: ContainerWidgetSetPosition + Proto: void:container,widget,float origin_x,float origin_y + Desc: Set a widget position in its container. + #*/ + sq_register(vm, ContainerWidgetSetPosition, "ContainerWidgetSetPosition", _SC(".xxnn")); + +/*# + Section: BitmapWidget + Desc: Widget Bitmap +#*/ + /*# + Func: BitmapSetPicture + Proto: void:bitmap,string bitmap + Desc: Set bitmap widget bitmap from resource. + #*/ + sq_register(vm, BitmapSetPicture, "BitmapSetPicture", _SC(".xs")); + +/*# + Section: TextWidget + Desc: Widget Text +#*/ + /*# + Func: TextSetAlignment + Proto: void:TextWidget,TextAlign align + Desc: Set widget text alignment method. + #*/ + sq_register(vm, TextSetAlignment, "TextSetAlignment", _SC(".xn")); + /*# + Func: TextSetFormat + Proto: void:TextWidget,TextFormat format + Desc: Set widget text formatting method. + #*/ + sq_register(vm, TextSetFormat, "TextSetFormat", _SC(".xn")); + /*# + Func: TextSetSize + Proto: void:TextWidget,int size + Desc: Set widget text font size. + #*/ + sq_register(vm, TextSetSize, "TextSetSize", _SC(".xn")); + /*# + Func: TextSetColor + Proto: void:TextWidget,int r,int g,int b,int a + Desc: Set widget text color. + #*/ + sq_register(vm, TextSetColor, "TextSetColor", _SC(".xnnnn")); + /*# + Func: TextSetText + Proto: void:TextWidget,string text + Desc: Set widget text. + #*/ + sq_register(vm, TextSetText, "TextSetText", _SC(".xs")); + /*# + Func: TextSetParameters + Proto: void:TextWidget,table param + Desc: Set widget text parameters.
+ The following table keys are available:
+
    +
  • 'color': Hexadecimal RGBA (eg. Red: xff0000ff) +
  • 'align': TextAlign +
  • 'format': TextFormat +
  • 'tracking': Integer value specifying an extra space between glyphs. +
  • 'heading': Integer value specifying an extra space between lines. +
+ #*/ + sq_register(vm, TextSetParameters, "TextSetParameters", _SC(".xt")); + +/*# + Section: CheckWidget + Desc: Widget Check +#*/ + /*# + Func: CheckWidgetSetLabel + Proto: void:check,string text + Desc: Set check widget text label. + #*/ + sq_register(vm, CheckWidgetSetLabel, "CheckWidgetSetLabel", _SC(".xs")); + /*# + Func: CheckWidgetSetLabelFont + Proto: void:Check,Font font + Desc: Set check widget text font. + #*/ + sq_register(vm, CheckWidgetSetLabelFont, "CheckWidgetSetLabelFont", _SC(".xx")); + /*# + Func: CheckWidgetSetLabelSize + Proto: void:check,int size + Desc: Set check widget font size. + #*/ + sq_register(vm, CheckWidgetSetLabelSize, "CheckWidgetSetLabelSize", _SC(".xn")); + /*# + Func: CheckWidgetSetState + Proto: void:check,bool state + Desc: Set check widget state. + #*/ + sq_register(vm, CheckWidgetSetState, "CheckWidgetSetState", _SC(".xb")); + /*# + Func: CheckWidgetGetState + Proto: bool:check + Desc: Get check widget state. + #*/ + sq_register(vm, CheckWidgetGetState, "CheckWidgetGetState", _SC(".x")); + /*# + Func: CheckWidgetGetText + Proto: string:check + Desc: Get check widget text label. + #*/ + sq_register(vm, CheckWidgetGetText, "CheckWidgetGetText", _SC(".x")); + +/*# + Section: MiscWidget + Desc: Widget +#*/ + /*# + Func: WidgetToBitmap + Proto: bitmap:widget + Desc: Cast widget to bitmap widget. + #*/ + sq_register(vm, WidgetToBitmap, "WidgetToBitmap", _SC(".x")); + /*# + Func: WidgetToText + Proto: text:widget + Desc: Cast widget to static text widget. + #*/ + sq_register(vm, WidgetToText, "WidgetToText", _SC(".x")); + /*# + Func: WidgetToCheck + Proto: check:widget + Desc: Cast widget to check widget. + #*/ + sq_register(vm, WidgetToCheck, "WidgetToCheck", _SC(".x")); + + /*# + Func: WidgetSetEventHandler + Proto: void:widget,UIEvent event,function callback + Desc: Set a native Squirrel function as the widget event callback. + #*/ + sq_register(vm, WidgetSetEventHandler, "WidgetSetEventHandler", _SC(".xnc")); + /*# + Func: WidgetSetEventHandlerWithContext + Proto: void:widget,UIEvent event,instance context,function callback + Desc: Set a native Squirrel function in a specific context (ie. a class) as a widget event callback. + #*/ + sq_register(vm, WidgetSetEventHandlerWithContext, "WidgetSetEventHandlerWithContext", _SC(".xn.c")); + /*# + Func: WidgetSetSensitive + Proto: void:widget,bool sensitive + Desc: Enable/disable mouse/keyboard event on a widget. + #*/ + sq_register(vm, WidgetSetSensitive, "WidgetSetSensitive", _SC(".xb")); + /*# + Func: WidgetGetRect + Proto: rect:widget + Desc: Return widget rect in window space. + #*/ + sq_register(vm, WidgetGetRect, "WidgetGetRect", _SC(".x")); + /*# + Func: WidgetSetHAlign + Proto: void:widget,WidgetAlign alignment + Desc: Set widget horizontal alignment. + #*/ + sq_register(vm, WidgetSetHAlign, "WidgetSetHAlign", _SC(".xn")); + /*# + Func: WidgetSetVAlign + Proto: void:widget,WidgetAlign alignment + Desc: Set widget vertical alignment. + #*/ + sq_register(vm, WidgetSetVAlign, "WidgetSetVAlign", _SC(".xn")); + /*# + Func: WidgetSetHidden + Proto: void:widget,bool hidden + Desc: Show/hide widget. + #*/ + sq_register(vm, WidgetSetHidden, "WidgetSetHidden", _SC(".xb")); + /*# + Func: WidgetIsHidden + Proto: bool:widget + Desc: Return true if the widget is hidden, false otherwise. + #*/ + sq_register(vm, WidgetIsHidden, "WidgetIsHidden", _SC(".x")); + /*# + Func: WidgetSetFormattingSize + Proto: void:widget,float ratio_x,float ratio_y + Desc: Set widget formatting size ratio. + #*/ + sq_register(vm, WidgetSetFormattingSize, "WidgetSetFormattingSize", _SC(".xnn")); + /*# + Func: CastToWidget + Proto: Widget:WidgetDerived + Desc: Cast any complex widget (such as containers, sizer, etc...) to its base widget. + #*/ + sq_register(vm, CastToWidget, "CastToWidget", _SC(".x")); + + // Push defines. + sq_pushroottable(vm); + + sq_pushstring(vm, "NullWindow", -1); CObject::Push(vm, NULL, typetag_Window); sq_newslot(vm, -3, true); + + /*# + Enum: SpriteStyle + Values: StyleBlendAdditive,StyleBlendOpaque,StyleNonSensitive,StyleResolutionInvariant, + StyleNoDecoration,StyleTransformUV,StyleNoTitleBar,StyleMovable,StyleSnapToPixel + #*/ + sq_pushstring(vm, "StyleBlendAdditive", -1); sq_pushinteger(vm, Sprite::FlagBlendAdditive); sq_newslot(vm, -3, true); + sq_pushstring(vm, "StyleNonSensitive", -1); sq_pushinteger(vm, Sprite::FlagNonSensitive); sq_newslot(vm, -3, true); + sq_pushstring(vm, "StyleResolutionInvariant", -1); sq_pushinteger(vm, Sprite::FlagResolutionInvariant); sq_newslot(vm, -3, true); + sq_pushstring(vm, "StyleTransformUV", -1); sq_pushinteger(vm, Sprite::FlagTransformUV); sq_newslot(vm, -3, true); + sq_pushstring(vm, "StyleSnapToPixel", -1); sq_pushinteger(vm, Sprite::FlagSnapToPixel); sq_newslot(vm, -3, true); + sq_pushstring(vm, "StyleBlendOpaque", -1); sq_pushinteger(vm, Sprite::FlagBlendOpaque); sq_newslot(vm, -3, true); +#if 1 + sq_pushstring(vm, "StyleNoBlend", -1); sq_pushinteger(vm, Sprite::FlagBlendOpaque); sq_newslot(vm, -3, true); // COMPAT +#endif + + /*# + Enum: WindowStyle + Values: StyleNoDecoration,StyleNoTitleBar + #*/ + sq_pushstring(vm, "StyleNoDecoration", -1); sq_pushinteger(vm, Window::FlagNoDecoration); sq_newslot(vm, -3, true); + sq_pushstring(vm, "StyleNoTitleBar", -1); sq_pushinteger(vm, Window::FlagNoTitleBar); sq_newslot(vm, -3, true); + + /*# + Enum: WidgetAlign + Values: WidgetAlignDefault,WidgetAlignLeft,WidgetAlignTop,WidgetAlignMiddle,WidgetAlignRight,WidgetAlignBottom + #*/ + sq_pushstring(vm, "WidgetAlignDefault", -1); sq_pushinteger(vm, Widget::AlignNone); sq_newslot(vm, -3, true); + sq_pushstring(vm, "WidgetAlignLeft", -1); sq_pushinteger(vm, Widget::AlignLeft); sq_newslot(vm, -3, true); + sq_pushstring(vm, "WidgetAlignTop", -1); sq_pushinteger(vm, Widget::AlignTop); sq_newslot(vm, -3, true); + sq_pushstring(vm, "WidgetAlignMiddle", -1); sq_pushinteger(vm, Widget::AlignMiddle); sq_newslot(vm, -3, true); + sq_pushstring(vm, "WidgetAlignRight", -1); sq_pushinteger(vm, Widget::AlignRight); sq_newslot(vm, -3, true); + sq_pushstring(vm, "WidgetAlignBottom", -1); sq_pushinteger(vm, Widget::AlignBottom); sq_newslot(vm, -3, true); + + /*# + Enum: TextAlign + Desc: Text alignment. + Values: TextAlignLeft,TextAlignRight,TextAlignCenter,TextAlignJustify + #*/ + sq_pushstring(vm, "TextAlignLeft", -1); sq_pushinteger(vm, TextState::Left); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TextAlignRight", -1); sq_pushinteger(vm, TextState::Right); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TextAlignCenter", -1); sq_pushinteger(vm, TextState::Center); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TextAlignJustify", -1); sq_pushinteger(vm, TextState::Justify); sq_newslot(vm, -3, true); + + /*# + Enum: TextFormat + Desc: Text formatting. + Values: TextFormatStandard,TextFormatParagraph,TextFormatLine,TextFormatColumn + #*/ + sq_pushstring(vm, "TextFormatStandard", -1); sq_pushinteger(vm, TextState::Line); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TextFormatLine", -1); sq_pushinteger(vm, TextState::Line); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TextFormatParagraph", -1); sq_pushinteger(vm, TextState::Paragraph); sq_newslot(vm, -3, true); + sq_pushstring(vm, "TextFormatColumn", -1); sq_pushinteger(vm, TextState::Column); sq_newslot(vm, -3, true); + + /*# + Enum: UIEvent + Values: EventCursorDown,EventCursorHit,EventCursorUp, + EventCursorEnter,EventCursorLeave,EventCursorMove + #*/ + sq_pushstring(vm, "EventCursorDown", -1); sq_pushinteger(vm, Event_CursorDown); sq_newslot(vm, -3, true); + sq_pushstring(vm, "EventCursorHit", -1); sq_pushinteger(vm, Event_CursorHit); sq_newslot(vm, -3, true); + sq_pushstring(vm, "EventCursorUp", -1); sq_pushinteger(vm, Event_CursorUp); sq_newslot(vm, -3, true); + sq_pushstring(vm, "EventCursorEnter", -1); sq_pushinteger(vm, Event_CursorEnter); sq_newslot(vm, -3, true); + sq_pushstring(vm, "EventCursorLeave", -1); sq_pushinteger(vm, Event_CursorLeave); sq_newslot(vm, -3, true); + sq_pushstring(vm, "EventCursorMove", -1); sq_pushinteger(vm, Event_CursorMove); sq_newslot(vm, -3, true); + + sq_pop(vm, 1); +} diff --git a/include/modules/script_squirrel/legacy/wii_binding.cpp b/include/modules/script_squirrel/legacy/wii_binding.cpp new file mode 100644 index 0000000..4babdd0 --- /dev/null +++ b/include/modules/script_squirrel/legacy/wii_binding.cpp @@ -0,0 +1,644 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + +#if __PLATFORM_NINTENDO_WII__ + + + #include "squirrel_binding.h" + #include "binding_helpers.h" + #include "uc_binding.h" + + #include + #include + + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + + #include "Wii_platform.h" + +//--------------------------------------------------------- +WIIHome Wii::HomeMenu ATTRIBUTE_ALIGN(32); + +nWiiMixer* Wii::Mixer = NULL; +WiiSaveMngr Wii::Save; +nWiiGXRenderer* Wii::Renderer = NULL; +GSFramework* Wii::Engine = NULL; +nProject* Wii::Project = NULL; +WIIWareStrap* Wii::Strap = NULL; +nWiiAllocator Wii::MEM2_allocator; +nIOMemoryFS* Wii::pMemory_fs = NULL; + +unsigned int Wii::LastAudioUpdateTime = (u32)OSGetTick(); +bool Wii::DisableAudioUpdate = false; +bool Wii::VideoInited = false; +//--------------------------------------------------------- + +//--------------------------------------------------------- +bool Wii::LoadingAudioUpdate() +//--------------------------------------------------------- +{ + #define WII_LOADING_AUDIO_UPDATE_PERIOD_MS (1000/20) + #define WII_LOADING_AUDIO_UPDATE_SLEEP_MS (2) + + if (DisableAudioUpdate) + return; + + u32 currentTick = (u32)OSGetTick(); + u32 diffCSTime = OSTicksToMilliseconds( OSDiffTick( currentTick, LastAudioUpdateTime ) ); + + if (diffCSTime >= WII_LOADING_AUDIO_UPDATE_PERIOD_MS) + { + if (Wii::Mixer) + { + Wii::Mixer->Update(); + OSSleepMilliseconds( WII_LOADING_AUDIO_UPDATE_SLEEP_MS ); + +// OSReport("audio updated, delayMs=%d\n",diffCSTime); + } + LastAudioUpdateTime = (u32)OSGetTick(); + } +} + +//--------------------------------------------------------- +void Wii::EnableHomeMenu(bool value) +//--------------------------------------------------------- +{ + if (value) + WIIHome::enableFlags &= ~WII_HOME_DISABLE_HOME_BUTTON; + else + WIIHome::enableFlags |= WII_HOME_DISABLE_HOME_BUTTON; +} + +//--------------------------------------------------------- +void Wii::ForceReturnToMenuInsteadOfReset(bool value) +//--------------------------------------------------------- +{ + WIIHome::forceReturnToMenuInsteadOfReset = value; +} + +//--------------------------------------------------------- +bool Wii::EnableResetAndPowerButtons(bool enable, bool allowPostpone) +//--------------------------------------------------------- +{ + u32 f = WII_HOME_DISABLE_RESET_BUTTON | WII_HOME_DISABLE_POWER_BUTTON; + bool res = !(WIIHome::enableFlags & f); + + if (!enable && allowPostpone) + f |= WII_HOME_ALLOW_POWER_POSTPONE | WII_HOME_ALLOW_RESET_POSTPONE; + + if (enable) + { + WIIHome::enableFlags &= ~f; + WIIHome::enableFlags &= ~WII_HOME_ALLOW_POWER_POSTPONE; + WIIHome::enableFlags &= ~WII_HOME_ALLOW_RESET_POSTPONE; + } + else + WIIHome::enableFlags |= f; + return res; +} + +//--------------------------------------------------------- +float Wii::GetSquareRatioFor16_9() +//--------------------------------------------------------- +{ + // cf VI_library_book, page 47 + // Game Virtual Space EFB XFB VI + //NTSC, EURGB60 832×456 640×456 640×456 686×456 + //PAL 832×456 640×456 640×542 682×542 + + if (SCGetAspectRatio()!=SC_ASPECT_RATIO_16x9) { + return(1.0f); + } + else { + if ( (SCGetEuRgb60Mode() == SC_EURGB60_MODE_ON) + || (VIGetTvFormat() != VI_PAL)) { + return(686.0f/832.0f); + } + else { + return(682.0f/832.0f); + } + } + + return (1.0f); +} + +//--------------------------------------------------------- +SQInteger WiiStartHomeMenu(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + if ( !Wii::HomeMenu.IsActivated() + && ((Wii::HomeMenu.enableFlags & WII_HOME_DISABLE_HOME_BUTTON)==0)) { + Wii::HomeMenu.Init( SCGetAspectRatio()==SC_ASPECT_RATIO_16x9, VIGetTvFormat() ); + } + __SQ_RETURN +} + + +//--------------------------------------------------------- +SQInteger WiiEnableHomeMenu(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETBOOL(value) + __SQ_GETEND + Wii::EnableHomeMenu(value); + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiGetHomeMenuRunning(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_RETURNBOOL(Wii::HomeMenu.IsActivated() == 1) +} + +//--------------------------------------------------------- +SQInteger WiiEnableResetAndPowerButtons(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETBOOL(value) + __SQ_GETEND + Wii::EnableResetAndPowerButtons(value); + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiIs16_9(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_RETURNBOOL(SCGetAspectRatio()==SC_ASPECT_RATIO_16x9) +} + +//--------------------------------------------------------- +SQInteger WiiGetSquareRatioFor16_9(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_RETURNFLOAT(Wii::GetSquareRatioFor16_9()); + return 1; +} + +//--------------------------------------------------------- +SQInteger WiiReturnToDataManager(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + WIIHome::PowerAndResetPreprocess(); + OSReturnToDataManager(); + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiInitStrap(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + if (Wii::Strap) { + static const GXColor fg = {0x00, 0xff, 0xff, 0xff}; + static const GXColor bg = {0x00, 0x00, 0x00, 0x00}; + OSFatal ( fg, bg, "WiiInitStrap" ); + } + Wii::Strap = new WIIWareStrap(); + Wii::Strap->Init(); + __SQ_RETURN +} + +extern GSFramework *gEngine; + +//--------------------------------------------------------- +SQInteger WiiDeInitStrap(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + if (Wii::Strap) { + Wii::Strap->DeInit(); + delete Wii::Strap; + Wii::Strap = NULL; + +// a quoi servait ce code déja ??? +// VISetBlack(TRUE); +// for (s32 i=0;i<2;i++) { +// gEngine->GetRenderer()->ShowFrame(); +// VIWaitForRetrace(); +// } +// VISetBlack(FALSE); +// VIWaitForRetrace(); + } + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiDrawStrap(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + Wii::Strap->Draw(); + VIWaitForRetrace(); + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiGetVersion(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + static const char noe[] = "NOE"; + static const char noa[] = "NOA"; + __SQ_RETURNSTRING ((WiiErrorMngr::Version == WiiErrorMngr::VERSION_NOE) ? noe : noa); +} + +//--------------------------------------------------------- +SQInteger WiiGetLastErrorStrId(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_RETURNSTRING (WiiErrorMngr::GetLastErrorStrId().c_str()); +} + +//--------------------------------------------------------- +SQInteger WiiGetLastErrorText(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_RETURNSTRING (WiiErrorMngr::GetLastErrorText(WiiErrorMngr::ForcedLocaleForGetLastErrorText).c_str()); +} + +//--------------------------------------------------------- +SQInteger WiiGetOptionText(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(optionStrID) + const char* res = ((WiiErrorMngr::GetOptionText(optionStrID, WiiErrorMngr::ForcedLocaleForGetLastErrorText)).c_str()); + __SQ_GETEND + + __SQ_RETURNSTRING(res); +} + +//--------------------------------------------------------- +SQInteger WiiSetGameTitle(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETSTRING(title) + WiiErrorMngr::SetGameTitle(title); + __SQ_GETEND + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiSaveInit(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(3) + __SQ_GETINT(nbMetafiles) + __SQ_GETINT(saveSizeInBytes) + __SQ_GETINT(saveIconNbPictures) + __SQ_GETEND + + WiiSaveMngr::Init(nbMetafiles, saveSizeInBytes, saveIconNbPictures); + + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiSaveExists(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_RETURNBOOL (WiiSaveMngr::SaveFileExists()); +} + + +//--------------------------------------------------------- +SQInteger WiiSaveSave(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ +#ifndef NDEBUG +// #define DEBUG_RESET_WHILE_SAVING +// #define DEBUG_POWER_WHILE_SAVING +#endif + +#ifdef DEBUG_RESET_WHILE_SAVING + WIIHome::reset_called = true; +#endif + +#ifdef DEBUG_POWER_WHILE_SAVING + WIIHome::power_called = true; +#endif + + WiiSaveMngr::Save(); + __SQ_RETURN +} + +/* +//--------------------------------------------------------- +SQInteger WiiSaveLoad(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ +// WiiSaveMngr::Save(); + __SQ_RETURN +} +*/ + +//--------------------------------------------------------- +SQInteger WiiSaveSetMetafile(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(2) + __SQ_GETSAFEPTR(metafile, nMetaFile, typetag_Metafile) + __SQ_GETINT(id) + WiiSaveMngr::SetMetafile(metafile, id); + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiSaveGetMetafile(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETINT(id) + nMetaFile* ptr = WiiSaveMngr::GetMetafile(id); + __SQ_RETURNMANAGEDSAFEPTR(ptr, typetag_Metafile) + __SQ_GETEND +} + +//--------------------------------------------------------- +SQInteger WiiSaveDelete(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + WiiSaveMngr::DeleteSaveFile(); + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiGameRestart(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + Wii::HomeMenu.PerformReset(); + __SQ_RETURN +} + + +//--------------------------------------------------------- +SQInteger WiiDumpMemInfo(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ +#if __ENABLE_ENGINE_LOG__ + u32 freeMem1 = MEMGetTotalFreeSizeForExpHeap(((nWiiAllocator *)MEM1_allocator.vacc)->heap); + OSReport("Mem1 Free = %do, %.2fko, %.2fMo\n", freeMem1, freeMem1/1024.0f, freeMem1/(1024.0f*1024.0f)); + + u32 freeMem2 = MEMGetTotalFreeSizeForExpHeap(Wii::MEM2_allocator.heap); + OSReport("Mem2 Free = %do, %.2fko, %.2fMo\n", freeMem2, freeMem2/1024.0f, freeMem2/(1024.0f*1024.0f)); +#endif + __SQ_RETURN +} + +//--------------------------------------------------------- +SQInteger WiiRemoteDisconnect(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(1) + __SQ_GETINT(id) + + if (id >= WPAD_CHAN0 && id <= WPAD_CHAN3) + WPADDisconnect(id); + + __SQ_RETURN +} + +/* +//--------------------------------------------------------- +SQInteger WiiSetClearColor(HSQUIRRELVM vm) +//--------------------------------------------------------- +{ + __SQ_GETSTART(3) + __SQ_GETINT(r) + __SQ_GETINT(g) + __SQ_GETINT(b) + __SQ_GETEND + + GXColor c; + c.a = 255; + c.r = r; + c.g = g; + c.b = b; + GXSetCopyClear(c, GX_MAX_Z24); + + __SQ_RETURN +} +*/ + +//------------------------------------------------------- +void RegisterWiiBinding(HSQUIRRELVM vm) +//------------------------------------------------------- +{ +/*# + Topic: Wii + Desc: NINTENDO Wii specific binding +#*/ + +/*# + Section: WiiHome + Desc: Wii Home menu +#*/ + + /*# + Func: WiiEnableHomeMenu + Proto: void:bool + Desc: Enable or disables the home button. + #*/ + sq_register(vm, WiiEnableHomeMenu, "WiiEnableHomeMenu", _SC(".b")); + /*# + Func: WiiGetHomeMenuRunning + Proto: bool:void + Desc: Returns the state of the Home menu. + #*/ + sq_register(vm, WiiGetHomeMenuRunning, "WiiGetHomeMenuRunning", _SC(".")); + /*# + Func: WiiStartHomeMenu + Proto: void:void + Desc: Launches Home menu (only if it is enabled). + #*/ + sq_register(vm, WiiStartHomeMenu, "WiiStartHomeMenu", _SC(".")); + /*# + Func: WiiReturnToDataManager + Proto: void:void + Desc: Launches the Home menu (only if it is enabled). + #*/ + sq_register(vm, WiiReturnToDataManager, "WiiReturnToDataManager", _SC(".")); + +/*# + Section: WiiStrap + Desc: Wii strap screen functions +#*/ + + /*# + Func: WiiInitStrap + Proto: void:void + Desc: Initializes strap screen data. + #*/ + sq_register(vm, WiiInitStrap, "WiiInitStrap", _SC(".")); + + /*# + Func: WiiDeInitStrap + Proto: void:void + Desc: Uninitialize strap screen data. + #*/ + sq_register(vm, WiiDeInitStrap, "WiiDeInitStrap", _SC(".")); + + /*# + Func: WiiDrawStrap + Proto: void:void + Desc: Draws strap screen data. + #*/ + sq_register(vm, WiiDrawStrap, "WiiDrawStrap", _SC(".")); + +/*# + Section: WiiSystem + Desc: Wii system functions +#*/ + + /*# + Func: WiiEnableResetButton + Proto: void:bool + Desc: Enable or disables the reset/shutdown button. + #*/ + sq_register(vm, WiiEnableResetAndPowerButtons, "WiiEnableResetAndPowerButtons", _SC(".b")); + + /*# + Func: WiiIs16_9 + Proto: bool:void + Desc: Returns true if the Wii system configuration is set to 16/9 mode. + #*/ + sq_register(vm, WiiIs16_9, "WiiIs16_9", _SC(".")); + + /*# + Func: WiiGetSquareRatioFor16_9 + Proto: float:void + Desc: Returns the ratio to use to scale 2D images in order to have square pixels on any TV screen. + #*/ + sq_register(vm, WiiGetSquareRatioFor16_9, "WiiGetSquareRatioFor16_9", _SC(".")); + + /*# + Func: WiiGetVersion + Proto: String:void + Desc: Returns "NOE" (Europe) or "NOA" (America). + #*/ + sq_register(vm, WiiGetVersion, "WiiGetVersion", _SC(".")); + + /*# + Func: WiiGetLastErrorStrId + Proto: String:void + Desc: Returns ID of the last error, returns an empty string if none. + #*/ + sq_register(vm, WiiGetLastErrorStrId, "WiiGetLastErrorStrId", _SC(".")); + + /*# + Func: WiiGetLastErrorText + Proto: String:void + Desc: Returns a localized string describing last error. + #*/ + sq_register(vm, WiiGetLastErrorText, "WiiGetLastErrorText", _SC(".")); + + /*# + Func: WiiGetOptionText + Proto: String:String error_id + Desc: Returns a localized string describing a non blocking error option string ID. + #*/ + sq_register(vm, WiiGetOptionText, "WiiGetOptionText", _SC(".s")); + + /*# + Func: WiiSetGameTitle + Proto: void:String title + Desc: Sets the game title that may be displayed in Wii error screens + #*/ + sq_register(vm, WiiSetGameTitle, "WiiSetGameTitle", _SC(".s")); + +/*# + Section: WiiSave + Desc: Wii save system functions +#*/ + + /*# + Func: WiiSaveInit + Proto: void:int nbMetafiles, int saveSizeInBytes, int saveIconNbPictures + Desc: Initialize the Wii save system information (does not perform any read/write to NAND). + #*/ + sq_register(vm, WiiSaveInit, "WiiSaveInit", _SC(".iii")); + /*# + Func: WiiSaveExists + Proto: bool:void + Desc: Returns TRUE if save data exists (does not perform any write to NAND). + #*/ + sq_register(vm, WiiSaveExists, "WiiSaveExists", _SC(".")); + /*# + Func: WiiSaveSave + Proto: void:void + Desc: Saves data to the Wii NAND memory (WiiSaveInit / WiiSaveAddMetafile must have been called before calling this function). + #*/ + sq_register(vm, WiiSaveSave, "WiiSaveSave", _SC(".")); + + /*# + Func: WiiSaveLoad + Proto: void:void + Desc: TBD (WiiSaveInit / WiiSaveSetMetafile must have been called before calling this function). + #*/ +// sq_register(vm, WiiSaveLoad, "WiiSaveLoad", _SC(".")); + + /*# + Func: WiiSaveSetMetafile + Proto: void:Metafile,int id + Desc: TBD + #*/ + sq_register(vm, WiiSaveSetMetafile, "WiiSaveSetMetafile", _SC(".xi")); + + /*# + Func: WiiSaveGetMetafile + Proto: Metafile:int id + Desc: TBD + #*/ + sq_register(vm, WiiSaveGetMetafile, "WiiSaveGetMetafile", _SC(".i")); + + /*# + Func: WiiSaveDelete + Proto: void:void + Desc: deletes a game save data & save banner + #*/ + sq_register(vm, WiiSaveDelete, "WiiSaveDelete", _SC(".")); + + /*# + Func: WiiGameRestart + Proto: void:void + Desc: restarts the game (like pressing reset ...) + #*/ + sq_register(vm, WiiGameRestart, "WiiGameRestart", _SC(".")); + + /* + Func: WiiSetClearColor + Proto: void:int r,int g,int b + Desc: changes the wii clear color + */ + //sq_register(vm, WiiSetClearColor, "WiiSetClearColor", _SC(".iii")); + + /*# + Func: WiiDumpMemInfo + Proto: void:void + Desc: TBD + #*/ + sq_register(vm, WiiDumpMemInfo, "WiiDumpMemInfo", _SC(".")); + + /*# + Func: WiiRemoteDisconnect + Proto: void:int id + Desc: TBD + #*/ + sq_register(vm, WiiRemoteDisconnect, "WiiRemoteDisconnect", _SC(".i")); +} + + +#endif diff --git a/include/modules/script_squirrel/mmf.cpp b/include/modules/script_squirrel/mmf.cpp new file mode 100644 index 0000000..380a565 --- /dev/null +++ b/include/modules/script_squirrel/mmf.cpp @@ -0,0 +1,48 @@ +#include "mmf.h" + +/** +*/ +CMMF::CMMF(LPCTSTR MMFName, int size, LPCTSTR mutexName) : +m_nSize(size), +m_hMutex(0) +{ + m_hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, m_nSize, MMFName); + m_pSharedData = MapViewOfFile(m_hFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + + if(mutexName != NULL) + m_hMutex = CreateMutex(NULL, FALSE, mutexName); +} + +/** +*/ +CMMF::~CMMF(void) +{ + UnmapViewOfFile(m_pSharedData); + CloseHandle(m_hFileMapping); + + if(m_hMutex) + CloseHandle(m_hMutex); +} + +/** +* Copies the current contents of the MMF into pData (buffer must be big enough to receive m_nSize bytes). +* Waits for locked mutex to be released if mutex name was specified during construction. +*/ +void CMMF::Read(void* pData, bool read /* = TRUE */) +{ + if(m_hMutex) + WaitForSingleObject(m_hMutex, INFINITE); + + memcpy(read ? pData : m_pSharedData, read ? m_pSharedData : pData, m_nSize); + + if(m_hMutex) + ReleaseMutex( m_hMutex ); +} + +/** +* Copies the contents of pData into the MMF, waiting for the MMF lock to be released if applicable. +*/ +void CMMF::Write(void* pData) +{ + Read(pData, false); +} diff --git a/include/modules/script_squirrel/squirrel_analyzer.cpp b/include/modules/script_squirrel/squirrel_analyzer.cpp new file mode 100644 index 0000000..f9f8449 --- /dev/null +++ b/include/modules/script_squirrel/squirrel_analyzer.cpp @@ -0,0 +1,266 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/squirrel_analyzer.h" + #include "ascii/parser.h" + #include "filesystem/filesystem.h" + #include "platform.h" + + using namespace GS; + using namespace GS::SquirrelAnalyzer; + using namespace GS::AsciiParser; + + +//------------------------------------------------------------------------------ +/* static bool SymbolFindByNameFunctor(Symbol *s, const char *n) { return s->name == n; } */ +static bool SourceFindByNameFunctor(Source *s, const char *n) { return s->name == n; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +struct ParserContext +{ + const char *s, *e, *o; + SharedList *symbols; + Symbol::Type type; + + Offset CurrentOffset() const + { + Offset offset(1, 0); + for (const char *p = o; p < e; ++offset.line) + { + const char *eol = RunToEOL(p, e); + + if (eol > s) + { + offset.column = s - p; + break; + } + if (eol >= e) + return Offset(1, 0); + + p = SkipEOL(eol, e); + } + return offset; + } + + ParserContext(const char *_s, const char *_e, const char *_o, SharedList *_symbols, Symbol::Type _type) : s(_s), e(_e), o(_o), symbols(_symbols), type(_type) {} +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void ParseContext(ParserContext &); +bool ParseMemberVariable(ParserContext &ctx) +{ + AutoPtr _var(new Variable); + _var->offset = ctx.CurrentOffset(); + _var->var_type = Variable::VarMember; + + const char *e = SkipEntry(ctx.s, ctx.e); + _var->name.Set(ctx.s, e); + + ctx.s = NextEntry(ctx.s, ctx.e) + 1; + ctx.symbols->Add(_var.Detach()); + return true; +} +bool ParseGlobalVariable(ParserContext &ctx) +{ + AutoPtr _var(new Variable); + _var->offset = ctx.CurrentOffset(); + _var->var_type = Variable::VarGlobal; + + const char *e = SkipEntry(ctx.s, ctx.e); + _var->name.Set(ctx.s, e); + + ctx.s = NextEntry(ctx.s, ctx.e) + 2; + ctx.symbols->Add(_var.Detach()); + return true; +} +bool ParseLocalVariable(ParserContext &ctx) +{ + AutoPtr _var(new Variable); + _var->offset = ctx.CurrentOffset(); + _var->var_type = Variable::VarLocal; + + const char *s = NextEntry(ctx.s, ctx.e); + _var->name.Set(s, SkipEntry(s, ctx.e)); + ctx.symbols->Add(_var.Detach()); + + // parse subsequent declarations. + s = NextEntry(s, ctx.e); + + forever + { +/* + // TODO a naive test won't do as there is no mandatory end-of-statement in Squirrel + if (s[0] == '=') + { + // check if there are more variables declared by this statement + } +*/ + if (s[0] == ',') + { + s = NextEntry(s + 1, ctx.e); + ctx.s = s; + + _var = new Variable; + _var->offset = ctx.CurrentOffset(); + _var->var_type = Variable::VarLocal; + + _var->name.Set(s, SkipEntry(s, ctx.e)); + ctx.symbols->Add(_var.Detach()); + + s = NextEntry(s, ctx.e); + } + else + break; + } + + ctx.s = s; + return true; +} +bool ParseFunction(ParserContext &ctx) +{ + AutoPtr _function(new Function); + _function->offset = ctx.CurrentOffset(); + + const char *s = NextEntry(ctx.s, ctx.e); + _function->name.Set(s, SkipEntry(s, ctx.e)); + + s = NextEntry(s, ctx.e); + + // Parse prototype. + if (s[0] != '(') + return false; + + const char *eoproto = RunToEOG(s, ctx.e, '(', ')'); + if (eoproto == NULL) + return false; + + _function->prototype.Set(s + 1, eoproto); + s = NextEntry(eoproto + 1, ctx.e); + + // Parse function content. + if (s[0] != '{') + return false; + + const char *eofunc = RunToEOG(s, ctx.e, '{', '}'); + if (eofunc == NULL) + eofunc = ctx.e; + ParserContext func_ctx(s + 1, eofunc, ctx.o, &_function->symbols, _function->type); + + ParseContext(func_ctx); + + ctx.s = eofunc + 1; + ctx.symbols->Add(_function.Detach()); + return true; +} +bool ParseClass(ParserContext &ctx) +{ + AutoPtr _class(new Class); + _class->offset = ctx.CurrentOffset(); + + ctx.s = NextEntry(ctx.s, ctx.e); + _class->name.Set(ctx.s, SkipEntry(ctx.s, ctx.e)); + + const char *s = NextEntry(ctx.s, ctx.e); + + if (!String::strccmp("extends", s)) + { + s = NextEntry(s, ctx.e); + _class->extends.Set(s, SkipEntry(s, ctx.e)); + + ctx.s = SkipEntry(s, ctx.e); + + s = NextEntry(s, ctx.e); + if (s == ctx.e) + return false; + } + + // Parse class content. + if (s[0] != '{') + return false; + + const char *eoclass = RunToEOG(s, ctx.e, '{', '}'); + if (eoclass == NULL) + eoclass = ctx.e; + + ParserContext class_ctx(s + 1, eoclass, ctx.o, &_class->symbols, _class->type); + ParseContext(class_ctx); + + ctx.s = eoclass + 1; + ctx.symbols->Add(_class.Detach()); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void ParseContext(ParserContext &ctx) +{ + for (bool r = true; r && (ctx.s < ctx.e); ) + { + if (!String::strccmp("class", ctx.s)) + r = ParseClass(ctx); + else if (!String::strccmp("function", ctx.s)) + r = ParseFunction(ctx); + else if (!String::strccmp("local", ctx.s)) + r = ParseLocalVariable(ctx); + else + { + const char *e = SkipEntry(ctx.s, ctx.e); + String tmp(ctx.s, e); + + const char *s = NextEntry(ctx.s, ctx.e); + if (ctx.s == s) + ++ctx.s; // skip + else + { + if ((s[0] == '<') && (s[1] == '-')) + r = ParseGlobalVariable(ctx); + else if ((ctx.type == Symbol::TypeClass) && (s[0] == '=')) + r = ParseMemberVariable(ctx); + else + ctx.s = s; + } + } + } +} +Source *ParseSource(const char *s, const char *e) +{ + AutoPtr source(new Source); + + ParserContext ctx(s, e, s, &source->symbols, Symbol::TypeNone); + ParseContext(ctx); + + return source.Detach(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Source *SquirrelAnalyzer::Analyze(const char *nut, Program &program, bool replace) +{ + Source *old_source = ListFindEx(program.sources, SourceFindByNameFunctor, nut); + if (old_source && !replace) + return NULL; + + String source; + { + Array buffer; + if (!Platform::Get().io->FileLoad(nut, buffer)) + return NULL; + source.Set(buffer.c_ptr(), buffer.c_ptr() + buffer.GetCount()); + } + + Source *new_source = ParseSource(source.c_str(), source.c_str() + source.Len()); + if (!new_source) + return NULL; + + new_source->name = nut; + + program.sources.Remove(old_source); + program.sources.Add(new_source); + return new_source; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/squirrel_analyzer_debug.cpp b/include/modules/script_squirrel/squirrel_analyzer_debug.cpp new file mode 100644 index 0000000..16e0b8d --- /dev/null +++ b/include/modules/script_squirrel/squirrel_analyzer_debug.cpp @@ -0,0 +1,88 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/squirrel_analyzer.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::SquirrelAnalyzer; + + +void DumpSymbols(const SharedList &, int); + +//------------------------------------------------------------------------------ +void DumpSymbol(const Symbol *symbol, int tab) +{ + for (int n = 0; n < tab; ++n) + __LOG__ << " "; + + __LOG__ << "offset: line " << symbol->offset.line << ", column " << symbol->offset.column << " -> "; + + switch (symbol->type) + { + case Symbol::TypeClass: + if (Class *c = (Class *)symbol) + { + __LOG__ << "Class " << c->name; + if (!c->extends.IsEmpty()) + __LOG__ << " extends: " << c->extends << "\n"; + __LOG__ << "\n"; + + DumpSymbols(c->symbols, tab + 4); + } + break; + + case Symbol::TypeFunction: + if (Function *f = (Function *)symbol) + { + __LOG__ << "Function " << f->name << "(" << f->prototype << ")\n"; + DumpSymbols(f->symbols, tab + 4); + } + break; + + case Symbol::TypeVariable: + if (Variable *v = (Variable *)symbol) + switch (v->var_type) + { + case Variable::VarLocal: __LOG__ << "Local variable " << v->name << "\n"; break; + case Variable::VarGlobal: __LOG__ << "Global variable " << v->name << "\n"; break; + case Variable::VarMember: __LOG__ << "Member variable " << v->name << "\n"; break; + } + break; + + default: + __LOG__ << "Variable " << symbol->name << "\n"; + break; + } +} +void DumpSymbols(const SharedList &symbols, int tab) +{ + ListForeachPtr(Symbol *, symbol, symbols) + DumpSymbol(symbol, tab); +} +void DumpSource(const Source *source) +{ + ListForeachPtr(Symbol *, symbol, source->symbols) + { + switch (symbol->type) + { + case Symbol::TypeClass: __LOG__ << " Class"; break; + case Symbol::TypeFunction: __LOG__ << " Function"; break; + case Symbol::TypeVariable: __LOG__ << " Variable"; break; + } + + __LOG__ << " '" << symbol->name << "'\n"; + } +} +void DumpProgram(const Program &program) +{ + ListForeachPtr(Source *, source, program.sources) + { + __LOG__ << "Source '" << source->name << "'\n"; + DumpSymbols(source->symbols, 4); + } +} +//------------------------------------------------------------------------------ diff --git a/include/modules/script_squirrel/squirrel_debugger.cpp b/include/modules/script_squirrel/squirrel_debugger.cpp new file mode 100644 index 0000000..f39b3be --- /dev/null +++ b/include/modules/script_squirrel/squirrel_debugger.cpp @@ -0,0 +1,398 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "script_squirrel/squirrel_debugger.h" + #include "script_squirrel/cobject/cobject.h" + #include "script_squirrel/cobject/vector_decl.h" + #include "math/vector.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +String SquirrelDebugger::FormatParameter(DebuggerVariable *var) +{ + switch (var->type) + { + case OT_STRING: + return String::Format("%s=%s", var->id.c_str(), var->v_string.c_str()); + case OT_FLOAT: + return String::Format("%s=%.4f", var->id.c_str(), var->v_float); + case OT_INTEGER: + return String::Format("%s=%d", var->id.c_str(), var->v_int); + case OT_BOOL: + return String::Format("%s=%s", var->id.c_str(), var->v_bool ? "True" : "False"); + } + return var->id; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static int DebuggerCompareVariable(DebuggerVariable *&v, const char *s) { return !String::Compare(v->id, s); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +DebuggerVariable *SquirrelDebugger::InsertVariable(const char *name, AutoList &debug_var, int level) +{ + // Catch nesting limit. + if (level == 3) + return NULL; + + // Try to locate variable in the current watch. + DebuggerVariable *var = ListFindEx(debug_var, DebuggerCompareVariable, name); + + // Retrieve stack variable type. + bool check_change = false, has_changed = false; + + SQObjectType sq_type = sq_gettype(vm, -1); + + if (var) + { + // If type has changed, drop the whole member watch structure. + if (var->type != (uint)sq_type) + var->member_list.Clear(); + else + check_change = true; + } + else + { + var = new DebuggerVariable; + if (!var) + __ERR__(__LOG_E__ << "Failed to allocate debugger watch structure.\n", NULL); + + debug_var.Add(var); + var->id = name; + } + + // Update the variable. + var->referenced = true; + var->type = sq_type; + + String type = "Unknown", value; + int limit = 64 / (level + 1); // Increasingly limit array exploration the deeper in the hierarchy we get. + + switch (sq_type) + { + case OT_NULL: + type = "Null"; + break; + + case OT_TABLE: + { + type = "Table"; + + // Check item slot. + sq_pushnull(vm); // Iterator. + while (SQ_SUCCEEDED(sq_next(vm, -2))) + { + // Here -1 is the value and -2 is the key. + const SQChar *slot_name; + if (sq_getstring(vm, -2, &slot_name) == SQ_OK) + InsertVariable(slot_name, var->member_list, level + 1); + + sq_pop(vm, 2); + } + sq_pop(vm, 1); + } + break; + + case OT_ARRAY: + { + type = "Array"; + SQInteger array_size = sq_getsize(vm, -1); + value = String::Format("{ Length=%d, [...] }", array_size); + + // Check item slot. + sq_pushnull(vm); // Iterator. + while (SQ_SUCCEEDED(sq_next(vm, -2))) + { + int idx; + sq_getinteger(vm, -2, (SQInteger *)&idx); + String slot_name = String::Format("[%d]", idx); + InsertVariable(slot_name, var->member_list, level + 1); + sq_pop(vm, 2); + + if (--limit == 0) + break; + } + sq_pop(vm, 1); + } + break; + + case OT_CLOSURE: + type = "Function"; + break; + + case OT_NATIVECLOSURE: + type = "C/C++"; + break; + + case OT_OUTER: + type = "Outer"; + break; + + case OT_USERDATA: + type = "User data"; + break; + + case OT_GENERATOR: + type = "Generator"; + break; + + case OT_USERPOINTER: + break; + + case OT_THREAD: + type = "Thread"; + break; + + case OT_FUNCPROTO: + type = "Prototype"; + break; + + case OT_CLASS: + type = "Class definition"; + break; + + case OT_INSTANCE: + { + type = "Class instance"; + + Vector4 *v = NULL; + + CObjectType typetag; + if (CObject::GetType(vm, -1, typetag)) + { + type = CObjectTypeToString(typetag); + value = FormatUserObjectParameter(typetag); + } + else if (SQ_SUCCEEDED(sq_getinstanceup(vm, -1, (SQUserPointer*)&v, (SQUserPointer)&__Vector_decl))) + { + type = "Vector"; + value = String::Format("{%.2f, %.2f, %.2f, %.2f}", v->x, v->y, v->z, v->w); + } + else + { + // Trying iterating over instance members. + AutoList member_list; + + sq_getclass(vm, -1); + sq_pushnull(vm); // Iterator. + while (SQ_SUCCEEDED(sq_next(vm, -2))) + { + switch (sq_gettype(vm, -1)) + { + case OT_CLOSURE: + case OT_NATIVECLOSURE: + break; + + default: + { + const SQChar *slot_name; + if (sq_getstring(vm, -2, &slot_name) == SQ_OK) + member_list.Add(new String(slot_name)); + } + break; + } + sq_pop(vm, 2); + } + sq_pop(vm, 2); + + // Get actual instance values. + ListForeachPtr(String *, m, member_list) + { + sq_pushstring(vm, m->c_str(), m->Len()); + if (sq_get(vm, -2) == SQ_OK) + InsertVariable(m->c_str(), var->member_list, level + 1); + sq_pop(vm, 1); + } + } + } + break; + + case OT_WEAKREF: + type = "Weakref"; + break; + + case OT_BOOL: + { + type = "Bool"; + SQBool b; + sq_getbool(vm, -1, &b); + value = b ? "True" : "False"; + has_changed = check_change ? var->v_bool != asbool(b) : false; + var->v_bool = b ? true : false; + } + break; + + case OT_STRING: + { + type = "String"; + const SQChar *s; + sq_getstring(vm, -1, &s); + value = String::Format("%s", s); + has_changed = check_change ? var->v_string != s : false; + var->v_string = s; + } + break; + + case OT_INTEGER: + { + type = "Integer"; + SQInteger i; + sq_getinteger(vm, -1, &i); + value = String::Format("%d", i); + has_changed = check_change ? var->v_int != i : false; + var->v_int = (int)i; + } + break; + + case OT_FLOAT: + { + type = "Float"; + SQFloat f; + sq_getfloat(vm, -1, &f); + value = String::Format("%.4f", f); + has_changed = check_change ? var->v_float != f : false; + var->v_float = f; + } + break; + } + + // Value for item with sub-items. + if (var->member_list.GetCount() && value.IsEmpty()) + { + value = "{ "; + + int max = 4; + ListForeachPtr(DebuggerVariable *, v, var->member_list) + { + value += max > 0 ? FormatParameter(v).c_str() : "..."; + value += (iterator.Next() == NULL) || (max == 0) ? " }" : ", "; + + if (!max--) + break; + } + } + + var->type_string = type; + var->modified = has_changed; + var->value = value; + + return var; +} +void SquirrelDebugger::RefreshStackFrameLocalsCache() +{ + // Mark all variables as unreferenced. + DereferenceVarTree(local_var_tree); + + // Update local variables. + const char *var_name; + for (int n = 0; (var_name = sq_getlocal(vm, debug_stack_frame, n)) != NULL; ++n) + InsertVariable(var_name, local_var_tree, 0); + + // Drop unreferenced variables. + ListForeachPtr(DebuggerVariable *, v, local_var_tree) + if (!v->referenced) + local_var_tree.Remove(v); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SquirrelDebugger::VariableToMetatagString(DebuggerVariable *v, String &s) +{ + s += String::Format("\n", v->id.c_str()); + + switch (v->type) + { + case OT_NULL: s += "\n"; break; + case OT_TABLE: s += "\n"; break; + case OT_ARRAY: s += "\n"; break; + case OT_USERDATA: s += "\n"; break; + case OT_CLOSURE: s += "\n"; break; + case OT_NATIVECLOSURE: s += "\n"; break; + case OT_GENERATOR: s += "\n"; break; + case OT_USERPOINTER: s += "\n"; break; + case OT_THREAD: s += "\n"; break; + case OT_FUNCPROTO: s += "\n"; break; + case OT_CLASS: s += "\n"; break; + case OT_INSTANCE: s += "\n"; break; + case OT_WEAKREF: s += "\n"; break; + case OT_BOOL: s += "\n"; break; + case OT_STRING: s += "\n"; break; + case OT_INTEGER: s += "\n"; break; + case OT_FLOAT: s += "\n"; break; + } + + // Display type. + s += String::Format("\n", v->type_string.c_str()); + + // Value. + if (!v->value.IsEmpty()) + s += String::Format("\n", v->value.c_str()); + + if (v->modified) + s += ""; + + // Members. + if (v->member_list.GetCount()) + { + s += "member_list) + VariableToMetatagString(m, s); + s += ">\n"; + } + + s += ">\n"; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SquirrelDebugger::GetStackFrameSource(const char *&source, int &line) +{ + SQStackInfos si; + + if (SQ_SUCCEEDED(sq_stackinfos(vm, debug_stack_frame, &si))) + { + source = (const char *)si.source; + line = si.line; + } + else + { + source = NULL; + line = -1; + } +} +int SquirrelDebugger::GetStackFrameIndex() +{ + int depth = 0; + + SQStackInfos si; + for (int c = 0; SQ_SUCCEEDED(sq_stackinfos(vm, c, &si)); ++c) + if (String(si.source) != "NATIVE") // Skip native C frame. + { + depth = c; + break; + } + + return depth; +} +int SquirrelDebugger::GetCallstackDepth() +{ + int depth = 0; + SQStackInfos si; + while (SQ_SUCCEEDED(sq_stackinfos(vm, depth, &si))) + depth++; + return depth; +} +//------------------------------------------------------------------------------ + +SquirrelDebugger::SquirrelDebugger(SquirrelVM &svm) +{ + vm = svm.VM(); +} diff --git a/include/modules/script_squirrel/squirrel_vm.cpp b/include/modules/script_squirrel/squirrel_vm.cpp new file mode 100644 index 0000000..0eefad5 --- /dev/null +++ b/include/modules/script_squirrel/squirrel_vm.cpp @@ -0,0 +1,522 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include + #include "squirrel.h" + #include "sqstdio.h" + #include "sqstdmath.h" + #include "sqstdstring.h" + #include "sqstdaux.h" + #include "sqstdblob.h" + #include "sqstdsystem.h" + #include "script_squirrel/squirrel_vm.h" + #include "script_squirrel/cobject/cobject.h" + #include "script/script_variant.h" + #include "filesystem/io_handle.h" + #include "filesystem/filesystem.h" + #include "viewer_base/viewer_base.h" + #include "platform.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void SquirrelVM::GetCallStack(AutoList &callstack) +{ + callstack.Clear(); + + SQStackInfos si; + for (SQInteger level = 0; SQ_SUCCEEDED(sq_stackinfos(vm, level, &si)); ++level) + callstack.Add(new CallStackEntry(si.source, si.funcname, si.line)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static void SqPrintFunc(HSQUIRRELVM v, const SQChar *s, ...) +{ + va_list arglist; + va_start(arglist, s); + char lcl[4096]; + +#ifdef __PLATFORM_WINDOWS__ + vsprintf_s(lcl, 4095, s, arglist); +#else + vsprintf(lcl, s, arglist); +#endif + + __LOG__ << "[S] " << lcl << "\n"; + va_end(arglist); +} +static void SqDebugHook(HSQUIRRELVM v, SQInteger type, const SQChar *sourcename, SQInteger line, const SQChar *funcname) +{ + if (SquirrelVM *vm = (SquirrelVM *)sq_getforeignptr(v)) + if (vm->GetEventHandler()) + vm->GetEventHandler()->OnStep((char)type, sourcename, line, funcname); +} +static void SqCompilerError(HSQUIRRELVM v, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column) +{ + if (SquirrelVM *vm = (SquirrelVM *)sq_getforeignptr(v)) + { + String msg("Script runtime Compilation exception:\n"); + msg += String::Format(" - (line %d) in \"%s\"\n", line, source); + __LOG_E__ << "Squirrel Compiler Error: '" << msg << "'\n\n"; + + if (vm->GetEventHandler()) + vm->GetEventHandler()->OnCompilerError(desc, source, line); + + time_t now = time(NULL); + struct tm *timeinfo = localtime(&now); + char timestamp[64]; + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d_%H-%M-%S", timeinfo); + + String logFileName = String::Format("g_engine_log_%s.txt", timestamp); + + // Check if g_engine_log.txt exists and copy it + if (Platform::Get().io->Exists("g_engine_log.txt")) + { + if (Platform::Get().io->FileCopy("g_engine_log.txt", logFileName.c_str())) + { + __LOG_E__ << "Engine log copied to: " << logFileName << "\n"; + } + else + { + __LOG_E__ << "Failed to copy engine log to: " << logFileName << "\n"; + } + } + else + { + __LOG_E__ << "Engine log file 'g_engine_log.txt' not found for copying\n"; + } + } +} +static SQInteger SqRuntimeError(HSQUIRRELVM v) +{ + SquirrelVM *vm = (SquirrelVM *)sq_getforeignptr(v); + + // Get error string. + const SQChar *error = NULL; + if (SQ_FAILED(sq_getstring(v, 2, &error))) + error = "Unspecified runtime error"; + + // Could be null if called from a coroutine. + if (vm && (vm->GetState() == IVM::StateOk)) + { + vm->SetState(IVM::StateExceptionThrown); + + // Redirect to the signal handler. + if (vm->GetEventHandler()) + { + vm->GetEventHandler()->OnRuntimeException(error); + return sq_suspendvm(v); // All debugging hope is lost beyond this point as the Squirrel VM will unwind all exception stack frame. + } + else + { + String msg = String::Format("Script runtime exception:\n\n%s", error); + + AutoList callstack; + vm->GetCallStack(callstack); + + msg += "\n\nCallstack:\n\n"; + ListForeachPtr(IVM::CallStackEntry *, cs, callstack) + msg += String::Format(" - %s() (line %d) in \"%s\"\n", cs->function.c_str(), cs->line, cs->source.c_str()); + + __LOG_E__ << "Squirrel Compiler Error: '" << msg << "'\n"; + + time_t now = time(NULL); + struct tm *timeinfo = localtime(&now); + char timestamp[64]; + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d_%H-%M-%S", timeinfo); + + String logFileName = String::Format("g_engine_log_%s.txt", timestamp); + + // Check if g_engine_log.txt exists and copy it + if (Platform::Get().io->Exists("g_engine_log.txt")) + { + if (Platform::Get().io->FileCopy("g_engine_log.txt", logFileName.c_str())) + { + __LOG_E__ << "Engine log copied to: " << logFileName << "\n"; + } + else + { + __LOG_E__ << "Failed to copy engine log to: " << logFileName << "\n"; + } + } + else + { + __LOG_E__ << "Engine log file 'g_engine_log.txt' not found for copying\n"; + } + + } + } + return sq_suspendvm(v); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SquirrelVM::SetDebugInterface(IDebug *i, bool debug) +{ + sq_enabledebuginfo(vm, debug); +/* if (vm) + { + sq_enabledebuginfo(vm, debug); + if (debug) + sq_setnativedebughook(vm, SqDebugHook); + } + IVM::SetDebugInterface(i, debug);*/ +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SquirrelVM::DumpCallStack(HSQUIRRELVM v, const char *desc, String *msg) +{ + SQStackInfos si; +// SQInteger level = 1; // Level 0 is the native closure we are in. + + __LOG_V__ << "\n"; + String _msg(String::Format("Call stack (%s):\n", desc ? desc : "Requested")); + __LOG_V__ << _msg.c_str(); + + for (SQInteger level = 1; SQ_SUCCEEDED(sq_stackinfos(v, level, &si)); ++level) + { + String _lg; + + if (si.funcname) + { + if (si.line != -1) + _lg = String::Format(" %d: %s() %s(%d)", level, si.funcname, si.source, si.line); + else _lg = String::Format(" %d: %s() C/C++", level, si.funcname); + } + else + _lg = String::Format(" %d: NOINFO", level); + + __LOG_V__ << _lg << "\n"; + _msg += _lg; + } + + if (msg) + *msg = _msg; + __LOG_V__ << "\n"; +} +bool SquirrelVM::Compile(const char *source, uint size, const Object *context, const char *sourcename) +{ + if (!source) + return false; + + if (SQ_SUCCEEDED(sq_compilebuffer(vm, source, size, sourcename, true))) + { + sq_pushroottable(vm); + sq_call(vm, 1, SQFalse, SQTrue); + sq_pop(vm, 1); + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Object *SquirrelVM::GetObjectFromStack(int idx) +{ + HSQOBJECT o; + sq_getstackobj(vm, idx, &o); + return new SquirrelObject(*this, o); +} +Object *SquirrelVM::GetObjectFromName(const char *name, const Object *context) +{ + if (context) + sq_pushobject(vm, ((const SquirrelObject *)context)->object); + else sq_pushroottable(vm); + + sq_pushstring(vm, name, -1); + if (SQ_FAILED(sq_get(vm, -2))) + { + sq_pop(vm, 1); + return NULL; + } + + Object *o = GetObjectFromStack(-1); + sq_pop(vm, 2); + return o; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool SquirrelVM::SetupFunctionCall(const char *func, const Object *cache, const Object *context) +{ + if (!vm || (GetState() != StateOk)) + return false; + + if (cache) + sq_pushobject(vm, ((SquirrelObject *)cache)->object); + else + { + if (context) + sq_pushobject(vm, ((SquirrelObject *)context)->object); + else sq_pushroottable(vm); + + sq_pushstring(vm, func, -1); + if (SQ_FAILED(sq_get(vm, -2))) + { + sq_pop(vm, 1); // Cleanup root table. + return false; + } + sq_remove(vm, -2); // Remove root table. + } + + // Push function environment. + if (context) + sq_pushobject(vm, ((SquirrelObject *)context)->object); + else sq_pushroottable(vm); + + call_arg_count = 1; + return true; +} +bool SquirrelVM::SetFunctionCallContext(const Script::Variant &v) +{ + return PushArgument(v); +} +bool SquirrelVM::PushNullArgument() +{ + call_arg_count++; + return PushNull(); +} +bool SquirrelVM::PushArgument(const Script::Variant &v) +{ + call_arg_count++; + return PushVariant(v); +} +bool SquirrelVM::DoFunctionCall(Script::Variant *v) +{ + if (GetState() != StateOk) + return false; + if (SQ_FAILED(sq_call(vm, call_arg_count, SQTrue, SQTrue))) + return false; + + if (v) + GetVariantFromStack(-1, *v); + sq_pop(vm, 2); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool SquirrelVM::GetVariantFromStack(int idx, Script::Variant &v) +{ + switch (sq_gettype(vm, idx)) + { + case OT_STRING: + { + const SQChar *s; + sq_getstring(vm, idx, &s); + v.Set((const char *)s); + } + break; + + case OT_BOOL: + { + SQBool b; + sq_getbool(vm, idx, &b); + v.Set(asbool(b)); + } + break; + + case OT_INTEGER: + { + SQInteger i; + sq_getinteger(vm, idx, &i); + v.Set((int)i); + } + break; + + case OT_FLOAT: + { + SQFloat f; + sq_getfloat(vm, idx, &f); + v.Set((float)f); + } + break; + + default: + { + HSQOBJECT o; + sq_getstackobj(vm, idx, &o); + v.Set(new SquirrelObject(*this, o), true); + } + break; + } + return true; +} +bool SquirrelVM::Get(const char *name, Script::Variant &prop, const Object *context) +{ + if (context) + sq_pushobject(vm, ((SquirrelObject *)context)->object); + else sq_pushroottable(vm); + sq_pushstring(vm, name, -1); + if (SQ_FAILED(sq_get(vm, -2))) + { + sq_pop(vm, 1); + return false; + } + bool r = GetVariantFromStack(-1, prop); + sq_pop(vm, 2); + return r; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool SquirrelVM::PushNull() +{ + sq_pushnull(vm); + return true; +} +bool SquirrelVM::PushVariant(const Script::Variant &v) +{ + switch (v.type) + { + case Variant::Type_Variant: + switch (v.variant.GetType()) + { + case GS::Variant::VariantString: + sq_pushstring(vm, v.variant.s_value.c_str(), -1); + break; + case GS::Variant::VariantInteger: + sq_pushinteger(vm, v.variant.i_value); + break; + case GS::Variant::VariantBool: + sq_pushbool(vm, v.variant.b_value); + break; + case GS::Variant::VariantFloat: + sq_pushfloat(vm, v.variant.f_value); + break; + + default: + __LOG_E__ << "Unsupported variant type: " << v.type << ".\n"; + return false; + } + break; + + case Variant::Type_ScriptObject: + sq_pushobject(VM(), ((SquirrelObject *)v.object)->object); + break; + + case Variant::Type_UserObject: + return CObject::Push(VM(), v.ptr, CObjectType(v.typetag)); + } + return true; +} +bool SquirrelVM::Set(const char *name, const Script::Variant &v, const Object *context) +{ + if (context) + sq_pushobject(vm, ((SquirrelObject *)context)->object); + else sq_pushroottable(vm); + sq_pushstring(vm, name, -1); + if (!PushVariant(v)) + { + sq_pop(vm, 2); + return false; + } + SQObjectType type = sq_gettype(vm, -3); + if ((type == OT_CLASS) || (type == OT_TABLE)) + sq_newslot(vm, -3, false); + else sq_set(vm, -3); + sq_pop(vm, 1); + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Object *SquirrelVM::CreateArray() +{ + sq_newarray(vm, 0); + Object *o = GetObjectFromStack(-1); + sq_pop(vm, 1); + return o; +} +bool SquirrelVM::Append(const Script::Variant &prop, const Object *context) +{ + if (context) + sq_pushobject(vm, ((SquirrelObject *)context)->object); + else sq_pushroottable(vm); + if (!PushVariant(prop)) + { + sq_pop(vm, 1); + return false; + } + sq_arrayappend(vm, -2); + sq_pop(vm, 1); + return true; +} +Object *SquirrelVM::CreateTable() +{ + sq_newtable(vm); + Object *o = GetObjectFromStack(-1); + sq_pop(vm, 1); + return o; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool SquirrelVM::Open() +{ + if (vm) + return true; + + vm = sq_open(1024); + if (!vm) + return false; + + sq_setforeignptr(vm, (SQUserPointer)this); + + sq_setcompilererrorhandler(vm, SqCompilerError); + sq_setprintfunc(vm, SqPrintFunc, SqPrintFunc); + sq_newclosure(vm, SqRuntimeError, 0); + sq_seterrorhandler(vm); + + sq_pushroottable(vm); + sqstd_register_bloblib(vm); + sqstd_register_iolib(vm); + sqstd_register_systemlib(vm); + sqstd_register_mathlib(vm); + sqstd_register_stringlib(vm); + sq_pop(vm, 1); + + return true; +} +void SquirrelVM::Close() +{ + //if (vm) + // sq_close(vm); + + vm = NULL; + state = StateOk; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SquirrelObject::SquirrelObject(SquirrelVM &_vm, HSQOBJECT _object) : Object(_vm) +{ + object = _object; + sq_addref(((SquirrelVM &)vm).VM(), &object); +} +SquirrelObject::~SquirrelObject() +{ + sq_release(((SquirrelVM &)vm).VM(), &object); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +SquirrelVM::SquirrelVM() +{ + vm = NULL; + call_arg_count = 0; +} +SquirrelVM::~SquirrelVM() +{ + Close(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/tools/geometry_merge.cpp b/include/modules/tools/geometry_merge.cpp new file mode 100644 index 0000000..6a4b23f --- /dev/null +++ b/include/modules/tools/geometry_merge.cpp @@ -0,0 +1,201 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "tools/geometry_merge.h" + #include "core/geometry.h" + #include "math/matrix4.h" + #include "log/log.h" + + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +Geometry *GS::Core::MergeGeometry(Geometry *geo_a, Geometry *geo_b, const Matrix4 *mtx_a, const Matrix4 *mtx_b) +{ + if (!geo_a || !geo_b) + __ERR__(__LOG_E__ << "Cannot merge NULL geometry.\n", NULL) + + if (!mtx_a) + mtx_a = &Matrix4::IdentityMatrix(); + if (!mtx_b) + mtx_b = &Matrix4::IdentityMatrix(); + + // Allocate a new geometry. + Geometry *geo_o = new Geometry; + if (!geo_o) + __ERR__(__LOG_E__ << "Failed to allocate merged geometry.\n", NULL) + + geo_o->name = geo_a->name; // Nothing fancy here, the string length would blow up on large merge. + + // Update data for all geometries. + if (geo_a->pol_normal || geo_b->pol_normal) + { + geo_a->ComputePolygonNormal(); + geo_b->ComputePolygonNormal(); + } + if (geo_a->vtx_normal || geo_b->vtx_normal) + { + geo_a->ComputeVertexNormal(); + geo_b->ComputeVertexNormal(); + } + + // Append vertex. + if (geo_o->vtx.Allocate(geo_a->vtx.GetCount() + geo_b->vtx.GetCount())) + { + Vector4 *pvtx = &geo_o->vtx[0]; + for (uint n = 0; n < geo_a->vtx.GetCount(); ++n) + *pvtx++ = geo_a->vtx[n] * *mtx_a; + for (uint n = 0; n < geo_b->vtx.GetCount(); ++n) + *pvtx++ = geo_b->vtx[n] * *mtx_b; + } + + // Append polygon. + if (geo_o->binding.Allocate(geo_a->binding.GetCount() + geo_b->binding.GetCount())) + { + uint *pbind = &geo_o->binding[0]; + for (uint n = 0; n < geo_a->binding.GetCount(); ++n) + *pbind++ = geo_a->binding[n]; + for (uint n = 0; n < geo_b->binding.GetCount(); ++n) + *pbind++ = geo_b->binding[n] + geo_a->vtx.GetCount(); + } + + if (geo_o->pol.Allocate(geo_a->pol.GetCount() + geo_b->pol.GetCount())) + { + uint total_binding = 0; + + Polygon *ppol = &geo_o->pol[0]; + for (uint n = 0; n < geo_a->pol.GetCount(); ++n) + { + ppol->vtx_count = geo_a->pol[n].vtx_count; + ppol->material = geo_a->pol[n].material; + ppol->binding = &geo_o->binding[total_binding]; + total_binding += ppol->vtx_count; + ppol++; + } + for (uint n = 0; n < geo_b->pol.GetCount(); ++n) + { + ppol->vtx_count = geo_b->pol[n].vtx_count; + ppol->material = (ushort)(geo_b->pol[n].material + geo_a->material_table.GetCount()); + ppol->binding = &geo_o->binding[total_binding]; + total_binding += ppol->vtx_count; + ppol++; + } + } + + // Append polygon normal. + static Vector4 default_normal(0, 0, 1); + + if (geo_a->pol_normal || geo_b->pol_normal) + if (geo_o->pol_normal.Allocate(geo_o->pol.GetCount())) + { + Vector4 *ppnrm = &geo_o->pol_normal[0]; + for (uint n = 0; n < geo_a->pol.GetCount(); ++n) + { + if (geo_a->pol_normal) + { + mtx_a->ApplyRotation(ppnrm, &geo_a->pol_normal[n]); + *ppnrm++ = ppnrm->Normalized(); + } + else + *ppnrm++ = default_normal; + } + for (uint n = 0; n < geo_b->pol.GetCount(); ++n) + { + if (geo_b->pol_normal) + { + mtx_b->ApplyRotation(ppnrm, &geo_b->pol_normal[n]); + *ppnrm++ = ppnrm->Normalized(); + } + else + *ppnrm++ = default_normal; + } + } + + // Append vertex normal. + if (geo_a->vtx_normal || geo_b->vtx_normal) + if (geo_o->vtx_normal.Allocate(geo_o->binding.GetCount())) + { + Vector4 *pvnrm = &geo_o->vtx_normal[0]; + for (uint n = 0; n < geo_a->binding.GetCount(); ++n) + { + if (geo_a->vtx_normal) + { + mtx_a->ApplyRotation(pvnrm, &geo_a->vtx_normal[n]); + *pvnrm++ = pvnrm->Normalized(); + } + else + *pvnrm++ = Vector4(0, 0, 1); + } + for (uint n = 0; n < geo_b->binding.GetCount(); ++n) + { + if (geo_b->vtx_normal) + { + mtx_b->ApplyRotation(pvnrm, &geo_b->vtx_normal[n]); + *pvnrm++ = pvnrm->Normalized(); + } + else + *pvnrm++ = Vector4(0, 0, 1); + } + } + + // Append RGB. + if (geo_a->rgb || geo_b->rgb) + if (geo_o->rgb.Allocate(geo_o->binding.GetCount())) + { + Color *prgb = &geo_o->rgb[0]; + for (uint n = 0; n < geo_a->binding.GetCount(); ++n) + *prgb++ = geo_a->rgb ? geo_a->rgb[n] : Color::White; + for (uint n = 0; n < geo_b->binding.GetCount(); ++n) + *prgb++ = geo_b->rgb ? geo_b->rgb[n] : Color::White; + } + + // Append all UV channels. + static Vector2 default_uv(0.5, 0.5); + + for (uint n = 0; n < __UV_PER_GEOMETRY__; ++n) + if (geo_a->uv[n] || geo_b->uv[n]) + if (geo_o->uv[n].Allocate(geo_o->binding.GetCount())) + { + Vector2 *puv = &geo_o->uv[n][0]; + + if (geo_a->uv[n]) + for (uint v = 0; v < geo_a->binding.GetCount(); ++v) + *puv++ = geo_a->uv[n][v]; + else + for (uint v = 0; v < geo_a->binding.GetCount(); ++v) + *puv++ = default_uv; + + if (geo_b->uv[n]) + for (uint v = 0; v < geo_b->binding.GetCount(); ++v) + *puv++ = geo_b->uv[n][v]; + else + for (uint v = 0; v < geo_b->binding.GetCount(); ++v) + *puv++ = default_uv; + } + + // Append all materials. + geo_o->material_table.Allocate(geo_a->material_table.GetCount() + geo_b->material_table.GetCount()); + Geometry::MaterialSlot *pslot = geo_o->material_table.c_ptr(); + + for (uint n = 0; n < geo_a->material_table.GetCount(); ++n) + { + pslot->name = geo_a->material_table[n].name; + pslot->use_cache = geo_a->material_table[n].use_cache; + ++pslot; + } + for (uint n = 0; n < geo_b->material_table.GetCount(); ++n) + { + pslot->name = geo_b->material_table[n].name; + pslot->use_cache = geo_b->material_table[n].use_cache; + ++pslot; + } + + // Merge materials. + geo_o->MergeDuplicateMaterials(); + + return geo_o; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/tools/resource_explorer.cpp b/include/modules/tools/resource_explorer.cpp new file mode 100644 index 0000000..6d02361 --- /dev/null +++ b/include/modules/tools/resource_explorer.cpp @@ -0,0 +1,235 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "tools/resource_explorer.h" + #include "metafile/nml.h" + #include "platform.h" + #include "filesystem/filesystem.h" + + using namespace GS::Resource; + using namespace GS::NML; + using GS::String; + + +//------------------------------------------------------------------------------ +DependencyRule scene3d_dependency_rules[] = +{ + // Instances + { "Items/*Instance/Template", "Scene" }, + + // Terrains + { "Items/*MTerrain/Terrain/Blendmap", "Texture" }, + { "Items/*MTerrain/Terrain/Blendmap", "Shader" }, + { "Items/*MTerrain/Terrain/MaterialName", "Material" }, + { "Items/*MTerrain/Terrain/Heightmap/Data", "Data" }, + { "Items/*MTerrain/Terrain/Layers/*Layer/Diffuse", "Texture" }, + { "Items/*MTerrain/Terrain/Layers/*Layer/Normal", "Texture" }, + { "Items/*MTerrain/Terrain/Layers/*Layer/Specular", "Texture" }, + { "Items/*MTerrain/Terrain/Layers/*Layer/Self", "Texture" }, + + // Lights + { "Items/*MLight/Light/ProjectionMap", "Texture" }, + + // Objects + { "Items/*MObject/Object/Geometry", "Geometry" }, + + // All items + { "Items/*/MItem/ScriptedObject/*ScriptUnit/Script", "Script" }, // legacy + { "Items/*/MItem/ScriptedObject/*ScriptUnit/ScriptPath", "Script" }, + { "Items/*/MItem/PhysicItem/Shapes/*PhysicShape/Mesh", "Geometry" }, + + // Scene + { "ScriptedObject/*ScriptUnit/Script", "Script" }, // legacy + { "ScriptedObject/*ScriptUnit/ScriptPath", "Script" }, + { 0, 0 } +}; +DependencyRule geometry_dependency_rules[] = +{ + { "Materials/*MaterialRef", "Material" }, + { "Materials/*MaterialRefEx/Name", "Material" }, + + { "LodProxy", "Geometry" }, + { "ShadowProxy", "Geometry" }, + + { 0, 0 } +}; +DependencyRule material_dependency_rules[] = +{ + { "*TextureStage/Texture", "Texture" }, + { "Shader", "Shader" }, + { 0, 0 } +}; +DependencyRule shader_tree_dependency_rules[] = +{ + { "Map/*Entry/Param/Texture", "Texture" }, + { 0, 0 } +}; +DependencyRule shader_dependency_rules[] = +{ + { "Input/*Uniform/Texture", "Texture" }, + { 0, 0 } +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ExplorerRule resource_rules[] = +{ + { "Scene3d", "Scene", scene3d_dependency_rules }, + { "Geometry", "Geometry", geometry_dependency_rules }, + { "Material", "Material", material_dependency_rules }, + { "Shader Tree", "ShaderMap", shader_tree_dependency_rules }, + { "Shader", "Shader", shader_dependency_rules }, + { 0, 0 } +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +const char *Explorer::DependencyTag::GetName() const +{ return tag->GetString(); } +void Explorer::DependencyTag::SetName(const char *n) +{ tag->SetString(n); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool resource_filter(const Explorer::Resource *r, const char *name) { return r->name == name; } +bool dependency_filter(const Explorer::Dependency *d, const char *name) { return !String::strccmp(d->GetName(), name); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +const Explorer::Dependency *Explorer::Resource::FindDependency(const char *n) const +{ + return ListFindEx(dependencies, dependency_filter, n); +} +bool Explorer::Resource::HasMissingDependencies() const +{ + ListForeachPtr(Dependency *, dep, dependencies) + if (dep->missing) + return true; + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Explorer::ExploreResourceRuleTags(const GS::StringList &tags, uint pos, Tag *tag, Resource *r, int depth) +{ + if (pos == tags.GetCount()) // end of path + { + if (tag->GetString()) + { + String name = tag->GetString(); + +// if (!r->FindDependency(name)) + { + DependencyTag *dependency = new DependencyTag(tag); + r->dependencies.Add(dependency); + + if (name.StartsWith("@sys/")) // engine generated resource + dependency->missing = false; + + else if (name.StartsWith("@core/")) + dependency->missing = !Platform::Get().io->Exists(name); + + // Assert dependency is found. + else if (!name.IsAbsolutePath()) + { + // Check in project path. + if (!project_path.IsEmpty()) + { + String _name = String::Format("%s/%s", project_path.c_str(), name.c_str()).CleanFilePath(); + if ((dependency->missing = !Platform::Get().io->Exists(_name)) == false) + name = _name; + } + + // Check in core path if still missing. + if (dependency->missing) + if (!core_path.IsEmpty()) + { + String _name = String::Format("%s/%s", core_path.c_str(), name.c_str()).CleanFilePath(); + if ((dependency->missing = !Platform::Get().io->Exists(_name)) == false) + name = _name; + } + } + ExploreResource(name, project_path, core_path, depth - 1); + } + } + } + else + { + const String &t = tags[pos]; + + if (t.StartsWith("*")) // iterate current tag + { + String match = t.Mid(1); + NMLTagForeach(c, *tag) + if (match.IsEmpty() || (c->name == match)) + ExploreResourceRuleTags(tags, pos + 1, c, r, depth); + } + else + { + if (Tag *c = tag->GetTag(t)) // no tag means rule not met + ExploreResourceRuleTags(tags, pos + 1, c, r, depth); + } + } +} +bool Explorer::ExploreResourceRule(ExplorerRule &rule, Resource *r, int depth) +{ + Tag *tag = r->file->GetTag(rule.root); + if (!tag) + return false; + + r->type = rule.type; + + for (int n = 0; rule.rules[n].type; ++n) + { + // Split rule tags. + StringList tags; + String(rule.rules[n].path).Split("/", tags); + + ExploreResourceRuleTags(tags, 0, tag, r, depth); + } + return true; +} +Explorer::Resource *Explorer::ExploreResource(const char *name, const char *_project_path, const char *_core_path, int depth) +{ + if (depth <= 0) + return NULL; + + project_path = _project_path; + core_path = _core_path; + + // Metafile. + if (!Parser::IsMetafile(name)) + return NULL; + + // Check if that resource has already been loaded. + if (Resource *_r = ListFindEx(resources, resource_filter, name)) + return _r; + + // Load file. + AutoPtr r(new Resource(name, "Null")); + r->file = Parser::Load(name); + if (r->file.IsNull()) + return NULL; + + // Explore resource. + for (int n = 0; resource_rules[n].type; ++n) + if (ExploreResourceRule(resource_rules[n], r, depth)) + { + resources.Add(r); + return r.Detach(); + } + + return NULL; +} +const Explorer::Resource *Explorer::FindResource(const char *name) const +{ + return ListFindEx(resources, resource_filter, name); +} +void Explorer::Clear() +{ + resources.Clear(); +} +//------------------------------------------------------------------------------ diff --git a/include/modules/tools/scene_merge_object_list.cpp b/include/modules/tools/scene_merge_object_list.cpp new file mode 100644 index 0000000..9095dce --- /dev/null +++ b/include/modules/tools/scene_merge_object_list.cpp @@ -0,0 +1,186 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "tools/scene_merge_object_list.h" + #include "tools/geometry_merge.h" + #include "scene3d/scene.h" + #include "scene3d/mobject.h" + #include "physic/physic_world.h" + #include "core/graphic_resource_factory.h" + + using namespace GS; + using namespace GS::Core; + using namespace GS::S3D; + + +//------------------------------------------------------------------------------ +struct ItemTransform +{ + sMItem i; + Matrix4 m; + + ItemTransform(MItem *_i, const Matrix4 &_m) : i(_i), m(_m) {} +}; +struct GeometryTransform +{ + sMItem i; + Matrix4 m; + sGeometry g; + + GeometryTransform(MItem *_i, Geometry *_g, const Matrix4 &_m) : i(_i), m(_m), g(_g) {} +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +static void MergePhysicShape(MItem *to, MItem *from) +{ + if (!from->physic_item) + return; + + ListForeachPtr(PhysicShape *, shape, from->physic_item_desc.shape_list) + if (PhysicShape *new_shape = new PhysicShape) + { + new_shape->SetMatrix(from->GetBaseItem()->GetMatrix() * shape->GetMatrix()); + new_shape->mass = shape->mass; + + switch (shape->GetType()) + { + case PhysicShape::TypeNone: + break; + + case PhysicShape::TypeHeightmap: + __LOG_W__ << "Merge heightmap physic shape STUB.\n"; + break; + + case PhysicShape::TypeBox: + case PhysicShape::TypeCapsule: + case PhysicShape::TypeCylinder: + case PhysicShape::TypeCone: + case PhysicShape::TypeSphere: + new_shape->Set(shape->GetType(), shape->dimensions); + break; + + case PhysicShape::TypeConvex: + case PhysicShape::TypeMesh: + new_shape->Set(shape->GetType(), shape->path); + break; + } + + to->physic_item_desc.shape_list.Add(new_shape); + } + + to->physic_item_desc.physic_mode = from->physic_item_desc.physic_mode; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool SceneMergeObjectList::Merge(Scene *scene, const SharedList &item_list, Core::ResourceFactory &gf, sMItem &out_item, sGeometry &out_geo) +{ + // Unlink all children, store matrix beforehand. + AutoList child_list; + + ListForeachPtr(MItem *, item, item_list) + ListForeachPtr(Item *, child, item->GetBaseItem()->GetChildren()) + { + MItem *cchild = Scene::LocateManagedItem(child); + + // Do not store item if it is going to be merged. + if (!item_list.Find(cchild)) + child_list.Add(new ItemTransform(cchild, cchild->GetBaseItem()->GetMatrix())); + } + + Vector4 average_vec(0.0,0.0,0.0); + int counter_average = 0; + ListForeachPtr(MItem *, item, item_list) + if (item->GetItemType() == Type_Object) + { + ++counter_average; + average_vec += item->GetBaseItem()->GetPosition(); + } + + average_vec /= counter_average; + + ListForeachPtr(MItem *, item, item_list) + if (item->GetItemType() == Type_Object) + item->GetBaseItem()->SetPosition(item->GetBaseItem()->GetPosition() - average_vec); + + // Build merge list. + AutoList geo_list; + ListForeachPtr(MItem *, item, item_list) + if (item->GetItemType() == Type_Object) + geo_list.Add(new GeometryTransform(item, gf.LoadGeometry(((MObject *)item)->geometry), item->GetBaseItem()->GetMatrix())); + + if (geo_list.GetCount() < 2) + return true; // nothing to be done + + // Count total steps. + int total_step_count = 0; + for (int count = item_list.GetCount(); count > 1; count /= 2) + total_step_count += count; + + // Merge list. + AutoList tgt_list, *in_list = &geo_list, *out_list = &tgt_list; + + int step_count = 0; + for (bool running = true; (in_list->GetCount() > 1) && running; ) + { + for (uint n = 0; (n < in_list->GetCount()) && running; n += 2) + { + if (n == (in_list->GetCount() - 1)) + { + GeometryTransform *t = (*in_list)[n]; + out_list->Add(new GeometryTransform(t->i, t->g, t->m)); + continue; // nothing to merge + } + + // Merge geometries. + GeometryTransform *left = (*in_list)[n], *right = (*in_list)[n + 1]; + sGeometry merged_geometry(MergeGeometry(left->g, right->g, &left->m, &right->m)); + if (merged_geometry.IsNull()) + continue; + + // Merge physic shapes. + MObject *merged_object = new MObject; + scene->SetupItemComponents(merged_object); + MergePhysicShape(merged_object, left->i); + MergePhysicShape(merged_object, right->i); + + out_list->Add(new GeometryTransform(merged_object, merged_geometry, Matrix4::IdentityMatrix())); + + running = OnProgress(++step_count, total_step_count); + } + in_list->Clear(); + + AutoList *tmp_list = in_list; in_list = out_list; out_list = tmp_list; + } + if (in_list->GetCount() != 1) + return false; + + // Remove merged items from scene. + ListForeachPtr(MItem *, item, item_list) + if (item->GetItemType() == Type_Object) + scene->RemoveItem(item); + + // Store output... + out_item = (*in_list)[0]->i; + out_geo = (*in_list)[0]->g; + + out_item->GetBaseItem()->SetPosition(average_vec); + + out_item->name = "Merged Object"; + scene->AddItem(out_item, false); + + // ...restore parenting. + ListForeachPtr(ItemTransform *, t, child_list) + { + t->i->GetBaseItem()->SetParent(out_item->GetBaseItem()); + t->i->GetBaseItem()->SnapshotTransformation(t->m); + } + child_list.Clear(); + + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/viewer_base/viewer_base.cpp b/include/modules/viewer_base/viewer_base.cpp new file mode 100644 index 0000000..53a26a7 --- /dev/null +++ b/include/modules/viewer_base/viewer_base.cpp @@ -0,0 +1,608 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "viewer_base/viewer_base.h" + #include "viewer_base/viewer_base_debugger.h" + #include "physic_bullet/bullet_world.h" + #include "io_archive/io_archive.h" + #include "raytracer/raytracer_core.h" + #include "font_freetype/ft2_font_factory.h" + #include "script_squirrel/engine_vm_debugger.h" + #include "script_squirrel/engine_vm.h" + #include "script/script_variant.h" + #include "ui/ui.h" + #include "gpu/gpu_triangle_batch.h" + #include "gpu/gpu_renderer.h" + #include "core/embedded_resource_extractor.h" + #include "core/renderer_toolbox.h" + #include "metafile/nml_object.h" + #include "picture/pict_io.h" + #include "filesystem/filesystem.h" + #include "filesystem/io_cfile.h" + #include "input/input_system.h" + #include "log/log.h" + + using namespace GS; + using namespace GS::Core; + + +//------------------------------------------------------------------------------ +bool ViewerBase::OpenViewer() +{ + // Check core file system. + if (!Platform::Get().io->Exists("@core/noise.tga")) + __ERR__(__LOG_E__ << "@core is not properly mounted.\n", false) + + // Embedded resources will be extracted to a ram disk. + IEmbeddedResourceHandler::Set(new EmbeddedResourceExtractor(true)); + + // Create outputs. + factories = new ResourceFactories; + if (!CreateRenderer() || !CreateMixer()) + return false; + + // Load renderer configuration. + NML::Parser::Load(config_path, renderer->registry); + + // Open output subsystems. + if (!OpenVideo() || !OpenAudio()) + return false; + + profiler_font[0] = new Render::RasterFont; + profiler_font[0]->Load(*factories->render, "@core/fonts/profiler_base.nml", "@core/fonts/profiler_base"); + profiler_font[1] = new Render::RasterFont; + profiler_font[1]->Load(*factories->render, "@core/fonts/profiler_bold.nml", "@core/fonts/profiler_bold"); + + fps_font = new Render::RasterFont; + fps_font->Load(*factories->render, "@core/fonts/fps.nml", "@core/fonts/fps"); + + gpu_batch = new GPU::TriangleBatch((GPU::Renderer &)*renderer); + + // Initialize input interface. + Platform::Get().input_system->SetHandle(renderer->GetCurrentSystemWindowHandle()); + + state = SessionSetup; + return true; +} +void ViewerBase::CloseViewer() +{ + CloseSession(); + + for (uint n = 0; n < 2; ++n) + _safe_delete(profiler_font[n]); + _safe_delete(fps_font); + + factories = NULL; + + if (renderer.IsValid()) + { + renderer->Close(); + renderer = NULL; + } + if (mixer.IsValid()) + { + mixer->Close(); + mixer = NULL; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool ViewerBase::SetupSessionSource() // session +{ + switch (session_source) + { + case SessionSourceFilesystem: + Platform::Get().io->Mount(new IO::CFile(session_source_path)); + break; + case SessionSourceArchive: + Platform::Get().io->Mount(new IO::Archive(session_source_path)); + break; + case SessionSourceArchiveBootstrap: + break; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool ViewerBase::OpenScriptVM() // session +{ + // Compile core library. + if (!script_vm->CompileFile("@core/script/nad.nut")) + return false; + + // Set defines. + ListForeachPtr(Variant *, prop, define_list) + script_vm->Set(prop->id, *prop); + + // Load optional includes. + for (uint n = 0; n < include_list.GetCount(); ++n) + if (!script_vm->CompileFile(include_list.ObjectAt(n))) + return false; + + // Compile bootstrap. + if (!bootstrap_script.IsEmpty() && !script_vm->Compile(bootstrap_script, bootstrap_script.Len(), NULL, "Bootstrap")) + return false; + + return true; +} +void ViewerBase::SetVMGlobals() +{ + script_vm->Set("g_project", Script::Variant(project, Script::typetag_Project)); + + script_vm->Set("g_factory", Script::Variant(factories, Script::typetag_ResourceFactories)); + script_vm->Set("g_render", Script::Variant(renderer, Script::typetag_Renderer)); + script_vm->Set("g_mixer", Script::Variant(mixer, Script::typetag_Mixer)); + + script_vm->Set("g_dt_frame", 1.f / 60.f); + script_vm->Set("g_raw_dt_frame", 1.f / 60.f); + script_vm->Set("g_clock", 0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool ViewerBase::LoadSessionData() +{ + if (remote) + session_type = remote_scene.isEmpty() ? SessionProject : SessionScene; + + __LOG__ << "Session type: " << session_type << "\n"; + + using namespace NML; + + if (session_type == SessionProject) + { + if (!remote) + { + if (!LoadFromFile(*project, input_path)) + return false; + } + else + if (!LoadFromFile(*project, remote_project)) + return false; + } + + if (!project->Open(session_type == SessionProject)) + return false; + + switch (session_type) + { + case SessionScene: + { + // Determine the scene type. + if (!remote) + if (!Parser::Load(input_path, remote_scene)) // load local scene over the remote_scene meta file + return false; + + Tag *t_scene2d = remote_scene.GetTag("Scene2D"), + *t_scene3d = remote_scene.GetTag("Scene"); + + // + if (t_scene3d) + { + scene_3d = new S3D::Scene(script_vm); + scene_3d->SetClock(project->clock); + + if (!scene_3d->Create(project->iproject_factory->NewPhysicWorld())) + return false; + if (!scene_3d->FromMetaTag(*t_scene3d, tool_mode ? ToolPreview : NoTool)) + return false; + + scene_3d->name = input_path; + scene_3d->SetAsScriptGlobalScene(); + scene_3d->InstanceSetup(); + scene_3d->RenderSetup(factories); + scene_3d->Setup(tool_mode ? ToolPreview : NoTool); + scene_3d->Reset(); + } + else if (t_scene2d) + { + scene_2d = new S2D::Scene(script_vm); + scene_2d->SetClock(project->clock); + + if (!scene_2d->FromMetaTag(*t_scene2d, tool_mode ? ToolPreview : NoTool)) + return false; + + scene_2d->name = input_path; + scene_2d->SetAsScriptGlobalScene(); + scene_2d->RenderSetup(factories); + scene_2d->Setup(); + scene_2d->Reset(); + } + } + break; + + case SessionProject: + project->Setup(); + break; + } + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool ViewerBase::OpenSession() +{ + if (!OpenScriptVM()) + return false; + + missing_resource = false; + + // Create project. + struct ProjectFactory : public IProjectFactory + { S3D::PhysicWorld *NewPhysicWorld() const { return new S3D::BulletWorld; } }; + + project = new Project(factories, new Freetype2FontFactory, script_vm); + project->iproject_factory = new ProjectFactory; + + SetVMGlobals(); + + // Setup data source. + if (!SetupSessionSource()) + return false; + + // Load viewer data. + if (!LoadSessionData()) + return false; + + time_start = Platform::Get().GetClock(); + return true; +} +void ViewerBase::CloseSession() +{ + paused = false; + + scene_2d = NULL; + scene_3d = NULL; + project = NULL; + + // [EJ] explicitly close the VM now as is may hold references to render resources + if (script_vm.IsValid()) + script_vm->Close(); + +// script_vm = NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void ViewerBase::ExecuteSession() +{ + if (scene_3d) + scene_3d->profiler.ResetProfiles(); + + project->ResetStatistics(); + renderer->ResetStatistics(); + + // Start frame. + if (!paused) + { + project->clock->Update(); + project->UpdateScriptClock(); + } + + float x = 32, y = 32; + bool end_session = false; + + switch (session_type) + { + case SessionScene: + if (scene_2d.IsValid()) + { + renderer->Clear(0, 0, 0); + + if (!paused) + scene_2d->Update(); + + // nGPUTriangleBatch batch(*renderer); + scene_2d->Render(*renderer/*, &batch*/); + } + if (scene_3d.IsValid()) + { + if (!paused) + scene_3d->Update(); + scene_3d->Render(*renderer); + scene_3d->RenderUI(*renderer, gpu_batch); + + // Viewer-specific + { + if (enable_profiler) + scene_3d->DrawProfilerText(*renderer, profiler_font, x, y); + + if (scene_3d->flags.IsSet(S3D::Scene::FlagEnd)) + end_session = true; + + if (!raytrace_path.IsEmpty()) + { + int w = raytrace_width == -1 ? width : raytrace_width, + h = raytrace_height == -1 ? height : raytrace_height; + + __LOG_H__ << "Raytracing frame " << frame_count << " (" << w << "x" << h << ")...\n"; + Raytrace::Raytracer ray(factories->graphic); + + if (ray.SetScene(scene_3d)) + { + Picture out; + ray.GetConfiguration().aa_sample = raytrace_aa; + if (ray.Render(out, w, h)) + PictureIO::Get().TgaSave(out, String::Format("%s/out_%05d.tga", raytrace_path.c_str(), frame_count)); + } + } + } + } + break; + + case SessionProject: + if (!paused) + project->Update(SceneUpdateAll); + + project->Render(*renderer); + + // Viewer-specific + { + if (enable_profiler) + project->DrawProfilerText(*renderer, profiler_font, x, y); + + if (project->flags.IsSet(Project::ProjectFlagEnd)) + end_session = true; + } + break; + } + + // End frame. + fRect viewport = renderer->GetViewport(); + + if (enable_profiler) + { + float x = viewport.GetWidth() - 400.f, y = 32.f; + renderer->DrawProfilerText(profiler_font, x, y); + } + else if (memory_profiler) + { + float x = 0, y = 0; + DrawAllocProfilerText(*renderer, profiler_font, x, y); + } + + if (enable_profiler || display_fps) + { + Color shadow(0, 0, 0, 0.5); + Render::Renderer::WriterConfig config(false); + + float x = 32, y = viewport.GetHeight() - 102; + renderer->Write(*fps_font, String::Format("%02.01f\n", fps.GetFps()), x, y, config, 1, &shadow); + y = viewport.GetHeight() - 112; + renderer->Write(*fps_font, String::Format("%02.01f\n", fps.GetFps()), x, y, config); + } + + renderer->ShowFrame(); + frame_count++; + + // Pause support. +/* if (Input::Device *keyboard = Platform::Get().input_system->GetDevice("keyboard")) + if (keyboard->WasPressed(Input::Device::Key_P)) + { + paused = !paused; + if (!paused) + project->clock->EatDeltaClock(); + } + */ + // Check session runtime error. + if (CheckRuntimeError()) + end_session = true; + if (time_live && ((Platform::Get().GetClock() - time_start) > (time_live * Platform::Get().GetClockFrequency()))) + end_session = true; + + if (end_session) + state = SessionClose; +} +bool ViewerBase::CheckRuntimeError() +{ + // Check VM state. + switch (script_vm->GetState()) + { + case Script::IVM::StateDead: + case Script::IVM::StateExceptionThrown: + return true; + + case Script::IVM::StateOk: + break; + } + + // Check for a missing resource error. + if (missing_resource && !ignore_missing_resource) + __ERR__(__LOG_E__ << "Closing session due to missing resources.\n", true) + + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Script::NetworkDebugger *ViewerBase::CreateVMDebugInterface() +{ + return new Script::ViewerBaseDebugger(*this, new Script::EngineDebugger((Script::EngineVM &)*script_vm), NULL, remote_port); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ViewerBase::State ViewerBase::Execute() +{ + fps.MarkLoop(); + + Platform::Get().input_system->Update(); + bool platform_update = PlatformUpdate(); + + switch (state) + { + //---------------------------------------------------------------------- + case ViewerSetup: + script_vm = new Script::EngineVM; + script_vm->Open(); + + if (active_debug) + script_vm->SetDebugInterface(script_debugger, true); + + if (remote) + { + script_debugger = CreateVMDebugInterface(); + script_vm->SetDebugInterface(script_debugger, true); + + // @FIXME make sure the network thread is running ok. + + __LOG_H__ << "Waiting for controller connection...\n"; + state = WaitRemoteController; + } + else + state = SessionSetup; // local setup done + break; + //---------------------------------------------------------------------- + + //---------------------------------------------------------------------- + case WaitRemoteController: + if (script_debugger && script_debugger->IsConnected()) + { + __LOG_H__ << "Controller connected.\n"; + state = WaitRemoteSetup; + } + if (!platform_update) + state = ViewerClose; + break; + + case WaitRemoteSetup: + if (script_debugger && !script_debugger->IsConnected()) + { + __LOG_H__ << "Controller lost, waiting for controller connection...\n"; + state = WaitRemoteController; + } + break; // state will be altered by the monitor + //---------------------------------------------------------------------- + + case SessionSetup: + if (OpenViewer() && OpenSession()) + { + __LOG_H__ << "Session running.\n"; + state = SessionRunning; + } + else + state = remote ? WaitRemoteSetup : SessionClose; + break; + + case SessionRunning: + ExecuteSession(); + + if (state == SessionRunning) + { + if (script_debugger && !script_debugger->IsConnected()) + state = SessionClose; + + if (!platform_update) + state = SessionClose; + } + + if (state != SessionRunning) + __LOG_H__ << "Closing session.\n"; + break; + + case SessionClose: + CloseSession(); + CloseViewer(); + + if (remote) + { + script_debugger->Stop(); + + if (remote_fs.IsValid()) + { + Platform::Get().io->Unmount(remote_fs); + remote_fs = NULL; + } + + state = ViewerSetup; + } + else + state = ViewerClose; + break; + + case ViewerClose: + break; + } + + if (script_debugger) + while (script_debugger->async.Execute()); + + Platform::Get().Sleep(1); + return state; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void ViewerBase::Suspend() // app sent to background (iOS/Android) +{ + if (script_vm && script_vm->SetupFunctionCall("OnSuspend")) + script_vm->DoFunctionCall(); + if (mixer) + mixer->SuspendWorkerThread(); +} +void ViewerBase::Resume() // app sent back to foreground (iOS/Android) +{ + if (script_vm && script_vm->SetupFunctionCall("OnResume")) + script_vm->DoFunctionCall(); + if (mixer) + mixer->ResumeWorkerThread(); + + if (project.IsValid()) + project->clock->EatDeltaClock(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +ViewerBase::ViewerBase() +{ + state = ViewerSetup; + + paused = false; + missing_resource = false; + + time_start = 0; + time_live = 0; + frame_count = 0; + + raytrace_width = -1; + raytrace_height = -1; + + session_source = SessionSourceFilesystem; + session_type = SessionScene; + session_source_path = "./"; + input_path = "scene.nms"; + + active_debug = false; + + remote = false; + remote_port = 999; + + tool_mode = false; + + script_debugger = NULL; + + safe_mode = false; + ignore_esc = false; + ignore_missing_resource = false; + fullscreen = false; + + enable_profiler = false; + memory_profiler = false; + display_fps = false; + + enable_pause = false; + + for (int n = 0; n < 2; ++n) + profiler_font[n] = NULL; + fps_font = NULL; + + width = 800; + height = 600; + aspect_ratio = 1; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/viewer_base/viewer_base_command_line.cpp b/include/modules/viewer_base/viewer_base_command_line.cpp new file mode 100644 index 0000000..ca5dabb --- /dev/null +++ b/include/modules/viewer_base/viewer_base_command_line.cpp @@ -0,0 +1,431 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "viewer_base/viewer_base.h" + #include + #include "io_archive/io_archive.h" + #include "scene3d/scene.h" + #include "core/engine.h" + #include "filesystem/filesystem.h" + #include "filesystem/io_cfile.h" + #include "platform.h" + + using namespace GS; + + +// [EJ] 4/4: Do not use Log to output the command line as it will be eaten by a release build. + +//------------------------------------------------------------------------------ +void ViewerBase::PrintHeader() +{ + std::cout << "GameStart stand-alone.\n"; + std::cout << "http://www.gamestart3d.com\n"; + std::cout << "Version: " << Core::Version << "\n"; + std::cout << "Emmanuel Julien 2001-2013.\n\n"; +} +String ViewerBase::GetBaseCommandLineParm() const +{ + String parm; + + parm << "Basic usage:\n\n"; + parm << "-P : Execute a project (default: execute scene).\n"; + parm << "-C : Configuration file path.\n"; + parm << "\n"; + + parm << "Data source (default: -f ./):\n\n"; + parm << "-f : Input data from the file system.\n"; + parm << "-A : Input data from an archive.\n"; + parm << "-version : Run a specific project version.\n"; + parm << "\n"; + + parm << "Resource path:\n\n"; + parm << "-CC : Mount a file system directory as core.\n"; + parm << "-MD : Mount a file system directory.\n"; + parm << "-S : Add search path.\n"; + parm << "\n"; + + parm << "Data output (default: -r gl2 -m al):\n\n"; + parm << "-r : Output renderer ('list' for details).\n"; + parm << "-m : Output audio mixer ('nengine dummy -m list' for valid IDs).\n"; + parm << "-w : Display width in pixels.\n"; + parm << "-h : Display height in pixels.\n"; + parm << "\n"; + + parm << "Script interface:\n\n"; + parm << "-I : Include a script.\n"; + parm << "-Ds : Define and initialize a variable.\n"; + parm << "-Di : Define and initialize a variable.\n"; + parm << "-Df : Define and initialize a variable.\n"; + parm << "\n"; + + parm << "Raytracer interface (scene view only):\n\n"; + parm << "-R : Raytrace each frame to a directory.\n"; + parm << "-Rw : Specify the raytracer frame width.\n"; + parm << "-Rh : Specify the raytracer frame height.\n"; + parm << "-Raa : Specify the raytracer AA grid size (default: 4).\n"; + parm << "\n"; + + parm << "Program flags:\n\n"; + parm << "-remote : Start the viewer in remote mode (must be first argument).\n"; + parm << "-remote_port : Set the remote mode listening port.\n"; + parm << "\n"; + parm << "-ignore_esc : Do not exit when escape is pressed.\n"; + parm << "-ignore_missing : Do not exit on missing resource.\n"; + parm << "-ignore_bootstrap : Ignore the bootstrap file.\n"; + parm << "\n"; + parm << "-tool_mode : Execute as if ran in the editor.\n"; + parm << "-safe_mode : Enable renderer/mixer safe-mode.\n"; + parm << "\n"; + parm << "-enable_pause : Enable 'p' key to pause engine.\n"; + parm << "\n"; + parm << "-fallback_disk_fs : Enable disk file system fallback.\n"; + parm << "\n"; + parm << "-enable_profiler : Enable on-screen performance profiler.\n"; + parm << "-memory_profiler : Enable on-screen memory profiler.\n"; + parm << "\n"; + parm << "-log_level : Set the engine log level mask (eg. -log_level !S*).\n"; + parm << " n: None\n"; + parm << " s: Standard\n"; + parm << " H: Header\n"; + parm << " *: Warning\n"; + parm << " !: Error\n"; + parm << " V: Verbose\n"; + parm << " S: Script\n"; + parm << " a: All (default)\n"; + parm << "-time_live : Set runtime time-to-live in seconds.\n"; + + return parm; +} +void ViewerBase::PrintUsage() +{ + std::cout << "Usage: gsviewer input(.nms|.ngp) <-P> <-f|-A> <-S>\n\n"; + std::cout << GetBaseCommandLineParm() << "\n"; + PrintAdditionalUsage(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool ViewerBase::LocateAndParseBootstrap(Stack &_arg) +{ + SharedPtr io; + AutoPtr h; + + // Look for a naked bootstrap file. + if ((h = Platform::Get().io->Open("bootstrap.txt")) != NULL) + session_source = SessionSourceFilesystem; + + else + { + // Mount core to default archive. + io = new IO::Archive("@root/native/000.gsa"); + Platform::Get().io->Mount(io, "@core/"); + + // Look for an archived bootstrap. + h = Platform::Get().io->Open("@core/bootstrap.txt"); + if (h.IsNull()) + { + Platform::Get().io->Unmount("@core/"); // [EJ] unmount on fail to locate bootstrap + return false; + } + + // Set archive as the data source. + session_source = SessionSourceArchiveBootstrap; + Platform::Get().io->Mount(io); + } + + // Parse bootstrap. + String bootstrap; + + size_t s = h->GetSize(); + Array s_buffer(s); + h->Read(s_buffer, s); + + bootstrap.Set(s_buffer.c_ptr(), &s_buffer.c_ptr()[s]); + bootstrap.Split(" ", _arg, '\"'); + + h = NULL; + return true; +} +void ViewerBase::SetupVersion(const char *name) +{ + using namespace NML; + + File file; + if (!Parser::Load("@root/.reserved/versions.rls", file)) + return; + + if (Tag *versions = file.GetTag("Versions;")) + { + NMLTagForeach(v, *versions) + if (Tag *n = v->GetTypedTag("Name", Variant::VariantString)) + if (String(n->GetString()) == name) + if (Tag *s = v->GetTypedTag("BootstrapScript", Variant::VariantString)) + { + bootstrap_script = s->GetString(); + return; + } + } +} +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------- +bool ViewerBase::ParseCommandLine(Stack &_arg) +{ + if ((_arg.GetCount() < 1) && !LocateAndParseBootstrap(_arg)) + __ERR__(PrintUsage(), false) + + session_type = SessionScene; // assume scene session + + // Remote is a special flag + int n = 0; + if (_arg[0] != "-remote") + input_path = _arg[n++]; + + // Parse optional arguments. + int narg = (int)_arg.GetCount(); + for ( ; n < narg; ++n) + { + String arg(_arg[n]); + + if (arg == "-P") + session_type = SessionProject; + + // Version. + else if (arg == "-version") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-version: Missing version name.\n", false); + SetupVersion(_arg[n]); + } + + // Time to live. + else if (arg == "-time_live") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-time_live: Missing mask.\n", false); + time_live = String::atoi(_arg[n]); + } + + // Log filter. + else if (arg == "-log_level") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-log_level: Missing mask.\n", false); + + uint mask = 0; + for (const char *p_flag = _arg[n]; p_flag[0]; ++p_flag) + switch (p_flag[0]) + { + case 'n': mask = EngineLogNone; break; + case 's': mask |= EngineLogStandard; break; + case 'H': mask |= EngineLogHeader; break; + case '*': mask |= EngineLogWarning; break; + case '!': mask |= EngineLogError; break; + case 'V': mask |= EngineLogVerbose; break; + case 'S': mask |= EngineLogScript; break; + case 'a': mask |= EngineLogAll; break; + } + + LogSystem::Get().GetLog().SetLogLevel(mask); + } + + else if (arg == "-debug") + active_debug = true; + + else if (arg == "-ignore_bootstrap") + ignore_bootstrap = true; + else if (arg == "-ignore_esc") + ignore_esc = true; + else if (arg == "-ignore_missing") + ignore_missing_resource = true; + + else if (arg == "-tool_mode") + tool_mode = true; + + else if (arg == "-fallback_disk_fs") + Platform::Get().io->Mount(new IO::CFile); + + else if (arg == "-safe_mode") + safe_mode = true; + + else if (arg == "-enable_profiler") + enable_profiler = true; + else if (arg == "-memory_profiler") + memory_profiler = true; + + else if (arg == "-enable_pause") + enable_pause = true; + + // Config path. + else if (arg == "-C") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-C: Missing configuration file path.\n", false); + config_path = _arg[n]; + } + + // File system source. + else if (arg == "-f") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-f: Missing root path.\n", false); + session_source_path = _arg[n]; + session_source = SessionSourceFilesystem; + } + + // Archive source. + else if (arg == "-A") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-A: Missing archive path.\n", false); + session_source_path = _arg[n]; + session_source = SessionSourceArchive; + } + + // Renderer. + else if (arg == "-r") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-r: Missing renderer id.\n", false); + s_render = _arg[n]; + } + + else if (arg == "-w") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-w: Missing width value.\n", false); + width = String::atoi(_arg[n]); + } + else if (arg == "-h") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-h: Missing height value.\n", false); + height = String::atoi(_arg[n]); + } + + // Mixer. + else if (arg == "-m") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-m: Missing mixer id.\n", false); + s_mixer = _arg[n]; + } + + // Search path. + else if (arg == "-S") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-S: Missing search path.\n", false); + + Platform::Get().io->Mount(new IO::CFile(_arg[n])); + } + + // Mount core. + else if (arg == "-CC") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-CC: Missing core path.\n", false); + + String c_path = _arg[n]; + Platform::Get().io->Mount(new IO::CFile(c_path), "@core/"); +Platform::Get().io->Mount(new IO::CFile(c_path)); // FIXME + } + + // Mount point. + else if (arg == "-MD") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-MD: Missing directory path.\n", false); + String dir_path = _arg[n]; + + if (++n == narg) + __ERR__(__LOG_E__ << "-MD: Missing mount point.\n", false); + String mount_point = _arg[n]; + + Platform::Get().io->Mount(new IO::CFile(dir_path), mount_point); + } + + // Raytrace path. + else if (arg == "-R") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-R: Missing raytracer output path.\n", false); + raytrace_path = _arg[n]; + } + + // Raytrace width. + else if (arg == "-Rw") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-Rw: Missing raytracer frame width.\n", false); + raytrace_width = String::atoi(_arg[n]); + } + + // Raytrace height. + else if (arg == "-Rh") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-Rh: Missing raytracer frame height.\n", false); + raytrace_height = String::atoi(_arg[n]); + } + + // Raytrace AA. + else if (arg == "-Raa") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-Raa: Missing raytracer AA grid size.\n", false); + raytrace_aa = String::atoi(_arg[n]); + } + + // Include. + else if (arg == "-I") + { + if (++n == narg) + __ERR__(__LOG_E__ << "-I: Missing include path.\n", false); + + if (!include_list.Add(_arg[n])) + __ERR__(__LOG_E__ << "Failed to allocate include structure.\n", false); + } + + // Variable. + else if (arg == "-Ds") + { + n += 2; + if (n == narg) + __ERR__(__LOG_E__ << "-Ds: Incomplete key-value pair. (eg. -Ds my_var \"String Value\")\n", false); + Variant *yo = new Variant(_arg[n - 1], _arg[n]); + if (!define_list.Add(new Variant(_arg[n - 1], _arg[n]))) + __ERR__(__LOG_E__ << "Failed to allocate define structure.\n", false); + } + + // Variable. + else if (arg == "-Di") + { + n += 2; + if (n == narg) + __ERR__(__LOG_E__ << "-Di: Incomplete key-value pair. (eg. -Di my_var 5)\n", false); + + if (!define_list.Add(new Variant(_arg[n - 1], String::atoi(_arg[n])))) + __ERR__(__LOG_E__ << "Failed to allocate define structure.\n", false); + } + + // Variable. + else if (arg == "-Df") + { + n += 2; + if (n == narg) + __ERR__(__LOG_E__ << "-Df: Incomplete key-value pair. (eg. -Df my_var 5.5)\n", false); + + if (!define_list.Add(new Variant(_arg[n - 1], String::atof(_arg[n])))) + __ERR__(__LOG_E__ << "Failed to allocate define structure.\n", false); + } + + else if (!OnUnknownCommandLineParam(_arg, n)) + __ERR__(__LOG_E__ << "Unknown command line parameter '" << arg << "'\n", false); + } + return true; +} +//----------------------------------------------------------------------------- diff --git a/include/modules/viewer_base/viewer_base_config.cpp b/include/modules/viewer_base/viewer_base_config.cpp new file mode 100644 index 0000000..99371c2 --- /dev/null +++ b/include/modules/viewer_base/viewer_base_config.cpp @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "viewer_base/viewer_base.h" + #include "core/renderer.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +bool ViewerBase::LoadViewerConfig(const char *path) +{ + if (!NML::Parser::Load(path, config_file)) + return false; + + NML::Tag *tag; + if ((tag = config_file.GetTypedTag("Fullscreen", Variant::VariantBool)) != NULL) + fullscreen = tag->GetBool(); + if ((tag = config_file.GetTypedTag("Width", Variant::VariantInteger)) != NULL) + width = tag->GetInteger(); + if ((tag = config_file.GetTypedTag("Height", Variant::VariantInteger)) != NULL) + height = tag->GetInteger(); + if ((tag = config_file.GetTypedTag("AspectRatio", Variant::VariantFloat)) != NULL) + aspect_ratio = tag->GetReal(); + + if (renderer) + renderer->SetGlobalAspectRatio(aspect_ratio); + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/modules/viewer_base/viewer_base_debugger.cpp b/include/modules/viewer_base/viewer_base_debugger.cpp new file mode 100644 index 0000000..5c44627 --- /dev/null +++ b/include/modules/viewer_base/viewer_base_debugger.cpp @@ -0,0 +1,114 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "viewer_base/viewer_base_debugger.h" + #include "viewer_base/viewer_base.h" + #include "io_net/io_net_client.h" + #include "async/task_loop.h" + #include "filesystem/io_buffer.h" + #include "filesystem/filesystem.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void ViewerBaseDebugger::SetViewerStatus(const char *status) +{ __LOG__ << "Viewer: " << status << "\n"; } +IO::Base *ViewerBaseDebugger::WrapRemoteFileSystem(IO::Base *remote_fs) +{ return new IO::Buffer(remote_fs, 65536, 65536); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void ViewerBaseDebugger::OnControllerPacketReceived(const Array &data) +{ + using namespace NML; + + Tag tag; + Parser::ParseTag(tag, data.Start(), data.End()); + + if (tag.name == "ShowPerformanceProfiler") + viewer.enable_profiler = tag.GetBool(); + else if (tag.name == "ShowMemoryProfiler") + viewer.memory_profiler = tag.GetBool(); + else if (tag.name == "DebugPhysics") + { + if (viewer.project.IsValid()) + viewer.project->flags.Raise(GS::Core::Project::ProjectFlagDebugPhysics, tag.GetBool()); + if (viewer.scene_3d.IsValid()) + viewer.scene_3d->flags.Raise(GS::S3D::Scene::FlagDebugPhysics, tag.GetBool()); + } + + // Remote session setup. + else if (tag.name == "MountRemoteFileSystem") + { + SetViewerStatus("Connecting to file server"); + + String address = GetPeerAddress(); + + int port = -1; + if (Tag *port_tag = tag.GetTypedTag("Port", GS::Variant::VariantInteger)) + port = port_tag->GetInteger(); + + __LOG_H__ << "Mounting remote file system from " << address << " on port " << port << ".\n"; + + if (!address.IsEmpty() && (port != -1)) + { + SharedPtr net(new IO::Net); + + bool connection_status = false; + + if (net->Connect(address, port)) + { + // Wait for connection... + __LOG_H__ << "Waiting for remote file system connection...\n"; + + StartTaskLoop(net->IsConnected() == false, 10000) // 10s timeout + Platform::Get().Sleep(1); + EndTaskLoop + + if ((connection_status = net->IsConnected()) == true) + { + // Mount net FS through an IO cache layer. + viewer.remote_fs = WrapRemoteFileSystem(net); + Platform::Get().io->Mount(viewer.remote_fs); + + // Remote FS ready. + BroadcastNetworkCommand(""); + } + } + + if (connection_status == false) + SetViewerStatus("File server connection failed"); + } + } + else if (tag.name == "SetSessionInput") + { + SetViewerStatus("Loading session"); + + viewer.remote_project.Clear(); + if (Tag *t = tag.GetTag("Environment")) + viewer.remote_project.AddRoot(t->Clone()); + + viewer.remote_scene.Clear(); + if (Tag *t = tag.GetTag("Scene")) + viewer.remote_scene.AddRoot(t->Clone()); + else if (Tag *t = tag.GetTag("Scene2D")) + viewer.remote_scene.AddRoot(t->Clone()); + + BroadcastNetworkCommand(""); + } + else if (tag.name == "StartSession") + { + SetViewerStatus("Session Running"); + viewer.state = ViewerBase::SessionSetup; // setup session before starting it + } + else + NetworkDebugger::OnControllerPacketReceived(data); +} +//------------------------------------------------------------------------------ + +ViewerBaseDebugger::ViewerBaseDebugger(ViewerBase &v, IDebugger *idbg, const char *address, int port) : NetworkDebugger(v.script_vm, idbg, address, port), viewer(v) {} diff --git a/include/modules/viewer_base/viewer_base_vmhook.cpp b/include/modules/viewer_base/viewer_base_vmhook.cpp new file mode 100644 index 0000000..f542095 --- /dev/null +++ b/include/modules/viewer_base/viewer_base_vmhook.cpp @@ -0,0 +1,36 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "viewer_base/viewer_base_vmhook.h" + #include "viewer_base/viewer_base.h" + + using namespace GS; + using namespace GS::Script; + + +//------------------------------------------------------------------------------ +void ViewerEventHookTable::OnStep(char type, const char *source, int line, const char *funcname) +{} +void ViewerEventHookTable::Kill(const char *reason) +{ viewer->DisplayUserMessage(ViewerBase::MessageWarning, String::Format("The script VM was killed:\n\n%s", reason)); } +void ViewerEventHookTable::OnCompilerError(const char *error, const char *source, int line) +{ viewer->DisplayUserMessage(ViewerBase::MessageNormal, String::Format("Script compiler error.\n\nSource: %s\nLine: %d\n\n%s", source, line, error)); } +void ViewerEventHookTable::OnRuntimeException(const char *error) +{ + String msg = String::Format("Script runtime exception:\n\n%s", error); + + AutoList callstack; + viewer->project->vm->GetCallStack(callstack); + + msg += "\n\nCallstack:\n\n"; + ListForeachPtr(IVM::CallStackEntry *, cs, callstack) + msg += String::Format(" - %s() (line %d) in \"%s\"\n", cs->function.c_str(), cs->line, cs->source.c_str()); + + __LOG_E__ << "Squirrel Compiler Error: '" << msg << "'\n"; + + viewer->DisplayUserMessage(ViewerBase::MessageNormal, msg); +} +//------------------------------------------------------------------------------ diff --git a/include/opencv2/calib3d.hpp b/include/opencv2/calib3d.hpp index 66ffe2c..c5b3ffd 100644 --- a/include/opencv2/calib3d.hpp +++ b/include/opencv2/calib3d.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CALIB3D_HPP__ -#define __OPENCV_CALIB3D_HPP__ +#ifndef OPENCV_CALIB3D_HPP +#define OPENCV_CALIB3D_HPP #include "opencv2/core.hpp" #include "opencv2/features2d.hpp" @@ -96,17 +96,62 @@ u = f_x*x' + c_x \\ v = f_y*y' + c_y \end{array}\f] +The following figure illustrates the pinhole camera model. + +![Pinhole camera model](pics/pinhole_camera_model.png) + Real lenses usually have some distortion, mostly radial distortion and slight tangential distortion. So, the above model is extended as: -\f[\begin{array}{l} \vecthree{x}{y}{z} = R \vecthree{X}{Y}{Z} + t \\ x' = x/z \\ y' = y/z \\ x'' = x' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + 2 p_1 x' y' + p_2(r^2 + 2 x'^2) + s_1 r^2 + s_2 r^4 \\ y'' = y' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' + s_1 r^2 + s_2 r^4 \\ \text{where} \quad r^2 = x'^2 + y'^2 \\ u = f_x*x'' + c_x \\ v = f_y*y'' + c_y \end{array}\f] +\f[\begin{array}{l} +\vecthree{x}{y}{z} = R \vecthree{X}{Y}{Z} + t \\ +x' = x/z \\ +y' = y/z \\ +x'' = x' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + 2 p_1 x' y' + p_2(r^2 + 2 x'^2) + s_1 r^2 + s_2 r^4 \\ +y'' = y' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' + s_3 r^2 + s_4 r^4 \\ +\text{where} \quad r^2 = x'^2 + y'^2 \\ +u = f_x*x'' + c_x \\ +v = f_y*y'' + c_y +\end{array}\f] \f$k_1\f$, \f$k_2\f$, \f$k_3\f$, \f$k_4\f$, \f$k_5\f$, and \f$k_6\f$ are radial distortion coefficients. \f$p_1\f$ and \f$p_2\f$ are tangential distortion coefficients. \f$s_1\f$, \f$s_2\f$, \f$s_3\f$, and \f$s_4\f$, are the thin prism distortion -coefficients. Higher-order coefficients are not considered in OpenCV. In the functions below the -coefficients are passed or returned as +coefficients. Higher-order coefficients are not considered in OpenCV. -\f[(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f] +The next figures show two common types of radial distortion: barrel distortion (typically \f$ k_1 < 0 \f$) and pincushion distortion (typically \f$ k_1 > 0 \f$). + +![](pics/distortion_examples.png) +![](pics/distortion_examples2.png) + +In some cases the image sensor may be tilted in order to focus an oblique plane in front of the +camera (Scheimpfug condition). This can be useful for particle image velocimetry (PIV) or +triangulation with a laser fan. The tilt causes a perspective distortion of \f$x''\f$ and +\f$y''\f$. This distortion can be modelled in the following way, see e.g. @cite Louhichi07. + +\f[\begin{array}{l} +s\vecthree{x'''}{y'''}{1} = +\vecthreethree{R_{33}(\tau_x, \tau_y)}{0}{-R_{13}(\tau_x, \tau_y)} +{0}{R_{33}(\tau_x, \tau_y)}{-R_{23}(\tau_x, \tau_y)} +{0}{0}{1} R(\tau_x, \tau_y) \vecthree{x''}{y''}{1}\\ +u = f_x*x''' + c_x \\ +v = f_y*y''' + c_y +\end{array}\f] + +where the matrix \f$R(\tau_x, \tau_y)\f$ is defined by two rotations with angular parameter \f$\tau_x\f$ +and \f$\tau_y\f$, respectively, + +\f[ +R(\tau_x, \tau_y) = +\vecthreethree{\cos(\tau_y)}{0}{-\sin(\tau_y)}{0}{1}{0}{\sin(\tau_y)}{0}{\cos(\tau_y)} +\vecthreethree{1}{0}{0}{0}{\cos(\tau_x)}{\sin(\tau_x)}{0}{-\sin(\tau_x)}{\cos(\tau_x)} = +\vecthreethree{\cos(\tau_y)}{\sin(\tau_y)\sin(\tau_x)}{-\sin(\tau_y)\cos(\tau_x)} +{0}{\cos(\tau_x)}{\sin(\tau_x)} +{\sin(\tau_y)}{-\cos(\tau_y)\sin(\tau_x)}{\cos(\tau_y)\cos(\tau_x)}. +\f] + +In the functions below the coefficients are passed or returned as + +\f[(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f] vector. That is, if the vector contains four elements, it means that \f$k_3=0\f$ . The distortion coefficients do not depend on the scene viewed. Thus, they also belong to the intrinsic camera @@ -139,7 +184,7 @@ pattern (every view is described by several 3D-2D point correspondences). - A calibration example on stereo matching can be found at opencv_source_code/samples/cpp/stereo_match.cpp - (Python) A camera calibration sample can be found at - opencv_source_code/samples/python2/calibrate.py + opencv_source_code/samples/python/calibrate.py @{ @defgroup calib3d_fisheye Fisheye camera model @@ -154,7 +199,7 @@ pattern (every view is described by several 3D-2D point correspondences). \f[x = Xc_1 \\ y = Xc_2 \\ z = Xc_3\f] - The pinehole projection coordinates of P is [a; b] where + The pinhole projection coordinates of P is [a; b] where \f[a = x / z \ and \ b = y / z \\ r^2 = a^2 + b^2 \\ \theta = atan(r)\f] @@ -164,12 +209,12 @@ pattern (every view is described by several 3D-2D point correspondences). The distorted point coordinates are [x'; y'] where - \f[x' = (\theta_d / r) x \\ y' = (\theta_d / r) y \f] + \f[x' = (\theta_d / r) a \\ y' = (\theta_d / r) b \f] Finally, conversion into pixel coordinates: The final pixel coordinates vector [u; v] where: \f[u = f_x (x' + \alpha y') + c_x \\ - v = f_y yy + c_y\f] + v = f_y y' + c_y\f] @defgroup calib3d_c C API @@ -183,17 +228,18 @@ namespace cv //! @{ //! type of the robust estimation algorithm -enum { LMEDS = 4, //!< least-median algorithm +enum { LMEDS = 4, //!< least-median of squares algorithm RANSAC = 8, //!< RANSAC algorithm RHO = 16 //!< RHO algorithm }; enum { SOLVEPNP_ITERATIVE = 0, - SOLVEPNP_EPNP = 1, // F.Moreno-Noguer, V.Lepetit and P.Fua "EPnP: Efficient Perspective-n-Point Camera Pose Estimation" - SOLVEPNP_P3P = 2, // X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang; "Complete Solution Classification for the Perspective-Three-Point Problem" - SOLVEPNP_DLS = 3, // Joel A. Hesch and Stergios I. Roumeliotis. "A Direct Least-Squares (DLS) Method for PnP" - SOLVEPNP_UPNP = 4 // A.Penate-Sanchez, J.Andrade-Cetto, F.Moreno-Noguer. "Exhaustive Linearization for Robust Camera Pose and Focal Length Estimation" - + SOLVEPNP_EPNP = 1, //!< EPnP: Efficient Perspective-n-Point Camera Pose Estimation @cite lepetit2009epnp + SOLVEPNP_P3P = 2, //!< Complete Solution Classification for the Perspective-Three-Point Problem @cite gao2003complete + SOLVEPNP_DLS = 3, //!< A Direct Least-Squares (DLS) Method for PnP @cite hesch2011direct + SOLVEPNP_UPNP = 4, //!< Exhaustive Linearization for Robust Camera Pose and Focal Length Estimation @cite penate2013exhaustive + SOLVEPNP_AP3P = 5, //!< An Efficient Algebraic Solution to the Perspective-Three-Point Problem @cite Ke17 + SOLVEPNP_MAX_COUNT //!< Used for count }; enum { CALIB_CB_ADAPTIVE_THRESH = 1, @@ -221,18 +267,24 @@ enum { CALIB_USE_INTRINSIC_GUESS = 0x00001, CALIB_RATIONAL_MODEL = 0x04000, CALIB_THIN_PRISM_MODEL = 0x08000, CALIB_FIX_S1_S2_S3_S4 = 0x10000, + CALIB_TILTED_MODEL = 0x40000, + CALIB_FIX_TAUX_TAUY = 0x80000, + CALIB_USE_QR = 0x100000, //!< use QR instead of SVD decomposition for solving. Faster but potentially less precise + CALIB_FIX_TANGENT_DIST = 0x200000, // only for stereo CALIB_FIX_INTRINSIC = 0x00100, CALIB_SAME_FOCAL_LENGTH = 0x00200, // for stereo rectification - CALIB_ZERO_DISPARITY = 0x00400 + CALIB_ZERO_DISPARITY = 0x00400, + CALIB_USE_LU = (1 << 17), //!< use LU instead of SVD decomposition for solving. much faster but potentially less precise + CALIB_USE_EXTRINSIC_GUESS = (1 << 22), //!< for stereoCalibrate }; //! the algorithm for finding fundamental matrix enum { FM_7POINT = 1, //!< 7-point algorithm FM_8POINT = 2, //!< 8-point algorithm - FM_LMEDS = 4, //!< least-median algorithm - FM_RANSAC = 8 //!< RANSAC algorithm + FM_LMEDS = 4, //!< least-median algorithm. 7-point algorithm is used. + FM_RANSAC = 8 //!< RANSAC algorithm. It needs at least 15 points. 7-point algorithm is used. }; @@ -256,28 +308,34 @@ optimization procedures like calibrateCamera, stereoCalibrate, or solvePnP . */ CV_EXPORTS_W void Rodrigues( InputArray src, OutputArray dst, OutputArray jacobian = noArray() ); +/** @example samples/cpp/tutorial_code/features2D/Homography/pose_from_homography.cpp +An example program about pose estimation from coplanar points + +Check @ref tutorial_homography "the corresponding tutorial" for more details +*/ + /** @brief Finds a perspective transformation between two planes. @param srcPoints Coordinates of the points in the original plane, a matrix of the type CV_32FC2 or vector\ . @param dstPoints Coordinates of the points in the target plane, a matrix of the type CV_32FC2 or a vector\ . -@param method Method used to computed a homography matrix. The following methods are possible: -- **0** - a regular method using all the points +@param method Method used to compute a homography matrix. The following methods are possible: +- **0** - a regular method using all the points, i.e., the least squares method - **RANSAC** - RANSAC-based robust method - **LMEDS** - Least-Median robust method -- **RHO** - PROSAC-based robust method +- **RHO** - PROSAC-based robust method @param ransacReprojThreshold Maximum allowed reprojection error to treat a point pair as an inlier (used in the RANSAC and RHO methods only). That is, if -\f[\| \texttt{dstPoints} _i - \texttt{convertPointsHomogeneous} ( \texttt{H} * \texttt{srcPoints} _i) \| > \texttt{ransacReprojThreshold}\f] -then the point \f$i\f$ is considered an outlier. If srcPoints and dstPoints are measured in pixels, +\f[\| \texttt{dstPoints} _i - \texttt{convertPointsHomogeneous} ( \texttt{H} * \texttt{srcPoints} _i) \|_2 > \texttt{ransacReprojThreshold}\f] +then the point \f$i\f$ is considered as an outlier. If srcPoints and dstPoints are measured in pixels, it usually makes sense to set this parameter somewhere in the range of 1 to 10. @param mask Optional output mask set by a robust method ( RANSAC or LMEDS ). Note that the input mask values are ignored. -@param maxIters The maximum number of RANSAC iterations, 2000 is the maximum it can be. +@param maxIters The maximum number of RANSAC iterations. @param confidence Confidence level, between 0 and 1. -The functions find and return the perspective transformation \f$H\f$ between the source and the +The function finds and returns the perspective transformation \f$H\f$ between the source and the destination planes: \f[s_i \vecthree{x'_i}{y'_i}{1} \sim H \vecthree{x_i}{y_i}{1}\f] @@ -292,10 +350,10 @@ pairs to compute an initial homography estimate with a simple least-squares sche However, if not all of the point pairs ( \f$srcPoints_i\f$, \f$dstPoints_i\f$ ) fit the rigid perspective transformation (that is, there are some outliers), this initial estimate will be poor. In this case, you can use one of the three robust methods. The methods RANSAC, LMeDS and RHO try many different -random subsets of the corresponding point pairs (of four pairs each), estimate the homography matrix -using this subset and a simple least-square algorithm, and then compute the quality/goodness of the -computed homography (which is the number of inliers for RANSAC or the median re-projection error for -LMeDs). The best subset is then used to produce the initial estimate of the homography matrix and +random subsets of the corresponding point pairs (of four pairs each, collinear pairs are discarded), estimate the homography matrix +using this subset and a simple least-squares algorithm, and then compute the quality/goodness of the +computed homography (which is the number of inliers for RANSAC or the least median re-projection error for +LMeDS). The best subset is then used to produce the initial estimate of the homography matrix and the mask of inliers/outliers. Regardless of the method, robust or not, the computed homography matrix is refined further (using @@ -308,17 +366,12 @@ correctly only when there are more than 50% of inliers. Finally, if there are no noise is rather small, use the default method (method=0). The function is used to find initial intrinsic and extrinsic matrices. Homography matrix is -determined up to a scale. Thus, it is normalized so that \f$h_{33}=1\f$. Note that whenever an H matrix +determined up to a scale. Thus, it is normalized so that \f$h_{33}=1\f$. Note that whenever an \f$H\f$ matrix cannot be estimated, an empty one will be returned. @sa - getAffineTransform, getPerspectiveTransform, estimateRigidTransform, warpPerspective, - perspectiveTransform - -@note - - A example on calculating a homography for image matching can be found at - opencv_source_code/samples/cpp/video_homography.cpp - +getAffineTransform, estimateAffine2D, estimateAffinePartial2D, getPerspectiveTransform, warpPerspective, +perspectiveTransform */ CV_EXPORTS_W Mat findHomography( InputArray srcPoints, InputArray dstPoints, int method = 0, double ransacReprojThreshold = 3, @@ -344,8 +397,8 @@ and a rotation matrix. It optionally returns three rotation matrices, one for each axis, and the three Euler angles in degrees (as the return value) that could be used in OpenGL. Note, there is always more than one -sequence of rotations about the three principle axes that results in the same orientation of an -object, eg. see @cite Slabaugh . Returned tree rotation matrices and corresponding three Euler angules +sequence of rotations about the three principal axes that results in the same orientation of an +object, e.g. see @cite Slabaugh . Returned tree rotation matrices and corresponding three Euler angles are only one of the possible solutions. */ CV_EXPORTS_W Vec3d RQDecomp3x3( InputArray src, OutputArray mtxR, OutputArray mtxQ, @@ -370,8 +423,8 @@ matrix and the position of a camera. It optionally returns three rotation matrices, one for each axis, and three Euler angles that could be used in OpenGL. Note, there is always more than one sequence of rotations about the three -principle axes that results in the same orientation of an object, eg. see @cite Slabaugh . Returned -tree rotation matrices and corresponding three Euler angules are only one of the possible solutions. +principal axes that results in the same orientation of an object, e.g. see @cite Slabaugh . Returned +tree rotation matrices and corresponding three Euler angles are only one of the possible solutions. The function is based on RQDecomp3x3 . */ @@ -443,8 +496,8 @@ vector\ ), where N is the number of points in the view. @param tvec Translation vector. @param cameraMatrix Camera matrix \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}\f$ . @param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements. If -the vector is NULL/empty, the zero distortion coefficients are assumed. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. If the vector is empty, the zero distortion coefficients are assumed. @param imagePoints Output array of image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel, or vector\ . @param jacobian Optional output 2Nx(10+\) jacobian matrix of derivatives of image @@ -474,20 +527,27 @@ CV_EXPORTS_W void projectPoints( InputArray objectPoints, OutputArray jacobian = noArray(), double aspectRatio = 0 ); +/** @example samples/cpp/tutorial_code/features2D/Homography/homography_from_camera_displacement.cpp +An example program about homography from the camera displacement + +Check @ref tutorial_homography "the corresponding tutorial" for more details +*/ + /** @brief Finds an object pose from 3D-2D point correspondences. -@param objectPoints Array of object points in the object coordinate space, 3xN/Nx3 1-channel or +@param objectPoints Array of object points in the object coordinate space, Nx3 1-channel or 1xN/Nx1 3-channel, where N is the number of points. vector\ can be also passed here. -@param imagePoints Array of corresponding image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel, +@param imagePoints Array of corresponding image points, Nx2 1-channel or 1xN/Nx1 2-channel, where N is the number of points. vector\ can be also passed here. @param cameraMatrix Input camera matrix \f$A = \vecthreethree{fx}{0}{cx}{0}{fy}{cy}{0}{0}{1}\f$ . @param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements. If -the vector is NULL/empty, the zero distortion coefficients are assumed. -@param rvec Output rotation vector (see Rodrigues ) that, together with tvec , brings points from +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are +assumed. +@param rvec Output rotation vector (see @ref Rodrigues ) that, together with tvec , brings points from the model coordinate system to the camera coordinate system. @param tvec Output translation vector. -@param useExtrinsicGuess Parameter used for SOLVEPNP_ITERATIVE. If true (1), the function uses +@param useExtrinsicGuess Parameter used for #SOLVEPNP_ITERATIVE. If true (1), the function uses the provided rvec and tvec values as initial approximations of the rotation and translation vectors, respectively, and further optimizes them. @param flags Method for solving a PnP problem: @@ -496,24 +556,120 @@ this case the function finds such a pose that minimizes reprojection error, that of squared distances between the observed projections imagePoints and the projected (using projectPoints ) objectPoints . - **SOLVEPNP_P3P** Method is based on the paper of X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang -"Complete Solution Classification for the Perspective-Three-Point Problem". In this case the -function requires exactly four object and image points. +"Complete Solution Classification for the Perspective-Three-Point Problem" (@cite gao2003complete). +In this case the function requires exactly four object and image points. +- **SOLVEPNP_AP3P** Method is based on the paper of T. Ke, S. Roumeliotis +"An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (@cite Ke17). +In this case the function requires exactly four object and image points. - **SOLVEPNP_EPNP** Method has been introduced by F.Moreno-Noguer, V.Lepetit and P.Fua in the -paper "EPnP: Efficient Perspective-n-Point Camera Pose Estimation". +paper "EPnP: Efficient Perspective-n-Point Camera Pose Estimation" (@cite lepetit2009epnp). - **SOLVEPNP_DLS** Method is based on the paper of Joel A. Hesch and Stergios I. Roumeliotis. -"A Direct Least-Squares (DLS) Method for PnP". +"A Direct Least-Squares (DLS) Method for PnP" (@cite hesch2011direct). - **SOLVEPNP_UPNP** Method is based on the paper of A.Penate-Sanchez, J.Andrade-Cetto, F.Moreno-Noguer. "Exhaustive Linearization for Robust Camera Pose and Focal Length -Estimation". In this case the function also estimates the parameters \f$f_x\f$ and \f$f_y\f$ +Estimation" (@cite penate2013exhaustive). In this case the function also estimates the parameters \f$f_x\f$ and \f$f_y\f$ assuming that both have the same value. Then the cameraMatrix is updated with the estimated focal length. +- **SOLVEPNP_AP3P** Method is based on the paper of Tong Ke and Stergios I. Roumeliotis. +"An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (@cite Ke17). In this case the +function requires exactly four object and image points. The function estimates the object pose given a set of object points, their corresponding image -projections, as well as the camera matrix and the distortion coefficients. +projections, as well as the camera matrix and the distortion coefficients, see the figure below +(more precisely, the X-axis of the camera frame is pointing to the right, the Y-axis downward +and the Z-axis forward). + +![](pnp.jpg) + +Points expressed in the world frame \f$ \bf{X}_w \f$ are projected into the image plane \f$ \left[ u, v \right] \f$ +using the perspective projection model \f$ \Pi \f$ and the camera intrinsic parameters matrix \f$ \bf{A} \f$: + +\f[ + \begin{align*} + \begin{bmatrix} + u \\ + v \\ + 1 + \end{bmatrix} &= + \bf{A} \hspace{0.1em} \Pi \hspace{0.2em} ^{c}\bf{M}_w + \begin{bmatrix} + X_{w} \\ + Y_{w} \\ + Z_{w} \\ + 1 + \end{bmatrix} \\ + \begin{bmatrix} + u \\ + v \\ + 1 + \end{bmatrix} &= + \begin{bmatrix} + f_x & 0 & c_x \\ + 0 & f_y & c_y \\ + 0 & 0 & 1 + \end{bmatrix} + \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 + \end{bmatrix} + \begin{bmatrix} + r_{11} & r_{12} & r_{13} & t_x \\ + r_{21} & r_{22} & r_{23} & t_y \\ + r_{31} & r_{32} & r_{33} & t_z \\ + 0 & 0 & 0 & 1 + \end{bmatrix} + \begin{bmatrix} + X_{w} \\ + Y_{w} \\ + Z_{w} \\ + 1 + \end{bmatrix} + \end{align*} +\f] + +The estimated pose is thus the rotation (`rvec`) and the translation (`tvec`) vectors that allow to transform +a 3D point expressed in the world frame into the camera frame: + +\f[ + \begin{align*} + \begin{bmatrix} + X_c \\ + Y_c \\ + Z_c \\ + 1 + \end{bmatrix} &= + \hspace{0.2em} ^{c}\bf{M}_w + \begin{bmatrix} + X_{w} \\ + Y_{w} \\ + Z_{w} \\ + 1 + \end{bmatrix} \\ + \begin{bmatrix} + X_c \\ + Y_c \\ + Z_c \\ + 1 + \end{bmatrix} &= + \begin{bmatrix} + r_{11} & r_{12} & r_{13} & t_x \\ + r_{21} & r_{22} & r_{23} & t_y \\ + r_{31} & r_{32} & r_{33} & t_z \\ + 0 & 0 & 0 & 1 + \end{bmatrix} + \begin{bmatrix} + X_{w} \\ + Y_{w} \\ + Z_{w} \\ + 1 + \end{bmatrix} + \end{align*} +\f] @note - An example of how to use solvePnP for planar augmented reality can be found at - opencv_source_code/samples/python2/plane_ar.py + opencv_source_code/samples/python/plane_ar.py - If you are using Python: - Numpy array slices won't work as input because solvePnP requires contiguous arrays (enforced by the assertion using cv::Mat::checkVector() around line 55 of @@ -524,6 +680,15 @@ projections, as well as the camera matrix and the distortion coefficients. - Thus, given some data D = np.array(...) where D.shape = (N,M), in order to use a subset of it as, e.g., imagePoints, one must effectively copy it into a new array: imagePoints = np.ascontiguousarray(D[:,:2]).reshape((N,1,2)) + - The methods **SOLVEPNP_DLS** and **SOLVEPNP_UPNP** cannot be used as the current implementations are + unstable and sometimes give completely wrong results. If you pass one of these two + flags, **SOLVEPNP_EPNP** method will be used instead. + - The minimum number of points is 4 in the general case. In the case of **SOLVEPNP_P3P** and **SOLVEPNP_AP3P** + methods, it is required to use exactly 4 points (the first 3 points are used to estimate all the solutions + of the P3P problem, the last one is used to retain the best solution that minimizes the reprojection error). + - With **SOLVEPNP_ITERATIVE** method and `useExtrinsicGuess=true`, the minimum number of points is 3 (3 points + are sufficient to compute a pose but there are up to 4 solutions). The initial solution should be close to the + global solution to converge. */ CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, @@ -532,14 +697,15 @@ CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints, /** @brief Finds an object pose from 3D-2D point correspondences using the RANSAC scheme. -@param objectPoints Array of object points in the object coordinate space, 3xN/Nx3 1-channel or +@param objectPoints Array of object points in the object coordinate space, Nx3 1-channel or 1xN/Nx1 3-channel, where N is the number of points. vector\ can be also passed here. -@param imagePoints Array of corresponding image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel, +@param imagePoints Array of corresponding image points, Nx2 1-channel or 1xN/Nx1 2-channel, where N is the number of points. vector\ can be also passed here. @param cameraMatrix Input camera matrix \f$A = \vecthreethree{fx}{0}{cx}{0}{fy}{cy}{0}{0}{1}\f$ . @param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements. If -the vector is NULL/empty, the zero distortion coefficients are assumed. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are +assumed. @param rvec Output rotation vector (see Rodrigues ) that, together with tvec , brings points from the model coordinate system to the camera coordinate system. @param tvec Output translation vector. @@ -563,6 +729,13 @@ makes the function resistant to outliers. @note - An example of how to use solvePNPRansac for object detection can be found at opencv_source_code/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/ + - The default method used to estimate the camera pose for the Minimal Sample Sets step + is #SOLVEPNP_EPNP. Exceptions are: + - if you choose #SOLVEPNP_P3P or #SOLVEPNP_AP3P, these methods will be used. + - if the number of input points is equal to 4, #SOLVEPNP_P3P is used. + - The method used to estimate the camera pose using all the inliers is defined by the + flags parameters unless it is equal to #SOLVEPNP_P3P or #SOLVEPNP_AP3P. In this case, + the method #SOLVEPNP_EPNP will be used instead. */ CV_EXPORTS_W bool solvePnPRansac( InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, @@ -570,6 +743,33 @@ CV_EXPORTS_W bool solvePnPRansac( InputArray objectPoints, InputArray imagePoint bool useExtrinsicGuess = false, int iterationsCount = 100, float reprojectionError = 8.0, double confidence = 0.99, OutputArray inliers = noArray(), int flags = SOLVEPNP_ITERATIVE ); +/** @brief Finds an object pose from 3 3D-2D point correspondences. + +@param objectPoints Array of object points in the object coordinate space, 3x3 1-channel or +1x3/3x1 3-channel. vector\ can be also passed here. +@param imagePoints Array of corresponding image points, 3x2 1-channel or 1x3/3x1 2-channel. + vector\ can be also passed here. +@param cameraMatrix Input camera matrix \f$A = \vecthreethree{fx}{0}{cx}{0}{fy}{cy}{0}{0}{1}\f$ . +@param distCoeffs Input vector of distortion coefficients +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are +assumed. +@param rvecs Output rotation vectors (see Rodrigues ) that, together with tvecs , brings points from +the model coordinate system to the camera coordinate system. A P3P problem has up to 4 solutions. +@param tvecs Output translation vectors. +@param flags Method for solving a P3P problem: +- **SOLVEPNP_P3P** Method is based on the paper of X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang +"Complete Solution Classification for the Perspective-Three-Point Problem" (@cite gao2003complete). +- **SOLVEPNP_AP3P** Method is based on the paper of Tong Ke and Stergios I. Roumeliotis. +"An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (@cite Ke17). + +The function estimates the object pose given 3 object points, their corresponding image +projections, as well as the camera matrix and the distortion coefficients. + */ +CV_EXPORTS_W int solveP3P( InputArray objectPoints, InputArray imagePoints, + InputArray cameraMatrix, InputArray distCoeffs, + OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, + int flags ); /** @brief Finds an initial camera matrix from 3D-2D point correspondences. @@ -597,11 +797,11 @@ CV_EXPORTS_W Mat initCameraMatrix2D( InputArrayOfArrays objectPoints, ( patternSize = cvSize(points_per_row,points_per_colum) = cvSize(columns,rows) ). @param corners Output array of detected corners. @param flags Various operation flags that can be zero or a combination of the following values: -- **CV_CALIB_CB_ADAPTIVE_THRESH** Use adaptive thresholding to convert the image to black +- **CALIB_CB_ADAPTIVE_THRESH** Use adaptive thresholding to convert the image to black and white, rather than a fixed threshold level (computed from the average image brightness). -- **CV_CALIB_CB_NORMALIZE_IMAGE** Normalize the image gamma with equalizeHist before +- **CALIB_CB_NORMALIZE_IMAGE** Normalize the image gamma with equalizeHist before applying fixed or adaptive thresholding. -- **CV_CALIB_CB_FILTER_QUADS** Use additional criteria (like contour area, perimeter, +- **CALIB_CB_FILTER_QUADS** Use additional criteria (like contour area, perimeter, square-like shape) to filter out false quads extracted at the contour retrieval stage. - **CALIB_CB_FAST_CHECK** Run a fast check on the image that looks for chessboard corners, and shortcut the call if none is found. This can drastically speed up the call in the @@ -660,6 +860,58 @@ found, or as colored corners connected with lines if the board was found. CV_EXPORTS_W void drawChessboardCorners( InputOutputArray image, Size patternSize, InputArray corners, bool patternWasFound ); +/** @brief Draw axes of the world/object coordinate system from pose estimation. @sa solvePnP + +@param image Input/output image. It must have 1 or 3 channels. The number of channels is not altered. +@param cameraMatrix Input 3x3 floating-point matrix of camera intrinsic parameters. +\f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ +@param distCoeffs Input vector of distortion coefficients +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. If the vector is empty, the zero distortion coefficients are assumed. +@param rvec Rotation vector (see @ref Rodrigues ) that, together with tvec , brings points from +the model coordinate system to the camera coordinate system. +@param tvec Translation vector. +@param length Length of the painted axes in the same unit than tvec (usually in meters). +@param thickness Line thickness of the painted axes. + +This function draws the axes of the world/object coordinate system w.r.t. to the camera frame. +OX is drawn in red, OY in green and OZ in blue. + */ +CV_EXPORTS_W void drawFrameAxes(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs, + InputArray rvec, InputArray tvec, float length, int thickness=3); + +struct CV_EXPORTS_W_SIMPLE CirclesGridFinderParameters +{ + CV_WRAP CirclesGridFinderParameters(); + CV_PROP_RW cv::Size2f densityNeighborhoodSize; + CV_PROP_RW float minDensity; + CV_PROP_RW int kmeansAttempts; + CV_PROP_RW int minDistanceToAddKeypoint; + CV_PROP_RW int keypointScale; + CV_PROP_RW float minGraphConfidence; + CV_PROP_RW float vertexGain; + CV_PROP_RW float vertexPenalty; + CV_PROP_RW float existingVertexGain; + CV_PROP_RW float edgeGain; + CV_PROP_RW float edgePenalty; + CV_PROP_RW float convexHullFactor; + CV_PROP_RW float minRNGEdgeSwitchDist; + + enum GridType + { + SYMMETRIC_GRID, ASYMMETRIC_GRID + }; + GridType gridType; +}; + +struct CV_EXPORTS_W_SIMPLE CirclesGridFinderParameters2 : public CirclesGridFinderParameters +{ + CV_WRAP CirclesGridFinderParameters2(); + + CV_PROP_RW float squareSize; //!< Distance between two adjacent points. Used by CALIB_CB_CLUSTERING. + CV_PROP_RW float maxRectifiedDistance; //!< Max deviation from predicion. Used by CALIB_CB_CLUSTERING. +}; + /** @brief Finds centers in the grid of circles. @param image grid view of input circles; it must be an 8-bit grayscale or color image. @@ -672,6 +924,7 @@ CV_EXPORTS_W void drawChessboardCorners( InputOutputArray image, Size patternSiz - **CALIB_CB_CLUSTERING** uses a special algorithm for grid detection. It is more robust to perspective distortions but much more sensitive to background clutter. @param blobDetector feature detector that finds blobs like dark circles on light background. +@param parameters struct for finding circles in a grid pattern. The function attempts to determine whether the input image contains a grid of circles. If it is, the function locates centers of the circles. The function returns a non-zero value if all of the centers @@ -691,6 +944,18 @@ Sample usage of detecting and drawing the centers of circles: : @note The function requires white space (like a square-thick border, the wider the better) around the board to make the detection more robust in various environments. */ +CV_EXPORTS_W bool findCirclesGrid( InputArray image, Size patternSize, + OutputArray centers, int flags, + const Ptr &blobDetector, + CirclesGridFinderParameters parameters); + +/** @overload */ +CV_EXPORTS_W bool findCirclesGrid2( InputArray image, Size patternSize, + OutputArray centers, int flags, + const Ptr &blobDetector, + CirclesGridFinderParameters2 parameters); + +/** @overload */ CV_EXPORTS_W bool findCirclesGrid( InputArray image, Size patternSize, OutputArray centers, int flags = CALIB_CB_SYMMETRIC_GRID, const Ptr &blobDetector = SimpleBlobDetector::create()); @@ -715,35 +980,44 @@ together. @param imageSize Size of the image used only to initialize the intrinsic camera matrix. @param cameraMatrix Output 3x3 floating-point camera matrix \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . If CV\_CALIB\_USE\_INTRINSIC\_GUESS -and/or CV_CALIB_FIX_ASPECT_RATIO are specified, some or all of fx, fy, cx, cy must be +and/or CALIB_FIX_ASPECT_RATIO are specified, some or all of fx, fy, cx, cy must be initialized before calling the function. @param distCoeffs Output vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. @param rvecs Output vector of rotation vectors (see Rodrigues ) estimated for each pattern view (e.g. std::vector>). That is, each k-th rotation vector together with the corresponding k-th translation vector (see the next output parameter description) brings the calibration pattern from the model coordinate space (in which object points are specified) to the world coordinate space, that is, a real position of the calibration pattern in the k-th pattern view (k=0.. *M* -1). @param tvecs Output vector of translation vectors estimated for each pattern view. +@param stdDeviationsIntrinsics Output vector of standard deviations estimated for intrinsic parameters. + Order of deviations values: +\f$(f_x, f_y, c_x, c_y, k_1, k_2, p_1, p_2, k_3, k_4, k_5, k_6 , s_1, s_2, s_3, + s_4, \tau_x, \tau_y)\f$ If one of parameters is not estimated, it's deviation is equals to zero. +@param stdDeviationsExtrinsics Output vector of standard deviations estimated for extrinsic parameters. + Order of deviations values: \f$(R_1, T_1, \dotsc , R_M, T_M)\f$ where M is number of pattern views, + \f$R_i, T_i\f$ are concatenated 1x3 vectors. + @param perViewErrors Output vector of the RMS re-projection error estimated for each pattern view. @param flags Different flags that may be zero or a combination of the following values: -- **CV_CALIB_USE_INTRINSIC_GUESS** cameraMatrix contains valid initial values of +- **CALIB_USE_INTRINSIC_GUESS** cameraMatrix contains valid initial values of fx, fy, cx, cy that are optimized further. Otherwise, (cx, cy) is initially set to the image center ( imageSize is used), and focal distances are computed in a least-squares fashion. Note, that if intrinsic parameters are known, there is no need to use this function just to estimate extrinsic parameters. Use solvePnP instead. -- **CV_CALIB_FIX_PRINCIPAL_POINT** The principal point is not changed during the global +- **CALIB_FIX_PRINCIPAL_POINT** The principal point is not changed during the global optimization. It stays at the center or at a different location specified when -CV_CALIB_USE_INTRINSIC_GUESS is set too. -- **CV_CALIB_FIX_ASPECT_RATIO** The functions considers only fy as a free parameter. The +CALIB_USE_INTRINSIC_GUESS is set too. +- **CALIB_FIX_ASPECT_RATIO** The functions considers only fy as a free parameter. The ratio fx/fy stays the same as in the input cameraMatrix . When -CV_CALIB_USE_INTRINSIC_GUESS is not set, the actual input values of fx and fy are +CALIB_USE_INTRINSIC_GUESS is not set, the actual input values of fx and fy are ignored, only their ratio is computed and used further. -- **CV_CALIB_ZERO_TANGENT_DIST** Tangential distortion coefficients \f$(p_1, p_2)\f$ are set +- **CALIB_ZERO_TANGENT_DIST** Tangential distortion coefficients \f$(p_1, p_2)\f$ are set to zeros and stay zero. -- **CV_CALIB_FIX_K1,...,CV_CALIB_FIX_K6** The corresponding radial distortion -coefficient is not changed during the optimization. If CV_CALIB_USE_INTRINSIC_GUESS is +- **CALIB_FIX_K1,...,CALIB_FIX_K6** The corresponding radial distortion +coefficient is not changed during the optimization. If CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the supplied distCoeffs matrix is used. Otherwise, it is set to 0. -- **CV_CALIB_RATIONAL_MODEL** Coefficients k4, k5, and k6 are enabled. To provide the +- **CALIB_RATIONAL_MODEL** Coefficients k4, k5, and k6 are enabled. To provide the backward compatibility, this extra flag should be explicitly specified to make the calibration function use the rational model and return 8 coefficients. If the flag is not set, the function computes and returns only 5 distortion coefficients. @@ -752,17 +1026,26 @@ backward compatibility, this extra flag should be explicitly specified to make t calibration function use the thin prism model and return 12 coefficients. If the flag is not set, the function computes and returns only 5 distortion coefficients. - **CALIB_FIX_S1_S2_S3_S4** The thin prism distortion coefficients are not changed during -the optimization. If CV_CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the +the optimization. If CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the +supplied distCoeffs matrix is used. Otherwise, it is set to 0. +- **CALIB_TILTED_MODEL** Coefficients tauX and tauY are enabled. To provide the +backward compatibility, this extra flag should be explicitly specified to make the +calibration function use the tilted sensor model and return 14 coefficients. If the flag is not +set, the function computes and returns only 5 distortion coefficients. +- **CALIB_FIX_TAUX_TAUY** The coefficients of the tilted sensor model are not changed during +the optimization. If CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the supplied distCoeffs matrix is used. Otherwise, it is set to 0. @param criteria Termination criteria for the iterative optimization algorithm. +@return the overall RMS re-projection error. + The function estimates the intrinsic camera parameters and extrinsic parameters for each of the views. The algorithm is based on @cite Zhang2000 and @cite BouguetMCT . The coordinates of 3D object points and their corresponding 2D projections in each view must be specified. That may be achieved by using an object with a known geometry and easily detectable feature points. Such an object is called a calibration rig or calibration pattern, and OpenCV has built-in support for a chessboard as a calibration rig (see findChessboardCorners ). Currently, initialization of intrinsic parameters -(when CV_CALIB_USE_INTRINSIC_GUESS is not set) is only implemented for planar calibration +(when CALIB_USE_INTRINSIC_GUESS is not set) is only implemented for planar calibration patterns (where Z-coordinates of the object points must be all zeros). 3D calibration rigs can also be used as long as initial cameraMatrix is provided. @@ -770,7 +1053,7 @@ The algorithm performs the following steps: - Compute the initial intrinsic parameters (the option only available for planar calibration patterns) or read them from the input parameters. The distortion coefficients are all set to - zeros initially unless some of CV_CALIB_FIX_K? are specified. + zeros initially unless some of CALIB_FIX_K? are specified. - Estimate the initial camera pose as if the intrinsic parameters have been already known. This is done using solvePnP . @@ -780,8 +1063,6 @@ The algorithm performs the following steps: the projected (using the current estimates for camera parameters and the poses) object points objectPoints. See projectPoints for details. -The function returns the final re-projection error. - @note If you use a non-square (=non-NxN) grid and findChessboardCorners for calibration, and calibrateCamera returns bad values (zero distortion coefficients, an image center very far from @@ -792,6 +1073,24 @@ The function returns the final re-projection error. @sa findChessboardCorners, solvePnP, initCameraMatrix2D, stereoCalibrate, undistort */ +CV_EXPORTS_AS(calibrateCameraExtended) double calibrateCamera( InputArrayOfArrays objectPoints, + InputArrayOfArrays imagePoints, Size imageSize, + InputOutputArray cameraMatrix, InputOutputArray distCoeffs, + OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, + OutputArray stdDeviationsIntrinsics, + OutputArray stdDeviationsExtrinsics, + OutputArray perViewErrors, + int flags = 0, TermCriteria criteria = TermCriteria( + TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) ); + +/** @overload double calibrateCamera( InputArrayOfArrays objectPoints, + InputArrayOfArrays imagePoints, Size imageSize, + InputOutputArray cameraMatrix, InputOutputArray distCoeffs, + OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, + OutputArray stdDeviations, OutputArray perViewErrors, + int flags = 0, TermCriteria criteria = TermCriteria( + TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) ) + */ CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs, @@ -834,12 +1133,12 @@ observed by the first camera. observed by the second camera. @param cameraMatrix1 Input/output first camera matrix: \f$\vecthreethree{f_x^{(j)}}{0}{c_x^{(j)}}{0}{f_y^{(j)}}{c_y^{(j)}}{0}{0}{1}\f$ , \f$j = 0,\, 1\f$ . If -any of CV_CALIB_USE_INTRINSIC_GUESS , CV_CALIB_FIX_ASPECT_RATIO , -CV_CALIB_FIX_INTRINSIC , or CV_CALIB_FIX_FOCAL_LENGTH are specified, some or all of the +any of CALIB_USE_INTRINSIC_GUESS , CALIB_FIX_ASPECT_RATIO , +CALIB_FIX_INTRINSIC , or CALIB_FIX_FOCAL_LENGTH are specified, some or all of the matrix components must be initialized. See the flags description for details. @param distCoeffs1 Input/output vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 ot 12 elements. The -output vector length depends on the flags. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. The output vector length depends on the flags. @param cameraMatrix2 Input/output second camera matrix. The parameter is similar to cameraMatrix1 @param distCoeffs2 Input/output lens distortion coefficients for the second camera. The parameter is similar to distCoeffs1 . @@ -848,22 +1147,25 @@ is similar to distCoeffs1 . @param T Output translation vector between the coordinate systems of the cameras. @param E Output essential matrix. @param F Output fundamental matrix. +@param perViewErrors Output vector of the RMS re-projection error estimated for each pattern view. @param flags Different flags that may be zero or a combination of the following values: -- **CV_CALIB_FIX_INTRINSIC** Fix cameraMatrix? and distCoeffs? so that only R, T, E , and F +- **CALIB_FIX_INTRINSIC** Fix cameraMatrix? and distCoeffs? so that only R, T, E , and F matrices are estimated. -- **CV_CALIB_USE_INTRINSIC_GUESS** Optimize some or all of the intrinsic parameters +- **CALIB_USE_INTRINSIC_GUESS** Optimize some or all of the intrinsic parameters according to the specified flags. Initial values are provided by the user. -- **CV_CALIB_FIX_PRINCIPAL_POINT** Fix the principal points during the optimization. -- **CV_CALIB_FIX_FOCAL_LENGTH** Fix \f$f^{(j)}_x\f$ and \f$f^{(j)}_y\f$ . -- **CV_CALIB_FIX_ASPECT_RATIO** Optimize \f$f^{(j)}_y\f$ . Fix the ratio \f$f^{(j)}_x/f^{(j)}_y\f$ +- **CALIB_USE_EXTRINSIC_GUESS** R, T contain valid initial values that are optimized further. +Otherwise R, T are initialized to the median value of the pattern views (each dimension separately). +- **CALIB_FIX_PRINCIPAL_POINT** Fix the principal points during the optimization. +- **CALIB_FIX_FOCAL_LENGTH** Fix \f$f^{(j)}_x\f$ and \f$f^{(j)}_y\f$ . +- **CALIB_FIX_ASPECT_RATIO** Optimize \f$f^{(j)}_y\f$ . Fix the ratio \f$f^{(j)}_x/f^{(j)}_y\f$ . -- **CV_CALIB_SAME_FOCAL_LENGTH** Enforce \f$f^{(0)}_x=f^{(1)}_x\f$ and \f$f^{(0)}_y=f^{(1)}_y\f$ . -- **CV_CALIB_ZERO_TANGENT_DIST** Set tangential distortion coefficients for each camera to +- **CALIB_SAME_FOCAL_LENGTH** Enforce \f$f^{(0)}_x=f^{(1)}_x\f$ and \f$f^{(0)}_y=f^{(1)}_y\f$ . +- **CALIB_ZERO_TANGENT_DIST** Set tangential distortion coefficients for each camera to zeros and fix there. -- **CV_CALIB_FIX_K1,...,CV_CALIB_FIX_K6** Do not change the corresponding radial -distortion coefficient during the optimization. If CV_CALIB_USE_INTRINSIC_GUESS is set, +- **CALIB_FIX_K1,...,CALIB_FIX_K6** Do not change the corresponding radial +distortion coefficient during the optimization. If CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the supplied distCoeffs matrix is used. Otherwise, it is set to 0. -- **CV_CALIB_RATIONAL_MODEL** Enable coefficients k4, k5, and k6. To provide the backward +- **CALIB_RATIONAL_MODEL** Enable coefficients k4, k5, and k6. To provide the backward compatibility, this extra flag should be explicitly specified to make the calibration function use the rational model and return 8 coefficients. If the flag is not set, the function computes and returns only 5 distortion coefficients. @@ -872,7 +1174,14 @@ backward compatibility, this extra flag should be explicitly specified to make t calibration function use the thin prism model and return 12 coefficients. If the flag is not set, the function computes and returns only 5 distortion coefficients. - **CALIB_FIX_S1_S2_S3_S4** The thin prism distortion coefficients are not changed during -the optimization. If CV_CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the +the optimization. If CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the +supplied distCoeffs matrix is used. Otherwise, it is set to 0. +- **CALIB_TILTED_MODEL** Coefficients tauX and tauY are enabled. To provide the +backward compatibility, this extra flag should be explicitly specified to make the +calibration function use the tilted sensor model and return 14 coefficients. If the flag is not +set, the function computes and returns only 5 distortion coefficients. +- **CALIB_FIX_TAUX_TAUY** The coefficients of the tilted sensor model are not changed during +the optimization. If CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the supplied distCoeffs matrix is used. Otherwise, it is set to 0. @param criteria Termination criteria for the iterative optimization algorithm. @@ -884,8 +1193,8 @@ This means that, given ( \f$R_1\f$,\f$T_1\f$ ), it should be possible to compute need to know the position and orientation of the second camera relative to the first camera. This is what the described function does. It computes ( \f$R\f$,\f$T\f$ ) so that: -\f[R_2=R*R_1 -T_2=R*T_1 + T,\f] +\f[R_2=R*R_1\f] +\f[T_2=R*T_1 + T,\f] Optionally, it computes the essential matrix E: @@ -900,16 +1209,25 @@ Besides the stereo-related information, the function can also perform a full cal two cameras. However, due to the high dimensionality of the parameter space and noise in the input data, the function can diverge from the correct solution. If the intrinsic parameters can be estimated with high accuracy for each of the cameras individually (for example, using -calibrateCamera ), you are recommended to do so and then pass CV_CALIB_FIX_INTRINSIC flag to the +calibrateCamera ), you are recommended to do so and then pass CALIB_FIX_INTRINSIC flag to the function along with the computed intrinsic parameters. Otherwise, if all the parameters are estimated at once, it makes sense to restrict some parameters, for example, pass -CV_CALIB_SAME_FOCAL_LENGTH and CV_CALIB_ZERO_TANGENT_DIST flags, which is usually a +CALIB_SAME_FOCAL_LENGTH and CALIB_ZERO_TANGENT_DIST flags, which is usually a reasonable assumption. Similarly to calibrateCamera , the function minimizes the total re-projection error for all the points in all the available views from both cameras. The function returns the final value of the re-projection error. */ +CV_EXPORTS_AS(stereoCalibrateExtended) double stereoCalibrate( InputArrayOfArrays objectPoints, + InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, + InputOutputArray cameraMatrix1, InputOutputArray distCoeffs1, + InputOutputArray cameraMatrix2, InputOutputArray distCoeffs2, + Size imageSize, InputOutputArray R,InputOutputArray T, OutputArray E, OutputArray F, + OutputArray perViewErrors, int flags = CALIB_FIX_INTRINSIC, + TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6) ); + +/// @overload CV_EXPORTS_W double stereoCalibrate( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, InputOutputArray cameraMatrix1, InputOutputArray distCoeffs1, @@ -918,12 +1236,11 @@ CV_EXPORTS_W double stereoCalibrate( InputArrayOfArrays objectPoints, int flags = CALIB_FIX_INTRINSIC, TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6) ); - /** @brief Computes rectification transforms for each head of a calibrated stereo camera. @param cameraMatrix1 First camera matrix. -@param cameraMatrix2 Second camera matrix. @param distCoeffs1 First camera distortion parameters. +@param cameraMatrix2 Second camera matrix. @param distCoeffs2 Second camera distortion parameters. @param imageSize Size of the image used for stereo calibration. @param R Rotation matrix between the coordinate systems of the first and the second cameras. @@ -935,7 +1252,7 @@ camera. @param P2 Output 3x4 projection matrix in the new (rectified) coordinate systems for the second camera. @param Q Output \f$4 \times 4\f$ disparity-to-depth mapping matrix (see reprojectImageTo3D ). -@param flags Operation flags that may be zero or CV_CALIB_ZERO_DISPARITY . If the flag is set, +@param flags Operation flags that may be zero or CALIB_ZERO_DISPARITY . If the flag is set, the function makes the principal points of each camera have the same pixel coordinates in the rectified views. And if the flag is not set, the function may still shift the images in the horizontal or vertical direction (depending on the orientation of epipolar lines) to maximize the @@ -974,7 +1291,7 @@ coordinates. The function distinguishes the following two cases: \f[\texttt{P2} = \begin{bmatrix} f & 0 & cx_2 & T_x*f \\ 0 & f & cy & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} ,\f] where \f$T_x\f$ is a horizontal shift between the cameras and \f$cx_1=cx_2\f$ if - CV_CALIB_ZERO_DISPARITY is set. + CALIB_ZERO_DISPARITY is set. - **Vertical stereo**: the first and the second camera views are shifted relative to each other mainly in vertical direction (and probably a bit in the horizontal direction too). The epipolar @@ -1020,7 +1337,7 @@ findFundamentalMat . @param threshold Optional threshold used to filter out the outliers. If the parameter is greater than zero, all the point pairs that do not comply with the epipolar geometry (that is, the points for which \f$|\texttt{points2[i]}^T*\texttt{F}*\texttt{points1[i]}|>\texttt{threshold}\f$ ) are -rejected prior to computing the homographies. Otherwise,all the points are considered inliers. +rejected prior to computing the homographies. Otherwise, all the points are considered inliers. The function computes the rectification transformations without knowing intrinsic parameters of the cameras and their relative position in the space, which explains the suffix "uncalibrated". Another @@ -1057,13 +1374,14 @@ CV_EXPORTS_W float rectify3Collinear( InputArray cameraMatrix1, InputArray distC @param cameraMatrix Input camera matrix. @param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements. If -the vector is NULL/empty, the zero distortion coefficients are assumed. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ of +4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are +assumed. @param imageSize Original image size. @param alpha Free scaling parameter between 0 (when all the pixels in the undistorted image are valid) and 1 (when all the source image pixels are retained in the undistorted image). See stereoRectify for details. -@param newImgSize Image size after rectification. By default,it is set to imageSize . +@param newImgSize Image size after rectification. By default, it is set to imageSize . @param validPixROI Optional output rectangle that outlines all-good-pixels region in the undistorted image. See roi1, roi2 description in stereoRectify . @param centerPrincipalPoint Optional flag that indicates whether in the new camera matrix the @@ -1074,7 +1392,7 @@ best fit a subset of the source image (determined by alpha) to the corrected ima The function computes and returns the optimal new camera matrix based on the free scaling parameter. By varying this parameter, you may retrieve only sensible pixels alpha=0 , keep all the original image pixels if there is valuable information in the corners alpha=1 , or get something in between. -When alpha\>0 , the undistortion result is likely to have some black pixels corresponding to +When alpha\>0 , the undistorted result is likely to have some black pixels corresponding to "virtual" pixels outside of the captured distorted image. The original camera matrix, distortion coefficients, the computed new camera matrix, and newImageSize should be passed to initUndistortRectifyMap to produce the maps for remap . @@ -1127,11 +1445,11 @@ floating-point (single or double precision). - **CV_FM_8POINT** for an 8-point algorithm. \f$N \ge 8\f$ - **CV_FM_RANSAC** for the RANSAC algorithm. \f$N \ge 8\f$ - **CV_FM_LMEDS** for the LMedS algorithm. \f$N \ge 8\f$ -@param param1 Parameter used for RANSAC. It is the maximum distance from a point to an epipolar +@param ransacReprojThreshold Parameter used only for RANSAC. It is the maximum distance from a point to an epipolar line in pixels, beyond which the point is considered an outlier and is not used for computing the final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the point localization, image resolution, and the image noise. -@param param2 Parameter used for the RANSAC or LMedS methods only. It specifies a desirable level +@param confidence Parameter used for the RANSAC and LMedS methods only. It specifies a desirable level of confidence (probability) that the estimated matrix is correct. @param mask @@ -1169,25 +1487,58 @@ stereoRectifyUncalibrated to compute the rectification transformation. : */ CV_EXPORTS_W Mat findFundamentalMat( InputArray points1, InputArray points2, int method = FM_RANSAC, - double param1 = 3., double param2 = 0.99, + double ransacReprojThreshold = 3., double confidence = 0.99, OutputArray mask = noArray() ); /** @overload */ CV_EXPORTS Mat findFundamentalMat( InputArray points1, InputArray points2, OutputArray mask, int method = FM_RANSAC, - double param1 = 3., double param2 = 0.99 ); + double ransacReprojThreshold = 3., double confidence = 0.99 ); /** @brief Calculates an essential matrix from the corresponding points in two images. +@param points1 Array of N (N \>= 5) 2D points from the first image. The point coordinates should +be floating-point (single or double precision). +@param points2 Array of the second image points of the same size and format as points1 . +@param cameraMatrix Camera matrix \f$K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . +Note that this function assumes that points1 and points2 are feature points from cameras with the +same camera matrix. +@param method Method for computing an essential matrix. +- **RANSAC** for the RANSAC algorithm. +- **LMEDS** for the LMedS algorithm. +@param prob Parameter used for the RANSAC or LMedS methods only. It specifies a desirable level of +confidence (probability) that the estimated matrix is correct. +@param threshold Parameter used for RANSAC. It is the maximum distance from a point to an epipolar +line in pixels, beyond which the point is considered an outlier and is not used for computing the +final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the +point localization, image resolution, and the image noise. +@param mask Output array of N elements, every element of which is set to 0 for outliers and to 1 +for the other points. The array is computed only in the RANSAC and LMedS methods. + +This function estimates essential matrix based on the five-point algorithm solver in @cite Nister03 . +@cite SteweniusCFS is also a related. The epipolar geometry is described by the following equation: + +\f[[p_2; 1]^T K^{-T} E K^{-1} [p_1; 1] = 0\f] + +where \f$E\f$ is an essential matrix, \f$p_1\f$ and \f$p_2\f$ are corresponding points in the first and the +second images, respectively. The result of this function may be passed further to +decomposeEssentialMat or recoverPose to recover the relative pose between cameras. + */ +CV_EXPORTS_W Mat findEssentialMat( InputArray points1, InputArray points2, + InputArray cameraMatrix, int method = RANSAC, + double prob = 0.999, double threshold = 1.0, + OutputArray mask = noArray() ); + +/** @overload @param points1 Array of N (N \>= 5) 2D points from the first image. The point coordinates should be floating-point (single or double precision). @param points2 Array of the second image points of the same size and format as points1 . @param focal focal length of the camera. Note that this function assumes that points1 and points2 -are feature points from cameras with same focal length and principle point. -@param pp principle point of the camera. +are feature points from cameras with same focal length and principal point. +@param pp principal point of the camera. @param method Method for computing a fundamental matrix. - **RANSAC** for the RANSAC algorithm. -- **MEDS** for the LMedS algorithm. +- **LMEDS** for the LMedS algorithm. @param threshold Parameter used for RANSAC. It is the maximum distance from a point to an epipolar line in pixels, beyond which the point is considered an outlier and is not used for computing the final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the @@ -1197,19 +1548,15 @@ confidence (probability) that the estimated matrix is correct. @param mask Output array of N elements, every element of which is set to 0 for outliers and to 1 for the other points. The array is computed only in the RANSAC and LMedS methods. -This function estimates essential matrix based on the five-point algorithm solver in @cite Nister03 . -@cite SteweniusCFS is also a related. The epipolar geometry is described by the following equation: +This function differs from the one above that it computes camera matrix from focal length and +principal point: -\f[[p_2; 1]^T K^{-T} E K^{-1} [p_1; 1] = 0 \\\f]\f[K = +\f[K = \begin{bmatrix} f & 0 & x_{pp} \\ 0 & f & y_{pp} \\ 0 & 0 & 1 \end{bmatrix}\f] - -where \f$E\f$ is an essential matrix, \f$p_1\f$ and \f$p_2\f$ are corresponding points in the first and the -second images, respectively. The result of this function may be passed further to -decomposeEssentialMat or recoverPose to recover the relative pose between cameras. */ CV_EXPORTS_W Mat findEssentialMat( InputArray points1, InputArray points2, double focal = 1.0, Point2d pp = Point2d(0, 0), @@ -1237,11 +1584,11 @@ the check. @param points1 Array of N 2D points from the first image. The point coordinates should be floating-point (single or double precision). @param points2 Array of the second image points of the same size and format as points1 . +@param cameraMatrix Camera matrix \f$K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . +Note that this function assumes that points1 and points2 are feature points from cameras with the +same camera matrix. @param R Recovered relative rotation. -@param t Recoverd relative translation. -@param focal Focal length of the camera. Note that this function assumes that points1 and points2 -are feature points from cameras with same focal length and principle point. -@param pp Principle point of the camera. +@param t Recovered relative translation. @param mask Input/output mask for inliers in points1 and points2. : If it is not empty, then it marks inliers in points1 and points2 for then given essential matrix E. Only these inliers will be used to recover pose. In the output mask only inliers @@ -1265,19 +1612,70 @@ points1 and points2 are the same input for findEssentialMat. : points2[i] = ...; } - double focal = 1.0; - cv::Point2d pp(0.0, 0.0); + // cametra matrix with both focal lengths = 1, and principal point = (0, 0) + Mat cameraMatrix = Mat::eye(3, 3, CV_64F); + Mat E, R, t, mask; - E = findEssentialMat(points1, points2, focal, pp, RANSAC, 0.999, 1.0, mask); - recoverPose(E, points1, points2, R, t, focal, pp, mask); + E = findEssentialMat(points1, points2, cameraMatrix, RANSAC, 0.999, 1.0, mask); + recoverPose(E, points1, points2, cameraMatrix, R, t, mask); @endcode */ +CV_EXPORTS_W int recoverPose( InputArray E, InputArray points1, InputArray points2, + InputArray cameraMatrix, OutputArray R, OutputArray t, + InputOutputArray mask = noArray() ); + +/** @overload +@param E The input essential matrix. +@param points1 Array of N 2D points from the first image. The point coordinates should be +floating-point (single or double precision). +@param points2 Array of the second image points of the same size and format as points1 . +@param R Recovered relative rotation. +@param t Recovered relative translation. +@param focal Focal length of the camera. Note that this function assumes that points1 and points2 +are feature points from cameras with same focal length and principal point. +@param pp principal point of the camera. +@param mask Input/output mask for inliers in points1 and points2. +: If it is not empty, then it marks inliers in points1 and points2 for then given essential +matrix E. Only these inliers will be used to recover pose. In the output mask only inliers +which pass the cheirality check. + +This function differs from the one above that it computes camera matrix from focal length and +principal point: + +\f[K = +\begin{bmatrix} +f & 0 & x_{pp} \\ +0 & f & y_{pp} \\ +0 & 0 & 1 +\end{bmatrix}\f] + */ CV_EXPORTS_W int recoverPose( InputArray E, InputArray points1, InputArray points2, OutputArray R, OutputArray t, double focal = 1.0, Point2d pp = Point2d(0, 0), InputOutputArray mask = noArray() ); +/** @overload +@param E The input essential matrix. +@param points1 Array of N 2D points from the first image. The point coordinates should be +floating-point (single or double precision). +@param points2 Array of the second image points of the same size and format as points1. +@param cameraMatrix Camera matrix \f$K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . +Note that this function assumes that points1 and points2 are feature points from cameras with the +same camera matrix. +@param R Recovered relative rotation. +@param t Recovered relative translation. +@param distanceThresh threshold distance which is used to filter out far away points (i.e. infinite points). +@param mask Input/output mask for inliers in points1 and points2. +: If it is not empty, then it marks inliers in points1 and points2 for then given essential +matrix E. Only these inliers will be used to recover pose. In the output mask only inliers +which pass the cheirality check. +@param triangulatedPoints 3d points which were reconstructed by triangulation. + */ + +CV_EXPORTS_W int recoverPose( InputArray E, InputArray points1, InputArray points2, + InputArray cameraMatrix, OutputArray R, OutputArray t, double distanceThresh, InputOutputArray mask = noArray(), + OutputArray triangulatedPoints = noArray()); /** @brief For points in an image of a stereo pair, computes the corresponding epilines in the other image. @@ -1375,7 +1773,8 @@ CV_EXPORTS_W void validateDisparity( InputOutputArray disparity, InputArray cost /** @brief Reprojects a disparity image to 3D space. @param disparity Input single-channel 8-bit unsigned, 16-bit signed, 32-bit signed or 32-bit -floating-point disparity image. +floating-point disparity image. If 16-bit signed format is used, the values are assumed to have no +fractional bits. @param _3dImage Output 3-channel floating-point image of the same size as disparity . Each element of _3dImage(x,y) contains 3D coordinates of the point (x,y) computed from the disparity map. @@ -1388,7 +1787,7 @@ to 3D points with a very large Z value (currently set to 10000). depth. ddepth can also be set to CV_16S, CV_32S or CV_32F. The function transforms a single-channel disparity map to a 3-channel image representing a 3D -surface. That is, for each pixel (x,y) andthe corresponding disparity d=disparity(x,y) , it +surface. That is, for each pixel (x,y) and the corresponding disparity d=disparity(x,y) , it computes: \f[\begin{array}{l} [X \; Y \; Z \; W]^T = \texttt{Q} *[x \; y \; \texttt{disparity} (x,y) \; 1]^T \\ \texttt{\_3dImage} (x,y) = (X/W, \; Y/W, \; Z/W) \end{array}\f] @@ -1402,12 +1801,64 @@ CV_EXPORTS_W void reprojectImageTo3D( InputArray disparity, bool handleMissingValues = false, int ddepth = -1 ); +/** @brief Calculates the Sampson Distance between two points. + +The function cv::sampsonDistance calculates and returns the first order approximation of the geometric error as: +\f[ +sd( \texttt{pt1} , \texttt{pt2} )= +\frac{(\texttt{pt2}^t \cdot \texttt{F} \cdot \texttt{pt1})^2} +{((\texttt{F} \cdot \texttt{pt1})(0))^2 + +((\texttt{F} \cdot \texttt{pt1})(1))^2 + +((\texttt{F}^t \cdot \texttt{pt2})(0))^2 + +((\texttt{F}^t \cdot \texttt{pt2})(1))^2} +\f] +The fundamental matrix may be calculated using the cv::findFundamentalMat function. See @cite HartleyZ00 11.4.3 for details. +@param pt1 first homogeneous 2d point +@param pt2 second homogeneous 2d point +@param F fundamental matrix +@return The computed Sampson distance. +*/ +CV_EXPORTS_W double sampsonDistance(InputArray pt1, InputArray pt2, InputArray F); + /** @brief Computes an optimal affine transformation between two 3D point sets. -@param src First input 3D point set. -@param dst Second input 3D point set. -@param out Output 3D affine transformation matrix \f$3 \times 4\f$ . -@param inliers Output vector indicating which points are inliers. +It computes +\f[ +\begin{bmatrix} +x\\ +y\\ +z\\ +\end{bmatrix} += +\begin{bmatrix} +a_{11} & a_{12} & a_{13}\\ +a_{21} & a_{22} & a_{23}\\ +a_{31} & a_{32} & a_{33}\\ +\end{bmatrix} +\begin{bmatrix} +X\\ +Y\\ +Z\\ +\end{bmatrix} ++ +\begin{bmatrix} +b_1\\ +b_2\\ +b_3\\ +\end{bmatrix} +\f] + +@param src First input 3D point set containing \f$(X,Y,Z)\f$. +@param dst Second input 3D point set containing \f$(x,y,z)\f$. +@param out Output 3D affine transformation matrix \f$3 \times 4\f$ of the form +\f[ +\begin{bmatrix} +a_{11} & a_{12} & a_{13} & b_1\\ +a_{21} & a_{22} & a_{23} & b_2\\ +a_{31} & a_{32} & a_{33} & b_3\\ +\end{bmatrix} +\f] +@param inliers Output vector indicating which points are inliers (1-inlier, 0-outlier). @param ransacThreshold Maximum reprojection error in the RANSAC algorithm to consider a point as an inlier. @param confidence Confidence level, between 0 and 1, for the estimated transformation. Anything @@ -1421,6 +1872,127 @@ CV_EXPORTS_W int estimateAffine3D(InputArray src, InputArray dst, OutputArray out, OutputArray inliers, double ransacThreshold = 3, double confidence = 0.99); +/** @brief Computes an optimal affine transformation between two 2D point sets. + +It computes +\f[ +\begin{bmatrix} +x\\ +y\\ +\end{bmatrix} += +\begin{bmatrix} +a_{11} & a_{12}\\ +a_{21} & a_{22}\\ +\end{bmatrix} +\begin{bmatrix} +X\\ +Y\\ +\end{bmatrix} ++ +\begin{bmatrix} +b_1\\ +b_2\\ +\end{bmatrix} +\f] + +@param from First input 2D point set containing \f$(X,Y)\f$. +@param to Second input 2D point set containing \f$(x,y)\f$. +@param inliers Output vector indicating which points are inliers (1-inlier, 0-outlier). +@param method Robust method used to compute transformation. The following methods are possible: +- cv::RANSAC - RANSAC-based robust method +- cv::LMEDS - Least-Median robust method +RANSAC is the default method. +@param ransacReprojThreshold Maximum reprojection error in the RANSAC algorithm to consider +a point as an inlier. Applies only to RANSAC. +@param maxIters The maximum number of robust method iterations. +@param confidence Confidence level, between 0 and 1, for the estimated transformation. Anything +between 0.95 and 0.99 is usually good enough. Values too close to 1 can slow down the estimation +significantly. Values lower than 0.8-0.9 can result in an incorrectly estimated transformation. +@param refineIters Maximum number of iterations of refining algorithm (Levenberg-Marquardt). +Passing 0 will disable refining, so the output matrix will be output of robust method. + +@return Output 2D affine transformation matrix \f$2 \times 3\f$ or empty matrix if transformation +could not be estimated. The returned matrix has the following form: +\f[ +\begin{bmatrix} +a_{11} & a_{12} & b_1\\ +a_{21} & a_{22} & b_2\\ +\end{bmatrix} +\f] + +The function estimates an optimal 2D affine transformation between two 2D point sets using the +selected robust algorithm. + +The computed transformation is then refined further (using only inliers) with the +Levenberg-Marquardt method to reduce the re-projection error even more. + +@note +The RANSAC method can handle practically any ratio of outliers but needs a threshold to +distinguish inliers from outliers. The method LMeDS does not need any threshold but it works +correctly only when there are more than 50% of inliers. + +@sa estimateAffinePartial2D, getAffineTransform +*/ +CV_EXPORTS_W cv::Mat estimateAffine2D(InputArray from, InputArray to, OutputArray inliers = noArray(), + int method = RANSAC, double ransacReprojThreshold = 3, + size_t maxIters = 2000, double confidence = 0.99, + size_t refineIters = 10); + +/** @brief Computes an optimal limited affine transformation with 4 degrees of freedom between +two 2D point sets. + +@param from First input 2D point set. +@param to Second input 2D point set. +@param inliers Output vector indicating which points are inliers. +@param method Robust method used to compute transformation. The following methods are possible: +- cv::RANSAC - RANSAC-based robust method +- cv::LMEDS - Least-Median robust method +RANSAC is the default method. +@param ransacReprojThreshold Maximum reprojection error in the RANSAC algorithm to consider +a point as an inlier. Applies only to RANSAC. +@param maxIters The maximum number of robust method iterations. +@param confidence Confidence level, between 0 and 1, for the estimated transformation. Anything +between 0.95 and 0.99 is usually good enough. Values too close to 1 can slow down the estimation +significantly. Values lower than 0.8-0.9 can result in an incorrectly estimated transformation. +@param refineIters Maximum number of iterations of refining algorithm (Levenberg-Marquardt). +Passing 0 will disable refining, so the output matrix will be output of robust method. + +@return Output 2D affine transformation (4 degrees of freedom) matrix \f$2 \times 3\f$ or +empty matrix if transformation could not be estimated. + +The function estimates an optimal 2D affine transformation with 4 degrees of freedom limited to +combinations of translation, rotation, and uniform scaling. Uses the selected algorithm for robust +estimation. + +The computed transformation is then refined further (using only inliers) with the +Levenberg-Marquardt method to reduce the re-projection error even more. + +Estimated transformation matrix is: +\f[ \begin{bmatrix} \cos(\theta) \cdot s & -\sin(\theta) \cdot s & t_x \\ + \sin(\theta) \cdot s & \cos(\theta) \cdot s & t_y +\end{bmatrix} \f] +Where \f$ \theta \f$ is the rotation angle, \f$ s \f$ the scaling factor and \f$ t_x, t_y \f$ are +translations in \f$ x, y \f$ axes respectively. + +@note +The RANSAC method can handle practically any ratio of outliers but need a threshold to +distinguish inliers from outliers. The method LMeDS does not need any threshold but it works +correctly only when there are more than 50% of inliers. + +@sa estimateAffine2D, getAffineTransform +*/ +CV_EXPORTS_W cv::Mat estimateAffinePartial2D(InputArray from, InputArray to, OutputArray inliers = noArray(), + int method = RANSAC, double ransacReprojThreshold = 3, + size_t maxIters = 2000, double confidence = 0.99, + size_t refineIters = 10); + +/** @example samples/cpp/tutorial_code/features2D/Homography/decompose_homography.cpp +An example program with homography decomposition. + +Check @ref tutorial_homography "the corresponding tutorial" for more details. +*/ + /** @brief Decompose a homography matrix to rotation(s), translation(s) and plane normal(s). @param H The input homography matrix between two images. @@ -1441,6 +2013,31 @@ CV_EXPORTS_W int decomposeHomographyMat(InputArray H, OutputArrayOfArrays translations, OutputArrayOfArrays normals); +/** @brief Filters homography decompositions based on additional information. + +@param rotations Vector of rotation matrices. +@param normals Vector of plane normal matrices. +@param beforePoints Vector of (rectified) visible reference points before the homography is applied +@param afterPoints Vector of (rectified) visible reference points after the homography is applied +@param possibleSolutions Vector of int indices representing the viable solution set after filtering +@param pointsMask optional Mat/Vector of 8u type representing the mask for the inliers as given by the findHomography function + +This function is intended to filter the output of the decomposeHomographyMat based on additional +information as described in @cite Malis . The summary of the method: the decomposeHomographyMat function +returns 2 unique solutions and their "opposites" for a total of 4 solutions. If we have access to the +sets of points visible in the camera frame before and after the homography transformation is applied, +we can determine which are the true potential solutions and which are the opposites by verifying which +homographies are consistent with all visible reference points being in front of the camera. The inputs +are left unchanged; the filtered solution set is returned as indices into the existing one. + +*/ +CV_EXPORTS_W void filterHomographyDecompByVisibleRefpoints(InputArrayOfArrays rotations, + InputArrayOfArrays normals, + InputArray beforePoints, + InputArray afterPoints, + OutputArray possibleSolutions, + InputArray pointsMask = noArray()); + /** @brief The base class for stereo correspondence algorithms. */ class CV_EXPORTS_W StereoMatcher : public Algorithm @@ -1547,7 +2144,7 @@ check, quadratic interpolation and speckle filtering). @note - (Python) An example illustrating the use of the StereoSGBM matching algorithm can be found - at opencv_source_code/samples/python2/stereo_match.py + at opencv_source_code/samples/python/stereo_match.py */ class CV_EXPORTS_W StereoSGBM : public StereoMatcher { @@ -1555,7 +2152,9 @@ public: enum { MODE_SGBM = 0, - MODE_HH = 1 + MODE_HH = 1, + MODE_SGBM_3WAY = 2, + MODE_HH4 = 3 }; CV_WRAP virtual int getPreFilterCap() const = 0; @@ -1610,7 +2209,7 @@ public: set StereoSGBM::numDisparities at minimum. The second constructor enables you to set each parameter to a custom value. */ - CV_WRAP static Ptr create(int minDisparity, int numDisparities, int blockSize, + CV_WRAP static Ptr create(int minDisparity = 0, int numDisparities = 16, int blockSize = 3, int P1 = 0, int P2 = 0, int disp12MaxDiff = 0, int preFilterCap = 0, int uniquenessRatio = 0, int speckleWindowSize = 0, int speckleRange = 0, @@ -1628,15 +2227,16 @@ namespace fisheye //! @{ enum{ - CALIB_USE_INTRINSIC_GUESS = 1, - CALIB_RECOMPUTE_EXTRINSIC = 2, - CALIB_CHECK_COND = 4, - CALIB_FIX_SKEW = 8, - CALIB_FIX_K1 = 16, - CALIB_FIX_K2 = 32, - CALIB_FIX_K3 = 64, - CALIB_FIX_K4 = 128, - CALIB_FIX_INTRINSIC = 256 + CALIB_USE_INTRINSIC_GUESS = 1 << 0, + CALIB_RECOMPUTE_EXTRINSIC = 1 << 1, + CALIB_CHECK_COND = 1 << 2, + CALIB_FIX_SKEW = 1 << 3, + CALIB_FIX_K1 = 1 << 4, + CALIB_FIX_K2 = 1 << 5, + CALIB_FIX_K3 = 1 << 6, + CALIB_FIX_K4 = 1 << 7, + CALIB_FIX_INTRINSIC = 1 << 8, + CALIB_FIX_PRINCIPAL_POINT = 1 << 9 }; /** @brief Projects points using fisheye model @@ -1674,6 +2274,10 @@ namespace fisheye @param D Input vector of distortion coefficients \f$(k_1, k_2, k_3, k_4)\f$. @param alpha The skew coefficient. @param distorted Output array of image points, 1xN/Nx1 2-channel, or vector\ . + + Note that the function assumes the camera matrix of the undistorted points to be identity. + This means if you want to transform back points undistorted with undistortPoints() you have to + multiply them with \f$P^{-1}\f$. */ CV_EXPORTS_W void distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha = 0); @@ -1782,8 +2386,10 @@ namespace fisheye of intrinsic optimization. - **fisheye::CALIB_CHECK_COND** The functions will check validity of condition number. - **fisheye::CALIB_FIX_SKEW** Skew coefficient (alpha) is set to zero and stay zero. - - **fisheye::CALIB_FIX_K1..4** Selected distortion coefficients are set to zeros and stay - zero. + - **fisheye::CALIB_FIX_K1..fisheye::CALIB_FIX_K4** Selected distortion coefficients + are set to zeros and stay zero. + - **fisheye::CALIB_FIX_PRINCIPAL_POINT** The principal point is not changed during the global +optimization. It stays at the center or at a different location specified when CALIB_USE_INTRINSIC_GUESS is set too. @param criteria Termination criteria for the iterative optimization algorithm. */ CV_EXPORTS_W double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size, @@ -1807,7 +2413,7 @@ namespace fisheye @param P2 Output 3x4 projection matrix in the new (rectified) coordinate systems for the second camera. @param Q Output \f$4 \times 4\f$ disparity-to-depth mapping matrix (see reprojectImageTo3D ). - @param flags Operation flags that may be zero or CV_CALIB_ZERO_DISPARITY . If the flag is set, + @param flags Operation flags that may be zero or CALIB_ZERO_DISPARITY . If the flag is set, the function makes the principal points of each camera have the same pixel coordinates in the rectified views. And if the flag is not set, the function may still shift the images in the horizontal or vertical direction (depending on the orientation of epipolar lines) to maximize the @@ -1833,7 +2439,7 @@ namespace fisheye observed by the second camera. @param K1 Input/output first camera matrix: \f$\vecthreethree{f_x^{(j)}}{0}{c_x^{(j)}}{0}{f_y^{(j)}}{c_y^{(j)}}{0}{0}{1}\f$ , \f$j = 0,\, 1\f$ . If - any of fisheye::CALIB_USE_INTRINSIC_GUESS , fisheye::CV_CALIB_FIX_INTRINSIC are specified, + any of fisheye::CALIB_USE_INTRINSIC_GUESS , fisheye::CALIB_FIX_INTRINSIC are specified, some or all of the matrix components must be initialized. @param D1 Input/output vector of distortion coefficients \f$(k_1, k_2, k_3, k_4)\f$ of 4 elements. @param K2 Input/output second camera matrix. The parameter is similar to K1 . @@ -1843,7 +2449,7 @@ namespace fisheye @param R Output rotation matrix between the 1st and the 2nd camera coordinate systems. @param T Output translation vector between the coordinate systems of the cameras. @param flags Different flags that may be zero or a combination of the following values: - - **fisheye::CV_CALIB_FIX_INTRINSIC** Fix K1, K2? and D1, D2? so that only R, T matrices + - **fisheye::CALIB_FIX_INTRINSIC** Fix K1, K2? and D1, D2? so that only R, T matrices are estimated. - **fisheye::CALIB_USE_INTRINSIC_GUESS** K1, K2 contains valid initial values of fx, fy, cx, cy that are optimized further. Otherwise, (cx, cy) is initially set to the image @@ -1862,9 +2468,9 @@ namespace fisheye TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON)); //! @} calib3d_fisheye -} +} // end namespace fisheye -} // cv +} //end namespace cv #ifndef DISABLE_OPENCV_24_COMPATIBILITY #include "opencv2/calib3d/calib3d_c.h" diff --git a/include/opencv2/calib3d/calib3d_c.h b/include/opencv2/calib3d/calib3d_c.h index 2392692..8ec6390 100644 --- a/include/opencv2/calib3d/calib3d_c.h +++ b/include/opencv2/calib3d/calib3d_c.h @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CALIB3D_C_H__ -#define __OPENCV_CALIB3D_C_H__ +#ifndef OPENCV_CALIB3D_C_H +#define OPENCV_CALIB3D_C_H #include "opencv2/core/core_c.h" @@ -243,7 +243,11 @@ CVAPI(void) cvDrawChessboardCorners( CvArr* image, CvSize pattern_size, #define CV_CALIB_RATIONAL_MODEL 16384 #define CV_CALIB_THIN_PRISM_MODEL 32768 #define CV_CALIB_FIX_S1_S2_S3_S4 65536 +#define CV_CALIB_TILTED_MODEL 262144 +#define CV_CALIB_FIX_TAUX_TAUY 524288 +#define CV_CALIB_FIX_TANGENT_DIST 2097152 +#define CV_CALIB_NINTRINSIC 18 /* Finds intrinsic and extrinsic camera parameters from a few views of known calibration pattern */ @@ -415,8 +419,9 @@ public: int state; int iters; bool completeSymmFlag; + int solveMethod; }; #endif -#endif /* __OPENCV_CALIB3D_C_H__ */ +#endif /* OPENCV_CALIB3D_C_H */ diff --git a/include/opencv2/core.hpp b/include/opencv2/core.hpp index 6594476..089c0db 100644 --- a/include/opencv2/core.hpp +++ b/include/opencv2/core.hpp @@ -42,8 +42,8 @@ // //M*/ -#ifndef __OPENCV_CORE_HPP__ -#define __OPENCV_CORE_HPP__ +#ifndef OPENCV_CORE_HPP +#define OPENCV_CORE_HPP #ifndef __cplusplus # error core.hpp header must be compiled as C++ @@ -72,7 +72,10 @@ @defgroup core_cluster Clustering @defgroup core_utils Utility and system functions and macros @{ + @defgroup core_utils_sse SSE utilities @defgroup core_utils_neon NEON utilities + @defgroup core_utils_softfloat Softfloat support + @defgroup core_utils_samples Utility functions for OpenCV samples @} @defgroup core_opengl OpenGL interoperability @defgroup core_ipp Intel IPP Asynchronous C/C++ Converters @@ -80,6 +83,16 @@ @defgroup core_directx DirectX interoperability @defgroup core_eigen Eigen support @defgroup core_opencl OpenCL support + @defgroup core_va_intel Intel VA-API/OpenCL (CL-VA) interoperability + @defgroup core_hal Hardware Acceleration Layer + @{ + @defgroup core_hal_functions Functions + @defgroup core_hal_interface Interface + @defgroup core_hal_intrin Universal intrinsics + @{ + @defgroup core_hal_intrin_impl Private implementation helpers + @} + @} @} */ @@ -103,7 +116,7 @@ public: */ Exception(); /*! - Full constructor. Normally the constuctor is not called explicitly. + Full constructor. Normally the constructor is not called explicitly. Instead, the macros CV_Error(), CV_Error_() and CV_Assert() are used. */ Exception(int _code, const String& _err, const String& _func, const String& _file, int _line); @@ -112,7 +125,7 @@ public: /*! \return the error description and the context as a text string. */ - virtual const char *what() const throw(); + virtual const char *what() const throw() CV_OVERRIDE; void formatMessage(); String msg; ///< the formatted error message @@ -120,15 +133,15 @@ public: int code; ///< error code @see CVStatus String err; ///< error description String func; ///< function name. Available only when the compiler supports getting it - String file; ///< source file name where the error has occured - int line; ///< line number in the source file where the error has occured + String file; ///< source file name where the error has occurred + int line; ///< line number in the source file where the error has occurred }; /*! @brief Signals an error and raises the exception. By default the function prints information about the error to stderr, then it either stops if cv::setBreakOnError() had been called before or raises the exception. -It is possible to alternate error processing by using cv::redirectError(). +It is possible to alternate error processing by using #redirectError(). @param exc the exception raisen. @deprecated drop this version */ @@ -163,7 +176,7 @@ enum CovarFlags { /**The output covariance matrix is calculated as: \f[\texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...] \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T,\f] covar will be a square matrix of the same size as the total number of elements in each input - vector. One and only one of COVAR_SCRAMBLED and COVAR_NORMAL must be specified.*/ + vector. One and only one of #COVAR_SCRAMBLED and #COVAR_NORMAL must be specified.*/ COVAR_NORMAL = 1, /** If the flag is specified, the function does not calculate mean from the input vectors but, instead, uses the passed mean vector. This is useful if mean has been @@ -207,8 +220,7 @@ enum LineTypes { LINE_AA = 16 //!< antialiased line }; -//! Only a subset of Hershey fonts -//! are supported +//! Only a subset of Hershey fonts are supported enum HersheyFonts { FONT_HERSHEY_SIMPLEX = 0, //!< normal size sans-serif font FONT_HERSHEY_PLAIN = 1, //!< small size sans-serif font @@ -254,14 +266,19 @@ Normally, the function is not called directly. It is used inside filtering funct copyMakeBorder. @param p 0-based coordinate of the extrapolated pixel along one of the axes, likely \<0 or \>= len @param len Length of the array along the corresponding axis. -@param borderType Border type, one of the cv::BorderTypes, except for cv::BORDER_TRANSPARENT and -cv::BORDER_ISOLATED . When borderType==cv::BORDER_CONSTANT , the function always returns -1, regardless +@param borderType Border type, one of the #BorderTypes, except for #BORDER_TRANSPARENT and +#BORDER_ISOLATED . When borderType==#BORDER_CONSTANT , the function always returns -1, regardless of p and len. @sa copyMakeBorder */ CV_EXPORTS_W int borderInterpolate(int p, int len, int borderType); +/** @example samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp +An example using copyMakeBorder function. +Check @ref tutorial_copyMakeBorder "the corresponding tutorial" for more details +*/ + /** @brief Forms a border around an image. The function copies the source image into the middle of the destination image. The areas to the @@ -289,7 +306,7 @@ function does not copy src itself but simply constructs the border, for example: @endcode @note When the source image is a part (ROI) of a bigger image, the function will try to use the pixels outside of the ROI to form a border. To disable this feature and always do extrapolation, as -if src was not a ROI, use borderType | BORDER_ISOLATED. +if src was not a ROI, use borderType | #BORDER_ISOLATED. @param src Source image. @param dst Destination image of the same type as src and the size Size(src.cols+left+right, @@ -415,7 +432,7 @@ CV_EXPORTS_W void multiply(InputArray src1, InputArray src2, /** @brief Performs per-element division of two arrays or a scalar by an array. -The functions divide divide one array by another: +The function cv::divide divides one array by another: \f[\texttt{dst(I) = saturate(src1(I)*scale/src2(I))}\f] or a scalar by an array when there is no src1 : \f[\texttt{dst(I) = saturate(scale/src2(I))}\f] @@ -460,6 +477,10 @@ The function can also be emulated with a matrix expression, for example: */ CV_EXPORTS_W void scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst); +/** @example samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp +Check @ref tutorial_trackbar "the corresponding tutorial" for more details +*/ + /** @brief Calculates the weighted sum of two arrays. The function addWeighted calculates the weighted sum of two arrays as follows: @@ -513,13 +534,25 @@ For example: CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst, double alpha = 1, double beta = 0); +/** @brief Converts an array to half precision floating number. + +This function converts FP32 (single precision floating point) from/to FP16 (half precision floating point). CV_16S format is used to represent FP16 data. +There are two use modes (src -> dst): CV_32F -> CV_16S and CV_16S -> CV_32F. The input array has to have type of CV_32F or +CV_16S to represent the bit depth. If the input array is neither of them, the function will raise an error. +The format of half precision floating point is defined in IEEE 754-2008. + +@param src input array. +@param dst output array. +*/ +CV_EXPORTS_W void convertFp16(InputArray src, OutputArray dst); + /** @brief Performs a look-up table transform of an array. The function LUT fills the output array with values from the look-up table. Indices of the entries are taken from the input array. That is, the function processes each element of src as follows: \f[\texttt{dst} (I) \leftarrow \texttt{lut(src(I) + d)}\f] where -\f[d = \fork{0}{if \texttt{src} has depth \texttt{CV\_8U}}{128}{if \texttt{src} has depth \texttt{CV\_8S}}\f] +\f[d = \fork{0}{if \(\texttt{src}\) has depth \(\texttt{CV_8U}\)}{128}{if \(\texttt{src}\) has depth \(\texttt{CV_8S}\)}\f] @param src input array of 8-bit elements. @param lut look-up table of 256 elements; in case of multi-channel input array, the table should either have a single channel (in this case the same table is used for all channels) or the same @@ -531,7 +564,7 @@ CV_EXPORTS_W void LUT(InputArray src, InputArray lut, OutputArray dst); /** @brief Calculates the sum of array elements. -The functions sum calculate and return the sum of array elements, +The function cv::sum calculates and returns the sum of array elements, independently for each channel. @param src input array that must have from 1 to 4 channels. @sa countNonZero, mean, meanStdDev, norm, minMaxLoc, reduce @@ -577,10 +610,10 @@ CV_EXPORTS_W void findNonZero( InputArray src, OutputArray idx ); /** @brief Calculates an average (mean) of array elements. -The function mean calculates the mean value M of array elements, +The function cv::mean calculates the mean value M of array elements, independently for each channel, and return it: \f[\begin{array}{l} N = \sum _{I: \; \texttt{mask} (I) \ne 0} 1 \\ M_c = \left ( \sum _{I: \; \texttt{mask} (I) \ne 0}{ \texttt{mtx} (I)_c} \right )/N \end{array}\f] -When all the mask elements are 0's, the functions return Scalar::all(0) +When all the mask elements are 0's, the function returns Scalar::all(0) @param src input array that should have from 1 to 4 channels so that the result can be stored in Scalar_ . @param mask optional operation mask. @@ -590,11 +623,11 @@ CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray()); /** Calculates a mean and standard deviation of array elements. -The function meanStdDev calculates the mean and the standard deviation M +The function cv::meanStdDev calculates the mean and the standard deviation M of array elements independently for each channel and returns it via the output parameters: \f[\begin{array}{l} N = \sum _{I, \texttt{mask} (I) \ne 0} 1 \\ \texttt{mean} _c = \frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \texttt{src} (I)_c}{N} \\ \texttt{stddev} _c = \sqrt{\frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \left ( \texttt{src} (I)_c - \texttt{mean} _c \right )^2}{N}} \end{array}\f] -When all the mask elements are 0's, the functions return +When all the mask elements are 0's, the function returns mean=stddev=Scalar::all(0). @note The calculated standard deviation is only the diagonal of the complete normalized covariance matrix. If the full matrix is needed, you @@ -604,67 +637,85 @@ then pass the matrix to calcCovarMatrix . @param src input array that should have from 1 to 4 channels so that the results can be stored in Scalar_ 's. @param mean output parameter: calculated mean value. -@param stddev output parameter: calculateded standard deviation. +@param stddev output parameter: calculated standard deviation. @param mask optional operation mask. @sa countNonZero, mean, norm, minMaxLoc, calcCovarMatrix */ CV_EXPORTS_W void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, InputArray mask=noArray()); -/** @brief Calculates an absolute array norm, an absolute difference norm, or a -relative difference norm. +/** @brief Calculates the absolute norm of an array. -The functions norm calculate an absolute norm of src1 (when there is no -src2 ): +This version of #norm calculates the absolute norm of src1. The type of norm to calculate is specified using #NormTypes. -\f[norm = \forkthree{\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM\_INF}\) } -{ \| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM\_L1}\) } -{ \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if \(\texttt{normType} = \texttt{NORM\_L2}\) }\f] - -or an absolute or relative difference norm if src2 is there: - -\f[norm = \forkthree{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM\_INF}\) } -{ \| \texttt{src1} - \texttt{src2} \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM\_L1}\) } -{ \| \texttt{src1} - \texttt{src2} \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if \(\texttt{normType} = \texttt{NORM\_L2}\) }\f] - -or - -\f[norm = \forkthree{\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} }{\|\texttt{src2}\|_{L_{\infty}} }}{if \(\texttt{normType} = \texttt{NORM\_RELATIVE\_INF}\) } -{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if \(\texttt{normType} = \texttt{NORM\_RELATIVE\_L1}\) } -{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if \(\texttt{normType} = \texttt{NORM\_RELATIVE\_L2}\) }\f] - -The functions norm return the calculated norm. +As example for one array consider the function \f$r(x)= \begin{pmatrix} x \\ 1-x \end{pmatrix}, x \in [-1;1]\f$. +The \f$ L_{1}, L_{2} \f$ and \f$ L_{\infty} \f$ norm for the sample value \f$r(-1) = \begin{pmatrix} -1 \\ 2 \end{pmatrix}\f$ +is calculated as follows +\f{align*} + \| r(-1) \|_{L_1} &= |-1| + |2| = 3 \\ + \| r(-1) \|_{L_2} &= \sqrt{(-1)^{2} + (2)^{2}} = \sqrt{5} \\ + \| r(-1) \|_{L_\infty} &= \max(|-1|,|2|) = 2 +\f} +and for \f$r(0.5) = \begin{pmatrix} 0.5 \\ 0.5 \end{pmatrix}\f$ the calculation is +\f{align*} + \| r(0.5) \|_{L_1} &= |0.5| + |0.5| = 1 \\ + \| r(0.5) \|_{L_2} &= \sqrt{(0.5)^{2} + (0.5)^{2}} = \sqrt{0.5} \\ + \| r(0.5) \|_{L_\infty} &= \max(|0.5|,|0.5|) = 0.5. +\f} +The following graphic shows all values for the three norm functions \f$\| r(x) \|_{L_1}, \| r(x) \|_{L_2}\f$ and \f$\| r(x) \|_{L_\infty}\f$. +It is notable that the \f$ L_{1} \f$ norm forms the upper and the \f$ L_{\infty} \f$ norm forms the lower border for the example function \f$ r(x) \f$. +![Graphs for the different norm functions from the above example](pics/NormTypes_OneArray_1-2-INF.png) When the mask parameter is specified and it is not empty, the norm is + +If normType is not specified, #NORM_L2 is used. calculated only over the region specified by the mask. -A multi-channel input arrays are treated as a single-channel, that is, +Multi-channel input arrays are treated as single-channel arrays, that is, the results for all channels are combined. +Hamming norms can only be calculated with CV_8U depth arrays. + @param src1 first input array. -@param normType type of the norm (see cv::NormTypes). +@param normType type of the norm (see #NormTypes). @param mask optional operation mask; it must have the same size as src1 and CV_8UC1 type. */ CV_EXPORTS_W double norm(InputArray src1, int normType = NORM_L2, InputArray mask = noArray()); -/** @overload +/** @brief Calculates an absolute difference norm or a relative difference norm. + +This version of cv::norm calculates the absolute difference norm +or the relative difference norm of arrays src1 and src2. +The type of norm to calculate is specified using #NormTypes. + @param src1 first input array. @param src2 second input array of the same size and the same type as src1. -@param normType type of the norm (cv::NormTypes). +@param normType type of the norm (see #NormTypes). @param mask optional operation mask; it must have the same size as src1 and CV_8UC1 type. */ CV_EXPORTS_W double norm(InputArray src1, InputArray src2, int normType = NORM_L2, InputArray mask = noArray()); /** @overload @param src first input array. -@param normType type of the norm (see cv::NormTypes). +@param normType type of the norm (see #NormTypes). */ CV_EXPORTS double norm( const SparseMat& src, int normType ); -/** @brief computes PSNR image/video quality metric +/** @brief Computes the Peak Signal-to-Noise Ratio (PSNR) image quality metric. + +This function calculates the Peak Signal-to-Noise Ratio (PSNR) image quality metric in decibels (dB), between two input arrays src1 and src2. Arrays must have depth CV_8U. + +The PSNR is calculated as follows: + +\f[ +\texttt{PSNR} = 10 \cdot \log_{10}{\left( \frac{R^2}{MSE} \right) } +\f] + +where R is the maximum integer value of depth CV_8U (255) and MSE is the mean squared error between the two arrays. + +@param src1 first input array. +@param src2 second input array of the same size as src1. -see http://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio for details -@todo document */ CV_EXPORTS_W double PSNR(InputArray src1, InputArray src2); @@ -681,7 +732,7 @@ CV_EXPORTS_W void batchDistance(InputArray src1, InputArray src2, /** @brief Normalizes the norm or value range of an array. -The functions normalize scale and shift the input array elements so that +The function cv::normalize normalizes scale and shift the input array elements so that \f[\| \texttt{dst} \| _{L_p}= \texttt{alpha}\f] (where p=Inf, 1 or 2) when normType=NORM_INF, NORM_L1, or NORM_L2, respectively; or so that \f[\min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta}\f] @@ -694,6 +745,37 @@ min-max but modify the whole array, you can use norm and Mat::convertTo. In case of sparse matrices, only the non-zero values are analyzed and transformed. Because of this, the range transformation for sparse matrices is not allowed since it can shift the zero level. +Possible usage with some positive example data: +@code{.cpp} + vector positiveData = { 2.0, 8.0, 10.0 }; + vector normalizedData_l1, normalizedData_l2, normalizedData_inf, normalizedData_minmax; + + // Norm to probability (total count) + // sum(numbers) = 20.0 + // 2.0 0.1 (2.0/20.0) + // 8.0 0.4 (8.0/20.0) + // 10.0 0.5 (10.0/20.0) + normalize(positiveData, normalizedData_l1, 1.0, 0.0, NORM_L1); + + // Norm to unit vector: ||positiveData|| = 1.0 + // 2.0 0.15 + // 8.0 0.62 + // 10.0 0.77 + normalize(positiveData, normalizedData_l2, 1.0, 0.0, NORM_L2); + + // Norm to max element + // 2.0 0.2 (2.0/10.0) + // 8.0 0.8 (8.0/10.0) + // 10.0 1.0 (10.0/10.0) + normalize(positiveData, normalizedData_inf, 1.0, 0.0, NORM_INF); + + // Norm to range [0.0;1.0] + // 2.0 0.0 (shift to left border) + // 8.0 0.75 (6.0/8.0) + // 10.0 1.0 (shift to right border) + normalize(positiveData, normalizedData_minmax, 1.0, 0.0, NORM_MINMAX); +@endcode + @param src input array. @param dst output array of the same size as src . @param alpha norm value to normalize to or the lower range boundary in case of the range @@ -720,11 +802,11 @@ CV_EXPORTS void normalize( const SparseMat& src, SparseMat& dst, double alpha, i /** @brief Finds the global minimum and maximum in an array. -The functions minMaxLoc find the minimum and maximum element values and their positions. The +The function cv::minMaxLoc finds the minimum and maximum element values and their positions. The extremums are searched across the whole array or, if mask is not an empty array, in the specified array region. -The functions do not work with multi-channel arrays. If you need to find minimum or maximum +The function do not work with multi-channel arrays. If you need to find minimum or maximum elements across all the channels, use Mat::reshape first to reinterpret the array as single-channel. Or you may extract the particular channel using either extractImageCOI , or mixChannels , or split . @@ -743,7 +825,7 @@ CV_EXPORTS_W void minMaxLoc(InputArray src, CV_OUT double* minVal, /** @brief Finds the global minimum and maximum in an array -The function minMaxIdx finds the minimum and maximum element values and their positions. The +The function cv::minMaxIdx finds the minimum and maximum element values and their positions. The extremums are searched across the whole array or, if mask is not an empty array, in the specified array region. The function does not work with multi-channel arrays. If you need to find minimum or maximum elements across all the channels, use Mat::reshape first to reinterpret the array as @@ -781,36 +863,47 @@ CV_EXPORTS void minMaxLoc(const SparseMat& a, double* minVal, /** @brief Reduces a matrix to a vector. -The function reduce reduces the matrix to a vector by treating the matrix rows/columns as a set of +The function #reduce reduces the matrix to a vector by treating the matrix rows/columns as a set of 1D vectors and performing the specified operation on the vectors until a single row/column is obtained. For example, the function can be used to compute horizontal and vertical projections of a -raster image. In case of REDUCE_SUM and REDUCE_AVG , the output may have a larger element -bit-depth to preserve accuracy. And multi-channel arrays are also supported in these two reduction -modes. +raster image. In case of #REDUCE_MAX and #REDUCE_MIN , the output image should have the same type as the source one. +In case of #REDUCE_SUM and #REDUCE_AVG , the output may have a larger element bit-depth to preserve accuracy. +And multi-channel arrays are also supported in these two reduction modes. + +The following code demonstrates its usage for a single channel matrix. +@snippet snippets/core_reduce.cpp example + +And the following code demonstrates its usage for a two-channel matrix. +@snippet snippets/core_reduce.cpp example2 + @param src input 2D matrix. @param dst output vector. Its size and type is defined by dim and dtype parameters. @param dim dimension index along which the matrix is reduced. 0 means that the matrix is reduced to a single row. 1 means that the matrix is reduced to a single column. -@param rtype reduction operation that could be one of cv::ReduceTypes +@param rtype reduction operation that could be one of #ReduceTypes @param dtype when negative, the output vector will have the same type as the input matrix, otherwise, its type will be CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels()). @sa repeat */ CV_EXPORTS_W void reduce(InputArray src, OutputArray dst, int dim, int rtype, int dtype = -1); -/** @brief Creates one multichannel array out of several single-channel ones. +/** @brief Creates one multi-channel array out of several single-channel ones. -The functions merge merge several arrays to make a single multi-channel array. That is, each +The function cv::merge merges several arrays to make a single multi-channel array. That is, each element of the output array will be a concatenation of the elements of the input arrays, where elements of i-th input array are treated as mv[i].channels()-element vectors. -The function split does the reverse operation. If you need to shuffle channels in some other -advanced way, use mixChannels . +The function cv::split does the reverse operation. If you need to shuffle channels in some other +advanced way, use cv::mixChannels. + +The following example shows how to merge 3 single channel matrices into a single 3-channel matrix. +@snippet snippets/core_merge.cpp example + @param mv input array of matrices to be merged; all the matrices in mv must have the same size and the same depth. @param count number of input matrices when mv is a plain C array; it must be greater than zero. @param dst output array of the same size and the same depth as mv[0]; The number of channels will -be the total number of channels in the matrix array. +be equal to the parameter count. @sa mixChannels, split, Mat::reshape */ CV_EXPORTS void merge(const Mat* mv, size_t count, OutputArray dst); @@ -825,10 +918,14 @@ CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst); /** @brief Divides a multi-channel array into several single-channel arrays. -The functions split split a multi-channel array into separate single-channel arrays: +The function cv::split splits a multi-channel array into separate single-channel arrays: \f[\texttt{mv} [c](I) = \texttt{src} (I)_c\f] If you need to extract a single channel or do some other sophisticated channel permutation, use mixChannels . + +The following example demonstrates how to split a 3-channel matrix into 3 single channel matrices. +@snippet snippets/core_split.cpp example + @param src input multi-channel array. @param mvbegin output array; the number of arrays must match src.channels(); the arrays themselves are reallocated, if needed. @@ -845,34 +942,34 @@ CV_EXPORTS_W void split(InputArray m, OutputArrayOfArrays mv); /** @brief Copies specified channels from input arrays to the specified channels of output arrays. -The functions mixChannels provide an advanced mechanism for shuffling image channels. +The function cv::mixChannels provides an advanced mechanism for shuffling image channels. -split and merge and some forms of cvtColor are partial cases of mixChannels . +cv::split,cv::merge,cv::extractChannel,cv::insertChannel and some forms of cv::cvtColor are partial cases of cv::mixChannels. -In the example below, the code splits a 4-channel RGBA image into a 3-channel BGR (with R and B +In the example below, the code splits a 4-channel BGRA image into a 3-channel BGR (with B and R channels swapped) and a separate alpha-channel image: @code{.cpp} - Mat rgba( 100, 100, CV_8UC4, Scalar(1,2,3,4) ); - Mat bgr( rgba.rows, rgba.cols, CV_8UC3 ); - Mat alpha( rgba.rows, rgba.cols, CV_8UC1 ); + Mat bgra( 100, 100, CV_8UC4, Scalar(255,0,0,255) ); + Mat bgr( bgra.rows, bgra.cols, CV_8UC3 ); + Mat alpha( bgra.rows, bgra.cols, CV_8UC1 ); // forming an array of matrices is a quite efficient operation, // because the matrix data is not copied, only the headers Mat out[] = { bgr, alpha }; - // rgba[0] -> bgr[2], rgba[1] -> bgr[1], - // rgba[2] -> bgr[0], rgba[3] -> alpha[0] + // bgra[0] -> bgr[2], bgra[1] -> bgr[1], + // bgra[2] -> bgr[0], bgra[3] -> alpha[0] int from_to[] = { 0,2, 1,1, 2,0, 3,3 }; - mixChannels( &rgba, 1, out, 2, from_to, 4 ); + mixChannels( &bgra, 1, out, 2, from_to, 4 ); @endcode @note Unlike many other new-style C++ functions in OpenCV (see the introduction section and -Mat::create ), mixChannels requires the output arrays to be pre-allocated before calling the +Mat::create ), cv::mixChannels requires the output arrays to be pre-allocated before calling the function. -@param src input array or vector of matricesl; all of the matrices must have the same size and the +@param src input array or vector of matrices; all of the matrices must have the same size and the same depth. -@param nsrcs number of matrices in src. -@param dst output array or vector of matrices; all the matrices *must be allocated*; their size and -depth must be the same as in src[0]. -@param ndsts number of matrices in dst. +@param nsrcs number of matrices in `src`. +@param dst output array or vector of matrices; all the matrices **must be allocated**; their size and +depth must be the same as in `src[0]`. +@param ndsts number of matrices in `dst`. @param fromTo array of index pairs specifying which channels are copied and where; fromTo[k\*2] is a 0-based index of the input channel in src, fromTo[k\*2+1] is an index of the output channel in dst; the continuous channel numbering is used: the first input image channels are indexed from 0 to @@ -880,16 +977,16 @@ src[0].channels()-1, the second input image channels are indexed from src[0].cha src[0].channels() + src[1].channels()-1, and so on, the same scheme is used for the output image channels; as a special case, when fromTo[k\*2] is negative, the corresponding output channel is filled with zero . -@param npairs number of index pairs in fromTo. -@sa split, merge, cvtColor +@param npairs number of index pairs in `fromTo`. +@sa split, merge, extractChannel, insertChannel, cvtColor */ CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs); /** @overload -@param src input array or vector of matricesl; all of the matrices must have the same size and the +@param src input array or vector of matrices; all of the matrices must have the same size and the same depth. -@param dst output array or vector of matrices; all the matrices *must be allocated*; their size and +@param dst output array or vector of matrices; all the matrices **must be allocated**; their size and depth must be the same as in src[0]. @param fromTo array of index pairs specifying which channels are copied and where; fromTo[k\*2] is a 0-based index of the input channel in src, fromTo[k\*2+1] is an index of the output channel in @@ -904,9 +1001,9 @@ CV_EXPORTS void mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst const int* fromTo, size_t npairs); /** @overload -@param src input array or vector of matricesl; all of the matrices must have the same size and the +@param src input array or vector of matrices; all of the matrices must have the same size and the same depth. -@param dst output array or vector of matrices; all the matrices *must be allocated*; their size and +@param dst output array or vector of matrices; all the matrices **must be allocated**; their size and depth must be the same as in src[0]. @param fromTo array of index pairs specifying which channels are copied and where; fromTo[k\*2] is a 0-based index of the input channel in src, fromTo[k\*2+1] is an index of the output channel in @@ -919,19 +1016,25 @@ filled with zero . CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, const std::vector& fromTo); -/** @brief extracts a single channel from src (coi is 0-based index) -@todo document +/** @brief Extracts a single channel from src (coi is 0-based index) +@param src input array +@param dst output array +@param coi index of channel to extract +@sa mixChannels, split */ CV_EXPORTS_W void extractChannel(InputArray src, OutputArray dst, int coi); -/** @brief inserts a single channel to dst (coi is 0-based index) -@todo document +/** @brief Inserts a single channel to dst (coi is 0-based index) +@param src input array +@param dst output array +@param coi index of channel for insertion +@sa mixChannels, merge */ CV_EXPORTS_W void insertChannel(InputArray src, InputOutputArray dst, int coi); /** @brief Flips a 2D array around vertical, horizontal, or both axes. -The function flip flips the array in one of three different ways (row +The function cv::flip flips the array in one of three different ways (row and column indices are 0-based): \f[\texttt{dst} _{ij} = \left\{ @@ -963,26 +1066,44 @@ around both axes. */ CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode); +enum RotateFlags { + ROTATE_90_CLOCKWISE = 0, //! +-DBL_MAX and maxVal \< DBL_MAX, the function also checks that each value is between minVal and maxVal. In case of multi-channel arrays, each channel is processed independently. If some values are out of range, position of the first outlier is stored in pos (when pos != NULL). Then, the -functions either return false (when quiet=true) or throw an exception. +function either returns false (when quiet=true) or throws an exception. @param a input array. @param quiet a flag, indicating whether the functions quietly return false when the array elements are out of range or they throw an exception. @@ -1500,7 +1618,7 @@ CV_EXPORTS_W void patchNaNs(InputOutputArray a, double val = 0); /** @brief Performs generalized matrix multiplication. -The function performs generalized matrix multiplication similar to the +The function cv::gemm performs generalized matrix multiplication similar to the gemm functions in BLAS level 3. For example, `gemm(src1, src2, alpha, src3, beta, dst, GEMM_1_T + GEMM_3_T)` corresponds to @@ -1531,7 +1649,7 @@ CV_EXPORTS_W void gemm(InputArray src1, InputArray src2, double alpha, /** @brief Calculates the product of a matrix and its transposition. -The function mulTransposed calculates the product of src and its +The function cv::mulTransposed calculates the product of src and its transposition: \f[\texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} )^T ( \texttt{src} - \texttt{delta} )\f] if aTa=true , and @@ -1563,9 +1681,9 @@ CV_EXPORTS_W void mulTransposed( InputArray src, OutputArray dst, bool aTa, /** @brief Transposes a matrix. -The function transpose transposes the matrix src : +The function cv::transpose transposes the matrix src : \f[\texttt{dst} (i,j) = \texttt{src} (j,i)\f] -@note No complex conjugation is done in case of a complex matrix. It it +@note No complex conjugation is done in case of a complex matrix. It should be done separately if needed. @param src input array. @param dst output array of the same type as src. @@ -1574,7 +1692,7 @@ CV_EXPORTS_W void transpose(InputArray src, OutputArray dst); /** @brief Performs the matrix transformation of every array element. -The function transform performs the matrix transformation of every +The function cv::transform performs the matrix transformation of every element of the array src and stores the results in dst : \f[\texttt{dst} (I) = \texttt{m} \cdot \texttt{src} (I)\f] (when m.cols=src.channels() ), or @@ -1594,13 +1712,13 @@ m.cols or m.cols-1. @param dst output array of the same size and depth as src; it has as many channels as m.rows. @param m transformation 2x2 or 2x3 floating-point matrix. -@sa perspectiveTransform, getAffineTransform, estimateRigidTransform, warpAffine, warpPerspective +@sa perspectiveTransform, getAffineTransform, estimateAffine2D, warpAffine, warpPerspective */ CV_EXPORTS_W void transform(InputArray src, OutputArray dst, InputArray m ); /** @brief Performs the perspective matrix transformation of vectors. -The function perspectiveTransform transforms every element of src by +The function cv::perspectiveTransform transforms every element of src by treating it as a 2D or 3D vector, in the following way: \f[(x, y, z) \rightarrow (x'/w, y'/w, z'/w)\f] where @@ -1625,24 +1743,25 @@ element is a 2D/3D vector to be transformed. */ CV_EXPORTS_W void perspectiveTransform(InputArray src, OutputArray dst, InputArray m ); -/** @brief Copies the lower or the upper half of a square matrix to another half. +/** @brief Copies the lower or the upper half of a square matrix to its another half. -The function completeSymm copies the lower half of a square matrix to +The function cv::completeSymm copies the lower or the upper half of a square matrix to its another half. The matrix diagonal remains unchanged: -* \f$\texttt{mtx}_{ij}=\texttt{mtx}_{ji}\f$ for \f$i > j\f$ if + - \f$\texttt{m}_{ij}=\texttt{m}_{ji}\f$ for \f$i > j\f$ if lowerToUpper=false -* \f$\texttt{mtx}_{ij}=\texttt{mtx}_{ji}\f$ for \f$i < j\f$ if + - \f$\texttt{m}_{ij}=\texttt{m}_{ji}\f$ for \f$i < j\f$ if lowerToUpper=true -@param mtx input-output floating-point square matrix. + +@param m input-output floating-point square matrix. @param lowerToUpper operation flag; if true, the lower half is copied to the upper half. Otherwise, the upper half is copied to the lower half. @sa flip, transpose */ -CV_EXPORTS_W void completeSymm(InputOutputArray mtx, bool lowerToUpper = false); +CV_EXPORTS_W void completeSymm(InputOutputArray m, bool lowerToUpper = false); /** @brief Initializes a scaled identity matrix. -The function setIdentity initializes a scaled identity matrix: +The function cv::setIdentity initializes a scaled identity matrix: \f[\texttt{mtx} (i,j)= \fork{\texttt{value}}{ if \(i=j\)}{0}{otherwise}\f] The function can also be emulated using the matrix initializers and the @@ -1659,7 +1778,7 @@ CV_EXPORTS_W void setIdentity(InputOutputArray mtx, const Scalar& s = Scalar(1)) /** @brief Returns the determinant of a square floating-point matrix. -The function determinant calculates and returns the determinant of the +The function cv::determinant calculates and returns the determinant of the specified matrix. For small matrices ( mtx.cols=mtx.rows\<=3 ), the direct method is used. For larger matrices, the function uses LU factorization with partial pivoting. @@ -1674,7 +1793,7 @@ CV_EXPORTS_W double determinant(InputArray mtx); /** @brief Returns the trace of a matrix. -The function trace returns the sum of the diagonal elements of the +The function cv::trace returns the sum of the diagonal elements of the matrix mtx . \f[\mathrm{tr} ( \texttt{mtx} ) = \sum _i \texttt{mtx} (i,i)\f] @param mtx input matrix. @@ -1683,20 +1802,20 @@ CV_EXPORTS_W Scalar trace(InputArray mtx); /** @brief Finds the inverse or pseudo-inverse of a matrix. -The function invert inverts the matrix src and stores the result in dst +The function cv::invert inverts the matrix src and stores the result in dst . When the matrix src is singular or non-square, the function calculates the pseudo-inverse matrix (the dst matrix) so that norm(src\*dst - I) is minimal, where I is an identity matrix. -In case of the DECOMP_LU method, the function returns non-zero value if +In case of the #DECOMP_LU method, the function returns non-zero value if the inverse has been successfully calculated and 0 if src is singular. -In case of the DECOMP_SVD method, the function returns the inverse +In case of the #DECOMP_SVD method, the function returns the inverse condition number of src (the ratio of the smallest singular value to the largest singular value) and 0 if src is singular. The SVD method calculates a pseudo-inverse matrix if src is singular. -Similarly to DECOMP_LU, the method DECOMP_CHOLESKY works only with +Similarly to #DECOMP_LU, the method #DECOMP_CHOLESKY works only with non-singular square matrices that should also be symmetrical and positively defined. In this case, the function stores the inverted matrix in dst and returns non-zero. Otherwise, it returns 0. @@ -1710,12 +1829,12 @@ CV_EXPORTS_W double invert(InputArray src, OutputArray dst, int flags = DECOMP_L /** @brief Solves one or more linear systems or least-squares problems. -The function solve solves a linear system or least-squares problem (the +The function cv::solve solves a linear system or least-squares problem (the latter is possible with SVD or QR methods, or by specifying the flag -DECOMP_NORMAL ): +#DECOMP_NORMAL ): \f[\texttt{dst} = \arg \min _X \| \texttt{src1} \cdot \texttt{X} - \texttt{src2} \|\f] -If DECOMP_LU or DECOMP_CHOLESKY method is used, the function returns 1 +If #DECOMP_LU or #DECOMP_CHOLESKY method is used, the function returns 1 if src1 (or \f$\texttt{src1}^T\texttt{src1}\f$ ) is non-singular. Otherwise, it returns 0. In the latter case, dst is not valid. Other methods find a pseudo-solution in case of a singular left-hand side part. @@ -1727,7 +1846,7 @@ will not do the work. Use SVD::solveZ instead. @param src1 input matrix on the left-hand side of the system. @param src2 input matrix on the right-hand side of the system. @param dst output solution. -@param flags solution (matrix inversion) method (cv::DecompTypes) +@param flags solution (matrix inversion) method (#DecompTypes) @sa invert, SVD, eigen */ CV_EXPORTS_W bool solve(InputArray src1, InputArray src2, @@ -1735,7 +1854,7 @@ CV_EXPORTS_W bool solve(InputArray src1, InputArray src2, /** @brief Sorts each row or each column of a matrix. -The function sort sorts each matrix row or each matrix column in +The function cv::sort sorts each matrix row or each matrix column in ascending or descending order. So you should pass two operation flags to get desired behaviour. If you want to sort matrix rows or columns lexicographically, you can use STL std::sort generic function with the @@ -1743,14 +1862,14 @@ proper comparison predicate. @param src input single-channel array. @param dst output array of the same size and type as src. -@param flags operation flags, a combination of cv::SortFlags +@param flags operation flags, a combination of #SortFlags @sa sortIdx, randShuffle */ CV_EXPORTS_W void sort(InputArray src, OutputArray dst, int flags); /** @brief Sorts each row or each column of a matrix. -The function sortIdx sorts each matrix row or each matrix column in the +The function cv::sortIdx sorts each matrix row or each matrix column in the ascending or descending order. So you should pass two operation flags to get desired behaviour. Instead of reordering the elements themselves, it stores the indices of sorted elements in the output array. For example: @@ -1779,12 +1898,13 @@ The function solveCubic finds the real roots of a cubic equation: The roots are stored in the roots array. @param coeffs equation coefficients, an array of 3 or 4 elements. @param roots output array of real roots that has 1 or 3 elements. +@return number of real roots. It can be 0, 1 or 2. */ CV_EXPORTS_W int solveCubic(InputArray coeffs, OutputArray roots); /** @brief Finds the real or complex roots of a polynomial equation. -The function solvePoly finds real and complex roots of a polynomial equation: +The function cv::solvePoly finds real and complex roots of a polynomial equation: \f[\texttt{coeffs} [n] x^{n} + \texttt{coeffs} [n-1] x^{n-1} + ... + \texttt{coeffs} [1] x + \texttt{coeffs} [0] = 0\f] @param coeffs array of polynomial coefficients. @param roots output (complex) array of roots. @@ -1794,13 +1914,14 @@ CV_EXPORTS_W double solvePoly(InputArray coeffs, OutputArray roots, int maxIters /** @brief Calculates eigenvalues and eigenvectors of a symmetric matrix. -The functions eigen calculate just eigenvalues, or eigenvalues and eigenvectors of the symmetric +The function cv::eigen calculates just eigenvalues, or eigenvalues and eigenvectors of the symmetric matrix src: @code src*eigenvectors.row(i).t() = eigenvalues.at(i)*eigenvectors.row(i).t() @endcode -@note in the new and the old interfaces different ordering of eigenvalues and eigenvectors -parameters is used. + +@note Use cv::eigenNonSymmetric for calculation of real eigenvalues and eigenvectors of non-symmetric matrix. + @param src input matrix that must have CV_32FC1 or CV_64FC1 type, square size and be symmetrical (src ^T^ == src). @param eigenvalues output vector of eigenvalues of the same type as src; the eigenvalues are stored @@ -1808,20 +1929,37 @@ in the descending order. @param eigenvectors output matrix of eigenvectors; it has the same size and type as src; the eigenvectors are stored as subsequent matrix rows, in the same order as the corresponding eigenvalues. -@sa completeSymm , PCA +@sa eigenNonSymmetric, completeSymm , PCA */ CV_EXPORTS_W bool eigen(InputArray src, OutputArray eigenvalues, OutputArray eigenvectors = noArray()); +/** @brief Calculates eigenvalues and eigenvectors of a non-symmetric matrix (real eigenvalues only). + +@note Assumes real eigenvalues. + +The function calculates eigenvalues and eigenvectors (optional) of the square matrix src: +@code + src*eigenvectors.row(i).t() = eigenvalues.at(i)*eigenvectors.row(i).t() +@endcode + +@param src input matrix (CV_32FC1 or CV_64FC1 type). +@param eigenvalues output vector of eigenvalues (type is the same type as src). +@param eigenvectors output matrix of eigenvectors (type is the same type as src). The eigenvectors are stored as subsequent matrix rows, in the same order as the corresponding eigenvalues. +@sa eigen +*/ +CV_EXPORTS_W void eigenNonSymmetric(InputArray src, OutputArray eigenvalues, + OutputArray eigenvectors); + /** @brief Calculates the covariance matrix of a set of vectors. -The functions calcCovarMatrix calculate the covariance matrix and, optionally, the mean vector of +The function cv::calcCovarMatrix calculates the covariance matrix and, optionally, the mean vector of the set of input vectors. @param samples samples stored as separate matrices @param nsamples number of samples @param covar output covariance matrix of the type ctype and square size. @param mean input or output (depending on the flags) array as the average value of the input vectors. -@param flags operation flags as a combination of cv::CovarFlags +@param flags operation flags as a combination of #CovarFlags @param ctype type of the matrixl; it equals 'CV_64F' by default. @sa PCA, mulTransposed, Mahalanobis @todo InputArrayOfArrays @@ -1830,11 +1968,11 @@ CV_EXPORTS void calcCovarMatrix( const Mat* samples, int nsamples, Mat& covar, M int flags, int ctype = CV_64F); /** @overload -@note use cv::COVAR_ROWS or cv::COVAR_COLS flag +@note use #COVAR_ROWS or #COVAR_COLS flag @param samples samples stored as rows/columns of a single matrix. @param covar output covariance matrix of the type ctype and square size. @param mean input or output (depending on the flags) array as the average value of the input vectors. -@param flags operation flags as a combination of cv::CovarFlags +@param flags operation flags as a combination of #CovarFlags @param ctype type of the matrixl; it equals 'CV_64F' by default. */ CV_EXPORTS_W void calcCovarMatrix( InputArray samples, OutputArray covar, @@ -1844,10 +1982,20 @@ CV_EXPORTS_W void calcCovarMatrix( InputArray samples, OutputArray covar, CV_EXPORTS_W void PCACompute(InputArray data, InputOutputArray mean, OutputArray eigenvectors, int maxComponents = 0); +/** wrap PCA::operator() and add eigenvalues output parameter */ +CV_EXPORTS_AS(PCACompute2) void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, OutputArray eigenvalues, + int maxComponents = 0); + /** wrap PCA::operator() */ CV_EXPORTS_W void PCACompute(InputArray data, InputOutputArray mean, OutputArray eigenvectors, double retainedVariance); +/** wrap PCA::operator() and add eigenvalues output parameter */ +CV_EXPORTS_AS(PCACompute2) void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, OutputArray eigenvalues, + double retainedVariance); + /** wrap PCA::project */ CV_EXPORTS_W void PCAProject(InputArray data, InputArray mean, InputArray eigenvectors, OutputArray result); @@ -1865,10 +2013,10 @@ CV_EXPORTS_W void SVBackSubst( InputArray w, InputArray u, InputArray vt, /** @brief Calculates the Mahalanobis distance between two vectors. -The function Mahalanobis calculates and returns the weighted distance between two vectors: +The function cv::Mahalanobis calculates and returns the weighted distance between two vectors: \f[d( \texttt{vec1} , \texttt{vec2} )= \sqrt{\sum_{i,j}{\texttt{icovar(i,j)}\cdot(\texttt{vec1}(I)-\texttt{vec2}(I))\cdot(\texttt{vec1(j)}-\texttt{vec2(j)})} }\f] -The covariance matrix may be calculated using the cv::calcCovarMatrix function and then inverted using -the invert function (preferably using the cv::DECOMP_SVD method, as the most accurate). +The covariance matrix may be calculated using the #calcCovarMatrix function and then inverted using +the invert function (preferably using the #DECOMP_SVD method, as the most accurate). @param v1 first 1D input vector. @param v2 second 1D input vector. @param icovar inverse covariance matrix. @@ -1877,7 +2025,7 @@ CV_EXPORTS_W double Mahalanobis(InputArray v1, InputArray v2, InputArray icovar) /** @brief Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array. -The function performs one of the following: +The function cv::dft performs one of the following: - Forward the Fourier transform of a 1D vector of N elements: \f[Y = F^{(N)} \cdot X,\f] where \f$F^{(N)}_{jk}=\exp(-2\pi i j k/N)\f$ and \f$i=\sqrt{-1}\f$ @@ -1898,28 +2046,28 @@ is how 2D *CCS* spectrum looks: In case of 1D transform of a real vector, the output looks like the first row of the matrix above. So, the function chooses an operation mode depending on the flags and size of the input array: -- If DFT_ROWS is set or the input array has a single row or single column, the function - performs a 1D forward or inverse transform of each row of a matrix when DFT_ROWS is set. +- If #DFT_ROWS is set or the input array has a single row or single column, the function + performs a 1D forward or inverse transform of each row of a matrix when #DFT_ROWS is set. Otherwise, it performs a 2D transform. -- If the input array is real and DFT_INVERSE is not set, the function performs a forward 1D or +- If the input array is real and #DFT_INVERSE is not set, the function performs a forward 1D or 2D transform: - - When DFT_COMPLEX_OUTPUT is set, the output is a complex matrix of the same size as + - When #DFT_COMPLEX_OUTPUT is set, the output is a complex matrix of the same size as input. - - When DFT_COMPLEX_OUTPUT is not set, the output is a real matrix of the same size as + - When #DFT_COMPLEX_OUTPUT is not set, the output is a real matrix of the same size as input. In case of 2D transform, it uses the packed format as shown above. In case of a single 1D transform, it looks like the first row of the matrix above. In case of - multiple 1D transforms (when using the DFT_ROWS flag), each row of the output matrix + multiple 1D transforms (when using the #DFT_ROWS flag), each row of the output matrix looks like the first row of the matrix above. -- If the input array is complex and either DFT_INVERSE or DFT_REAL_OUTPUT are not set, the +- If the input array is complex and either #DFT_INVERSE or #DFT_REAL_OUTPUT are not set, the output is a complex array of the same size as input. The function performs a forward or inverse 1D or 2D transform of the whole input array or each row of the input array independently, depending on the flags DFT_INVERSE and DFT_ROWS. -- When DFT_INVERSE is set and the input array is real, or it is complex but DFT_REAL_OUTPUT +- When #DFT_INVERSE is set and the input array is real, or it is complex but #DFT_REAL_OUTPUT is set, the output is a real array of the same size as input. The function performs a 1D or 2D inverse transformation of the whole input array or each individual row, depending on the flags - DFT_INVERSE and DFT_ROWS. + #DFT_INVERSE and #DFT_ROWS. -If DFT_SCALE is set, the scaling is done after the transformation. +If #DFT_SCALE is set, the scaling is done after the transformation. Unlike dct , the function supports arrays of arbitrary size. But only those arrays are processed efficiently, whose sizes can be factorized in a product of small prime numbers (2, 3, and 5 in the @@ -1985,7 +2133,7 @@ To optimize this sample, consider the following approaches: - If different tiles in C can be calculated in parallel and, thus, the convolution is done by parts, the loop can be threaded. -All of the above improvements have been implemented in matchTemplate and filter2D . Therefore, by +All of the above improvements have been implemented in #matchTemplate and #filter2D . Therefore, by using them, you can get the performance even better than with the above theoretically optimal implementation. Though, those two functions actually calculate cross-correlation, not convolution, so you need to "flip" the second convolution operand B vertically and horizontally using flip . @@ -1993,15 +2141,15 @@ so you need to "flip" the second convolution operand B vertically and horizontal - An example using the discrete fourier transform can be found at opencv_source_code/samples/cpp/dft.cpp - (Python) An example using the dft functionality to perform Wiener deconvolution can be found - at opencv_source/samples/python2/deconvolution.py + at opencv_source/samples/python/deconvolution.py - (Python) An example rearranging the quadrants of a Fourier image can be found at - opencv_source/samples/python2/dft.py + opencv_source/samples/python/dft.py @param src input array that could be real or complex. @param dst output array whose size and type depends on the flags . -@param flags transformation flags, representing a combination of the cv::DftFlags +@param flags transformation flags, representing a combination of the #DftFlags @param nonzeroRows when the parameter is not zero, the function assumes that only the first -nonzeroRows rows of the input array (DFT_INVERSE is not set) or only the first nonzeroRows of the -output array (DFT_INVERSE is set) contain non-zeros, thus, the function can handle the rest of the +nonzeroRows rows of the input array (#DFT_INVERSE is not set) or only the first nonzeroRows of the +output array (#DFT_INVERSE is set) contain non-zeros, thus, the function can handle the rest of the rows more efficiently and save some time; this technique is very useful for calculating array cross-correlation or convolution using DFT. @sa dct , getOptimalDFTSize , mulSpectrums, filter2D , matchTemplate , flip , cartToPolar , @@ -2011,13 +2159,13 @@ CV_EXPORTS_W void dft(InputArray src, OutputArray dst, int flags = 0, int nonzer /** @brief Calculates the inverse Discrete Fourier Transform of a 1D or 2D array. -idft(src, dst, flags) is equivalent to dft(src, dst, flags | DFT_INVERSE) . -@note None of dft and idft scales the result by default. So, you should pass DFT_SCALE to one of +idft(src, dst, flags) is equivalent to dft(src, dst, flags | #DFT_INVERSE) . +@note None of dft and idft scales the result by default. So, you should pass #DFT_SCALE to one of dft or idft explicitly to make these transforms mutually inverse. @sa dft, dct, idct, mulSpectrums, getOptimalDFTSize @param src input floating-point real or complex array. @param dst output array whose size and type depend on the flags. -@param flags operation flags (see dft and cv::DftFlags). +@param flags operation flags (see dft and #DftFlags). @param nonzeroRows number of dst rows to process; the rest of the rows have undefined content (see the convolution sample in dft description. */ @@ -2025,7 +2173,7 @@ CV_EXPORTS_W void idft(InputArray src, OutputArray dst, int flags = 0, int nonze /** @brief Performs a forward or inverse discrete Cosine transform of 1D or 2D array. -The function dct performs a forward or inverse discrete Cosine transform (DCT) of a 1D or 2D +The function cv::dct performs a forward or inverse discrete Cosine transform (DCT) of a 1D or 2D floating-point array: - Forward Cosine transform of a 1D vector of N elements: \f[Y = C^{(N)} \cdot X\f] @@ -2042,9 +2190,9 @@ floating-point array: \f[X = \left (C^{(N)} \right )^T \cdot X \cdot C^{(N)}\f] The function chooses the mode of operation by looking at the flags and size of the input array: -- If (flags & DCT_INVERSE) == 0 , the function does a forward 1D or 2D transform. Otherwise, it +- If (flags & #DCT_INVERSE) == 0 , the function does a forward 1D or 2D transform. Otherwise, it is an inverse 1D or 2D transform. -- If (flags & DCT_ROWS) != 0 , the function performs a 1D transform of each row. +- If (flags & #DCT_ROWS) != 0 , the function performs a 1D transform of each row. - If the array is a single column or a single row, the function performs a 1D transform. - If none of the above is true, the function performs a 2D transform. @@ -2076,7 +2224,7 @@ CV_EXPORTS_W void idct(InputArray src, OutputArray dst, int flags = 0); /** @brief Performs the per-element multiplication of two Fourier spectrums. -The function mulSpectrums performs the per-element multiplication of the two CCS-packed or complex +The function cv::mulSpectrums performs the per-element multiplication of the two CCS-packed or complex matrices that are results of a real or complex Fourier transform. The function, together with dft and idft , may be used to calculate convolution (pass conjB=false ) @@ -2103,7 +2251,7 @@ original one. Arrays whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the Though, the arrays whose size is a product of 2's, 3's, and 5's (for example, 300 = 5\*5\*3\*2\*2) are also processed quite efficiently. -The function getOptimalDFTSize returns the minimum number N that is greater than or equal to vecsize +The function cv::getOptimalDFTSize returns the minimum number N that is greater than or equal to vecsize so that the DFT of a vector of size N can be processed efficiently. In the current implementation N = 2 ^p^ \* 3 ^q^ \* 5 ^r^ for some integer p, q, r. @@ -2119,7 +2267,7 @@ CV_EXPORTS_W int getOptimalDFTSize(int vecsize); /** @brief Returns the default random number generator. -The function theRNG returns the default random number generator. For each thread, there is a +The function cv::theRNG returns the default random number generator. For each thread, there is a separate random number generator, so you can use the function safely in multi-thread environments. If you just need to get a single random number using this generator or initialize an array, you can use randu or randn instead. But if you are going to generate many random numbers inside a loop, it @@ -2128,6 +2276,14 @@ is much faster to use this function to retrieve the generator and then use RNG:: */ CV_EXPORTS RNG& theRNG(); +/** @brief Sets state of default random number generator. + +The function cv::setRNGSeed sets state of default random number generator to custom value. +@param seed new state for default random number generator +@sa RNG, randu, randn +*/ +CV_EXPORTS_W void setRNGSeed(int seed); + /** @brief Generates a single uniformly-distributed random number or an array of random numbers. Non-template variant of the function fills the matrix dst with uniformly-distributed @@ -2142,7 +2298,7 @@ CV_EXPORTS_W void randu(InputOutputArray dst, InputArray low, InputArray high); /** @brief Fills the array with normally distributed random numbers. -The function randn fills the matrix dst with normally distributed random numbers with the specified +The function cv::randn fills the matrix dst with normally distributed random numbers with the specified mean vector and the standard deviation matrix. The generated random numbers are clipped to fit the value range of the output array data type. @param dst output array of random numbers; the array must be pre-allocated and have 1 to 4 channels. @@ -2155,7 +2311,7 @@ CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, InputArray stddev /** @brief Shuffles the array elements randomly. -The function randShuffle shuffles the specified 1D array by randomly choosing pairs of elements and +The function cv::randShuffle shuffles the specified 1D array by randomly choosing pairs of elements and swapping them. The number of such swap operations will be dst.rows\*dst.cols\*iterFactor . @param dst input/output numerical 1D array. @param iterFactor scale factor that determines the number of random swap operations (see the details @@ -2274,11 +2430,11 @@ public: The operator performs %PCA of the supplied dataset. It is safe to reuse the same PCA structure for multiple datasets. That is, if the structure has been previously used with another dataset, the existing internal - data is reclaimed and the new eigenvalues, @ref eigenvectors , and @ref + data is reclaimed and the new @ref eigenvalues, @ref eigenvectors and @ref mean are allocated and computed. - The computed eigenvalues are sorted from the largest to the smallest and - the corresponding eigenvectors are stored as eigenvectors rows. + The computed @ref eigenvalues are sorted from the largest to the smallest and + the corresponding @ref eigenvectors are stored as eigenvectors rows. @param data input samples stored as the matrix rows or as the matrix columns. @@ -2358,31 +2514,40 @@ public: */ void backProject(InputArray vec, OutputArray result) const; - /** @brief write and load PCA matrix + /** @brief write PCA objects -*/ - void write(FileStorage& fs ) const; - void read(const FileNode& fs); + Writes @ref eigenvalues @ref eigenvectors and @ref mean to specified FileStorage + */ + void write(FileStorage& fs) const; + + /** @brief load PCA objects + + Loads @ref eigenvalues @ref eigenvectors and @ref mean from specified FileNode + */ + void read(const FileNode& fn); Mat eigenvectors; //!< eigenvectors of the covariation matrix Mat eigenvalues; //!< eigenvalues of the covariation matrix Mat mean; //!< mean value subtracted before the projection and added after the back projection }; -/** @example pca.cpp - An example using %PCA for dimensionality reduction while maintaining an amount of variance - */ +/** @example samples/cpp/pca.cpp +An example using %PCA for dimensionality reduction while maintaining an amount of variance +*/ + +/** @example samples/cpp/tutorial_code/ml/introduction_to_pca/introduction_to_pca.cpp +Check @ref tutorial_introduction_to_pca "the corresponding tutorial" for more details +*/ /** - @brief Linear Discriminant Analysis - @todo document this class - */ +@brief Linear Discriminant Analysis +@todo document this class +*/ class CV_EXPORTS LDA { public: /** @brief constructor - Initializes a LDA with num_components (default 0) and specifies how - samples are aligned (default dataAsRow=true). + Initializes a LDA with num_components (default 0). */ explicit LDA(int num_components = 0); @@ -2413,15 +2578,17 @@ public: */ ~LDA(); - /** Compute the discriminants for data in src and labels. + /** Compute the discriminants for data in src (row aligned) and labels. */ void compute(InputArrayOfArrays src, InputArray labels); /** Projects samples into the LDA subspace. + src may be one or more row aligned samples. */ Mat project(InputArray src); /** Reconstructs projections from the LDA subspace. + src may be one or more row aligned projections. */ Mat reconstruct(InputArray src); @@ -2437,11 +2604,10 @@ public: static Mat subspaceReconstruct(InputArray W, InputArray mean, InputArray src); protected: - bool _dataAsRow; + bool _dataAsRow; // unused, but needed for 3.0 ABI compatibility. int _num_components; Mat _eigenvectors; Mat _eigenvalues; - void lda(InputArrayOfArrays src, InputArray labels); }; @@ -2483,7 +2649,7 @@ public: /** @overload initializes an empty SVD structure and then calls SVD::operator() - @param src decomposed matrix. + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. @param flags operation flags (SVD::Flags) */ SVD( InputArray src, int flags = 0 ); @@ -2496,7 +2662,7 @@ public: different matrices. Each time, if needed, the previous u,`vt` , and w are reclaimed and the new matrices are created, which is all handled by Mat::create. - @param src decomposed matrix. + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. @param flags operation flags (SVD::Flags) */ SVD& operator ()( InputArray src, int flags = 0 ); @@ -2512,18 +2678,18 @@ public: SVD::compute(A, w, u, vt); @endcode - @param src decomposed matrix + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. @param w calculated singular values @param u calculated left singular vectors - @param vt transposed matrix of right singular values - @param flags operation flags - see SVD::SVD. + @param vt transposed matrix of right singular vectors + @param flags operation flags - see SVD::Flags. */ static void compute( InputArray src, OutputArray w, OutputArray u, OutputArray vt, int flags = 0 ); /** @overload computes singular values of a matrix - @param src decomposed matrix + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. @param w calculated singular values @param flags operation flags - see SVD::Flags. */ @@ -2567,7 +2733,7 @@ public: if you need to solve many linear systems with the same left-hand side (for example, src ). If all you need is to solve a single system (possibly with multiple rhs immediately available), simply call solve - add pass DECOMP_SVD there. It does absolutely the same thing. + add pass #DECOMP_SVD there. It does absolutely the same thing. */ void backSubst( InputArray rhs, OutputArray dst ) const; @@ -2674,7 +2840,7 @@ public: double a1 = rng.uniform((double)0, (double)1); // produces float from [0, 1) - double b = rng.uniform(0.f, 1.f); + float b = rng.uniform(0.f, 1.f); // produces double from [0, 1) double c = rng.uniform(0., 1.); @@ -2690,9 +2856,9 @@ public: want a floating-point random number, but the range boundaries are integer numbers, either put dots in the end, if they are constants, or use explicit type cast operators, as in the a1 initialization above. - @param a lower inclusive boundary of the returned random numbers. - @param b upper non-inclusive boundary of the returned random numbers. - */ + @param a lower inclusive boundary of the returned random number. + @param b upper non-inclusive boundary of the returned random number. + */ int uniform(int a, int b); /** @overload */ float uniform(float a, float b); @@ -2746,13 +2912,15 @@ public: double gaussian(double sigma); uint64 state; + + bool operator ==(const RNG& other) const; }; /** @brief Mersenne Twister random number generator Inspired by http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c @todo document - */ +*/ class CV_EXPORTS RNG_MT19937 { public: @@ -2770,17 +2938,11 @@ public: unsigned operator ()(unsigned N); unsigned operator ()(); - /** @brief returns uniformly distributed integer random number from [a,b) range - -*/ + /** @brief returns uniformly distributed integer random number from [a,b) range*/ int uniform(int a, int b); - /** @brief returns uniformly distributed floating-point random number from [a,b) range - -*/ + /** @brief returns uniformly distributed floating-point random number from [a,b) range*/ float uniform(float a, float b); - /** @brief returns uniformly distributed double-precision floating-point random number from [a,b) range - -*/ + /** @brief returns uniformly distributed double-precision floating-point random number from [a,b) range*/ double uniform(double a, double b); private: @@ -2794,19 +2956,19 @@ private: //! @addtogroup core_cluster //! @{ -/** @example kmeans.cpp - An example on K-means clustering +/** @example samples/cpp/kmeans.cpp +An example on K-means clustering */ /** @brief Finds centers of clusters and groups input samples around the clusters. The function kmeans implements a k-means algorithm that finds the centers of cluster_count clusters -and groups the input samples around the clusters. As an output, \f$\texttt{labels}_i\f$ contains a +and groups the input samples around the clusters. As an output, \f$\texttt{bestLabels}_i\f$ contains a 0-based cluster index for the sample stored in the \f$i^{th}\f$ row of the samples matrix. @note - (Python) An example on K-means clustering can be found at - opencv_source_code/samples/python2/kmeans.py + opencv_source_code/samples/python/kmeans.py @param data Data for clustering. An array of N-Dimensional points with float coordinates is needed. Examples of this array can be: - Mat points(count, 2, CV_32F); @@ -2828,7 +2990,7 @@ function parameter). after every attempt. The best (minimum) value is chosen and the corresponding labels and the compactness value are returned by the function. Basically, you can use only the core of the function, set the number of attempts to 1, initialize labels each time using a custom algorithm, -pass them with the ( flags = KMEANS_USE_INITIAL_LABELS ) flag, and then choose the best +pass them with the ( flags = #KMEANS_USE_INITIAL_LABELS ) flag, and then choose the best (most-compact) clustering. */ CV_EXPORTS_W double kmeans( InputArray data, int K, InputOutputArray bestLabels, @@ -2875,6 +3037,21 @@ public: }; +static inline +String& operator << (String& out, Ptr fmtd) +{ + fmtd->reset(); + for(const char* str = fmtd->next(); str; str = fmtd->next()) + out += cv::String(str); + return out; +} + +static inline +String& operator << (String& out, const Mat& mtx) +{ + return out << Formatter::get()->format(mtx); +} + //////////////////////////////////////// Algorithm //////////////////////////////////// class CV_EXPORTS Algorithm; @@ -2890,32 +3067,9 @@ matching, graph-cut etc.), background subtraction (which can be done using mixtu models, codebook-based algorithm etc.), optical flow (block matching, Lucas-Kanade, Horn-Schunck etc.). -Here is example of SIFT use in your application via Algorithm interface: -@code - #include "opencv2/opencv.hpp" - #include "opencv2/xfeatures2d.hpp" - using namespace cv::xfeatures2d; - - Ptr sift = SIFT::create(); - FileStorage fs("sift_params.xml", FileStorage::READ); - if( fs.isOpened() ) // if we have file with parameters, read them - { - sift->read(fs["sift_params"]); - fs.release(); - } - else // else modify the parameters and store them; user can later edit the file to use different parameters - { - sift->setContrastThreshold(0.01f); // lower the contrast threshold, compared to the default value - { - WriteStructContext ws(fs, "sift_params", CV_NODE_MAP); - sift->write(fs); - } - } - Mat image = imread("myimage.png", 0), descriptors; - vector keypoints; - sift->detectAndCompute(image, noArray(), keypoints, descriptors); -@endcode - */ +Here is example of SimpleBlobDetector use in your application via Algorithm interface: +@snippet snippets/core_various.cpp Algorithm +*/ class CV_EXPORTS_W Algorithm { public: @@ -2928,26 +3082,32 @@ public: /** @brief Stores algorithm parameters in a file storage */ - virtual void write(FileStorage& fs) const { (void)fs; } + virtual void write(FileStorage& fs) const { CV_UNUSED(fs); } + + /** @brief simplified API for language bindings + * @overload + */ + CV_WRAP void write(const Ptr& fs, const String& name = String()) const; /** @brief Reads algorithm parameters from a file storage */ - virtual void read(const FileNode& fn) { (void)fn; } + CV_WRAP virtual void read(const FileNode& fn) { CV_UNUSED(fn); } /** @brief Returns true if the Algorithm is empty (e.g. in the very beginning or after unsuccessful read - */ - virtual bool empty() const { return false; } + */ + CV_WRAP virtual bool empty() const { return false; } /** @brief Reads algorithm from the file node - This is static template method of Algorithm. It's usage is following (in the case of SVM): - @code - Ptr svm = Algorithm::read(fn); - @endcode - In order to make this method work, the derived class must overwrite Algorithm::read(const - FileNode& fn) and also have static create() method without parameters - (or with all the optional parameters) - */ + This is static template method of Algorithm. It's usage is following (in the case of SVM): + @code + cv::FileStorage fsRead("example.xml", FileStorage::READ); + Ptr svm = Algorithm::read(fsRead.root()); + @endcode + In order to make this method work, the derived class must overwrite Algorithm::read(const + FileNode& fn) and also have static create() method without parameters + (or with all the optional parameters) + */ template static Ptr<_Tp> read(const FileNode& fn) { Ptr<_Tp> obj = _Tp::create(); @@ -2957,20 +3117,22 @@ public: /** @brief Loads algorithm from the file - @param filename Name of the file to read. - @param objname The optional name of the node to read (if empty, the first top-level node will be used) + @param filename Name of the file to read. + @param objname The optional name of the node to read (if empty, the first top-level node will be used) - This is static template method of Algorithm. It's usage is following (in the case of SVM): - @code - Ptr svm = Algorithm::load("my_svm_model.xml"); - @endcode - In order to make this method work, the derived class must overwrite Algorithm::read(const - FileNode& fn). - */ + This is static template method of Algorithm. It's usage is following (in the case of SVM): + @code + Ptr svm = Algorithm::load("my_svm_model.xml"); + @endcode + In order to make this method work, the derived class must overwrite Algorithm::read(const + FileNode& fn). + */ template static Ptr<_Tp> load(const String& filename, const String& objname=String()) { FileStorage fs(filename, FileStorage::READ); + CV_Assert(fs.isOpened()); FileNode fn = objname.empty() ? fs.getFirstTopLevelNode() : fs[objname]; + if (fn.empty()) return Ptr<_Tp>(); Ptr<_Tp> obj = _Tp::create(); obj->read(fn); return !obj->empty() ? obj : Ptr<_Tp>(); @@ -2978,14 +3140,14 @@ public: /** @brief Loads algorithm from a String - @param strModel The string variable containing the model you want to load. - @param objname The optional name of the node to read (if empty, the first top-level node will be used) + @param strModel The string variable containing the model you want to load. + @param objname The optional name of the node to read (if empty, the first top-level node will be used) - This is static template method of Algorithm. It's usage is following (in the case of SVM): - @code - Ptr svm = Algorithm::loadFromString(myStringModel); - @endcode - */ + This is static template method of Algorithm. It's usage is following (in the case of SVM): + @code + Ptr svm = Algorithm::loadFromString(myStringModel); + @endcode + */ template static Ptr<_Tp> loadFromString(const String& strModel, const String& objname=String()) { FileStorage fs(strModel, FileStorage::READ + FileStorage::MEMORY); @@ -2996,17 +3158,20 @@ public: } /** Saves the algorithm to a file. - In order to make this method work, the derived class must implement Algorithm::write(FileStorage& fs). */ + In order to make this method work, the derived class must implement Algorithm::write(FileStorage& fs). */ CV_WRAP virtual void save(const String& filename) const; /** Returns the algorithm string identifier. - This string is used as top level xml/yml node tag when the object is saved to a file or string. */ + This string is used as top level xml/yml node tag when the object is saved to a file or string. */ CV_WRAP virtual String getDefaultName() const; + +protected: + void writeFormat(FileStorage& fs) const; }; struct Param { enum { INT=0, BOOLEAN=1, REAL=2, STRING=3, MAT=4, MAT_VECTOR=5, ALGORITHM=6, FLOAT=7, - UNSIGNED_INT=8, UINT64=9, UCHAR=11 }; + UNSIGNED_INT=8, UINT64=9, UCHAR=11, SCALAR=12 }; }; @@ -3099,6 +3264,14 @@ template<> struct ParamType enum { type = Param::UCHAR }; }; +template<> struct ParamType +{ + typedef const Scalar& const_param_type; + typedef Scalar member_type; + + enum { type = Param::SCALAR }; +}; + //! @} core_basic } //namespace cv @@ -3107,5 +3280,6 @@ template<> struct ParamType #include "opencv2/core/cvstd.inl.hpp" #include "opencv2/core/utility.hpp" #include "opencv2/core/optim.hpp" +#include "opencv2/core/ovx.hpp" -#endif /*__OPENCV_CORE_HPP__*/ +#endif /*OPENCV_CORE_HPP*/ diff --git a/include/opencv2/core/affine.hpp b/include/opencv2/core/affine.hpp index 3b527cd..7e2ed30 100644 --- a/include/opencv2/core/affine.hpp +++ b/include/opencv2/core/affine.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CORE_AFFINE3_HPP__ -#define __OPENCV_CORE_AFFINE3_HPP__ +#ifndef OPENCV_CORE_AFFINE3_HPP +#define OPENCV_CORE_AFFINE3_HPP #ifdef __cplusplus @@ -55,7 +55,72 @@ namespace cv //! @{ /** @brief Affine transform - @todo document + * + * It represents a 4x4 homogeneous transformation matrix \f$T\f$ + * + * \f[T = + * \begin{bmatrix} + * R & t\\ + * 0 & 1\\ + * \end{bmatrix} + * \f] + * + * where \f$R\f$ is a 3x3 rotation matrix and \f$t\f$ is a 3x1 translation vector. + * + * You can specify \f$R\f$ either by a 3x3 rotation matrix or by a 3x1 rotation vector, + * which is converted to a 3x3 rotation matrix by the Rodrigues formula. + * + * To construct a matrix \f$T\f$ representing first rotation around the axis \f$r\f$ with rotation + * angle \f$|r|\f$ in radian (right hand rule) and then translation by the vector \f$t\f$, you can use + * + * @code + * cv::Vec3f r, t; + * cv::Affine3f T(r, t); + * @endcode + * + * If you already have the rotation matrix \f$R\f$, then you can use + * + * @code + * cv::Matx33f R; + * cv::Affine3f T(R, t); + * @endcode + * + * To extract the rotation matrix \f$R\f$ from \f$T\f$, use + * + * @code + * cv::Matx33f R = T.rotation(); + * @endcode + * + * To extract the translation vector \f$t\f$ from \f$T\f$, use + * + * @code + * cv::Vec3f t = T.translation(); + * @endcode + * + * To extract the rotation vector \f$r\f$ from \f$T\f$, use + * + * @code + * cv::Vec3f r = T.rvec(); + * @endcode + * + * Note that since the mapping from rotation vectors to rotation matrices + * is many to one. The returned rotation vector is not necessarily the one + * you used before to set the matrix. + * + * If you have two transformations \f$T = T_1 * T_2\f$, use + * + * @code + * cv::Affine3f T, T1, T2; + * T = T2.concatenate(T1); + * @endcode + * + * To get the inverse transform of \f$T\f$, use + * + * @code + * cv::Affine3f T, T_inv; + * T_inv = T.inv(); + * @endcode + * */ template class Affine3 @@ -66,54 +131,136 @@ namespace cv typedef Matx Mat4; typedef Vec Vec3; + //! Default constructor. It represents a 4x4 identity matrix. Affine3(); //! Augmented affine matrix Affine3(const Mat4& affine); - //! Rotation matrix + /** + * The resulting 4x4 matrix is + * + * \f[ + * \begin{bmatrix} + * R & t\\ + * 0 & 1\\ + * \end{bmatrix} + * \f] + * + * @param R 3x3 rotation matrix. + * @param t 3x1 translation vector. + */ Affine3(const Mat3& R, const Vec3& t = Vec3::all(0)); - //! Rodrigues vector + /** + * Rodrigues vector. + * + * The last row of the current matrix is set to [0,0,0,1]. + * + * @param rvec 3x1 rotation vector. Its direction indicates the rotation axis and its length + * indicates the rotation angle in radian (using right hand rule). + * @param t 3x1 translation vector. + */ Affine3(const Vec3& rvec, const Vec3& t = Vec3::all(0)); - //! Combines all contructors above. Supports 4x4, 4x3, 3x3, 1x3, 3x1 sizes of data matrix + /** + * Combines all constructors above. Supports 4x4, 3x4, 3x3, 1x3, 3x1 sizes of data matrix. + * + * The last row of the current matrix is set to [0,0,0,1] when data is not 4x4. + * + * @param data 1-channel matrix. + * when it is 4x4, it is copied to the current matrix and t is not used. + * When it is 3x4, it is copied to the upper part 3x4 of the current matrix and t is not used. + * When it is 3x3, it is copied to the upper left 3x3 part of the current matrix. + * When it is 3x1 or 1x3, it is treated as a rotation vector and the Rodrigues formula is used + * to compute a 3x3 rotation matrix. + * @param t 3x1 translation vector. It is used only when data is neither 4x4 nor 3x4. + */ explicit Affine3(const Mat& data, const Vec3& t = Vec3::all(0)); - //! From 16th element array + //! From 16-element array explicit Affine3(const float_type* vals); - //! Create identity transform + //! Create an 4x4 identity transform static Affine3 Identity(); - //! Rotation matrix + /** + * Rotation matrix. + * + * Copy the rotation matrix to the upper left 3x3 part of the current matrix. + * The remaining elements of the current matrix are not changed. + * + * @param R 3x3 rotation matrix. + * + */ void rotation(const Mat3& R); - //! Rodrigues vector + /** + * Rodrigues vector. + * + * It sets the upper left 3x3 part of the matrix. The remaining part is unaffected. + * + * @param rvec 3x1 rotation vector. The direction indicates the rotation axis and + * its length indicates the rotation angle in radian (using the right thumb convention). + */ void rotation(const Vec3& rvec); - //! Combines rotation methods above. Suports 3x3, 1x3, 3x1 sizes of data matrix; + /** + * Combines rotation methods above. Supports 3x3, 1x3, 3x1 sizes of data matrix. + * + * It sets the upper left 3x3 part of the matrix. The remaining part is unaffected. + * + * @param data 1-channel matrix. + * When it is a 3x3 matrix, it sets the upper left 3x3 part of the current matrix. + * When it is a 1x3 or 3x1 matrix, it is used as a rotation vector. The Rodrigues formula + * is used to compute the rotation matrix and sets the upper left 3x3 part of the current matrix. + */ void rotation(const Mat& data); + /** + * Copy the 3x3 matrix L to the upper left part of the current matrix + * + * It sets the upper left 3x3 part of the matrix. The remaining part is unaffected. + * + * @param L 3x3 matrix. + */ void linear(const Mat3& L); + + /** + * Copy t to the first three elements of the last column of the current matrix + * + * It sets the upper right 3x1 part of the matrix. The remaining part is unaffected. + * + * @param t 3x1 translation vector. + */ void translation(const Vec3& t); + //! @return the upper left 3x3 part Mat3 rotation() const; + + //! @return the upper left 3x3 part Mat3 linear() const; + + //! @return the upper right 3x1 part Vec3 translation() const; - //! Rodrigues vector + //! Rodrigues vector. + //! @return a vector representing the upper left 3x3 rotation matrix of the current matrix. + //! @warning Since the mapping between rotation vectors and rotation matrices is many to one, + //! this function returns only one rotation vector that represents the current rotation matrix, + //! which is not necessarily the same one set by `rotation(const Vec3& rvec)`. Vec3 rvec() const; + //! @return the inverse of the current matrix. Affine3 inv(int method = cv::DECOMP_SVD) const; //! a.rotate(R) is equivalent to Affine(R, 0) * a; Affine3 rotate(const Mat3& R) const; - //! a.rotate(R) is equivalent to Affine(rvec, 0) * a; + //! a.rotate(rvec) is equivalent to Affine(rvec, 0) * a; Affine3 rotate(const Vec3& rvec) const; - //! a.translate(t) is equivalent to Affine(E, t) * a; + //! a.translate(t) is equivalent to Affine(E, t) * a, where E is an identity matrix Affine3 translate(const Vec3& t) const; //! a.concatenate(affine) is equivalent to affine * a; @@ -136,6 +283,7 @@ namespace cv template static Affine3 operator*(const Affine3& affine1, const Affine3& affine2); + //! V is a 3-element vector with member fields x, y and z template static V operator*(const Affine3& affine, const V& vector); @@ -153,15 +301,24 @@ namespace cv typedef _Tp channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 16, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; + namespace traits { + template + struct Depth< Affine3<_Tp> > { enum { value = Depth<_Tp>::value }; }; + template + struct Type< Affine3<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 16) }; }; + } // namespace + //! @} core } @@ -169,7 +326,7 @@ namespace cv //! @cond IGNORED /////////////////////////////////////////////////////////////////////////////////// -// Implementaiton +// Implementation template inline cv::Affine3::Affine3() @@ -202,7 +359,8 @@ cv::Affine3::Affine3(const Vec3& _rvec, const Vec3& t) template inline cv::Affine3::Affine3(const cv::Mat& data, const Vec3& t) { - CV_Assert(data.type() == cv::DataType::type); + CV_Assert(data.type() == cv::traits::Type::value); + CV_Assert(data.channels() == 1); if (data.cols == 4 && data.rows == 4) { @@ -213,11 +371,13 @@ cv::Affine3::Affine3(const cv::Mat& data, const Vec3& t) { rotation(data(Rect(0, 0, 3, 3))); translation(data(Rect(3, 0, 1, 3))); - return; + } + else + { + rotation(data); + translation(t); } - rotation(data); - translation(t); matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; matrix.val[15] = 1; } @@ -241,40 +401,36 @@ void cv::Affine3::rotation(const Mat3& R) template inline void cv::Affine3::rotation(const Vec3& _rvec) { - double rx = _rvec[0], ry = _rvec[1], rz = _rvec[2]; - double theta = std::sqrt(rx*rx + ry*ry + rz*rz); + double theta = norm(_rvec); if (theta < DBL_EPSILON) rotation(Mat3::eye()); else { - const double I[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; - double c = std::cos(theta); double s = std::sin(theta); double c1 = 1. - c; double itheta = (theta != 0) ? 1./theta : 0.; - rx *= itheta; ry *= itheta; rz *= itheta; + Point3_ r = _rvec*itheta; - double rrt[] = { rx*rx, rx*ry, rx*rz, rx*ry, ry*ry, ry*rz, rx*rz, ry*rz, rz*rz }; - double _r_x_[] = { 0, -rz, ry, rz, 0, -rx, -ry, rx, 0 }; - Mat3 R; + Mat3 rrt( r.x*r.x, r.x*r.y, r.x*r.z, r.x*r.y, r.y*r.y, r.y*r.z, r.x*r.z, r.y*r.z, r.z*r.z ); + Mat3 r_x( 0, -r.z, r.y, r.z, 0, -r.x, -r.y, r.x, 0 ); // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x] // where [r_x] is [0 -rz ry; rz 0 -rx; -ry rx 0] - for(int k = 0; k < 9; ++k) - R.val[k] = static_cast(c*I[k] + c1*rrt[k] + s*_r_x_[k]); + Mat3 R = c*Mat3::eye() + c1*rrt + s*r_x; rotation(R); } } -//Combines rotation methods above. Suports 3x3, 1x3, 3x1 sizes of data matrix; +//Combines rotation methods above. Supports 3x3, 1x3, 3x1 sizes of data matrix; template inline void cv::Affine3::rotation(const cv::Mat& data) { - CV_Assert(data.type() == cv::DataType::type); + CV_Assert(data.type() == cv::traits::Type::value); + CV_Assert(data.channels() == 1); if (data.cols == 3 && data.rows == 3) { @@ -289,7 +445,7 @@ void cv::Affine3::rotation(const cv::Mat& data) rotation(_rvec); } else - CV_Assert(!"Input marix can be 3x3, 1x3 or 3x1"); + CV_Error(Error::StsError, "Input matrix can only be 3x3, 1x3 or 3x1"); } template inline @@ -488,21 +644,21 @@ cv::Vec3d cv::operator*(const cv::Affine3d& affine, const cv::Vec3d& v) template inline cv::Affine3::Affine3(const Eigen::Transform& affine) { - cv::Mat(4, 4, cv::DataType::type, affine.matrix().data()).copyTo(matrix); + cv::Mat(4, 4, cv::traits::Type::value, affine.matrix().data()).copyTo(matrix); } template inline cv::Affine3::Affine3(const Eigen::Transform& affine) { Eigen::Transform a = affine; - cv::Mat(4, 4, cv::DataType::type, a.matrix().data()).copyTo(matrix); + cv::Mat(4, 4, cv::traits::Type::value, a.matrix().data()).copyTo(matrix); } template inline cv::Affine3::operator Eigen::Transform() const { Eigen::Transform r; - cv::Mat hdr(4, 4, cv::DataType::type, r.matrix().data()); + cv::Mat hdr(4, 4, cv::traits::Type::value, r.matrix().data()); cv::Mat(matrix, false).copyTo(hdr); return r; } @@ -519,4 +675,4 @@ cv::Affine3::operator Eigen::Transform() const #endif /* __cplusplus */ -#endif /* __OPENCV_CORE_AFFINE3_HPP__ */ +#endif /* OPENCV_CORE_AFFINE3_HPP */ diff --git a/include/opencv2/core/base.hpp b/include/opencv2/core/base.hpp index 83cc311..31cd7a8 100644 --- a/include/opencv2/core/base.hpp +++ b/include/opencv2/core/base.hpp @@ -42,18 +42,20 @@ // //M*/ -#ifndef __OPENCV_CORE_BASE_HPP__ -#define __OPENCV_CORE_BASE_HPP__ +#ifndef OPENCV_CORE_BASE_HPP +#define OPENCV_CORE_BASE_HPP #ifndef __cplusplus # error base.hpp header must be compiled as C++ #endif +#include "opencv2/opencv_modules.hpp" + #include +#include #include "opencv2/core/cvdef.h" #include "opencv2/core/cvstd.hpp" -#include "opencv2/hal.hpp" namespace cv { @@ -64,38 +66,38 @@ namespace cv namespace Error { //! error codes enum Code { - StsOk= 0, //!< everithing is ok + StsOk= 0, //!< everything is ok StsBackTrace= -1, //!< pseudo error for back trace StsError= -2, //!< unknown /unspecified error StsInternal= -3, //!< internal error (bad state) StsNoMem= -4, //!< insufficient memory StsBadArg= -5, //!< function arg/param is bad StsBadFunc= -6, //!< unsupported function - StsNoConv= -7, //!< iter. didn't converge + StsNoConv= -7, //!< iteration didn't converge StsAutoTrace= -8, //!< tracing HeaderIsNull= -9, //!< image header is NULL BadImageSize= -10, //!< image size is invalid BadOffset= -11, //!< offset is invalid BadDataPtr= -12, //!< - BadStep= -13, //!< + BadStep= -13, //!< image step is wrong, this may happen for a non-continuous matrix. BadModelOrChSeq= -14, //!< - BadNumChannels= -15, //!< + BadNumChannels= -15, //!< bad number of channels, for example, some functions accept only single channel matrices. BadNumChannel1U= -16, //!< - BadDepth= -17, //!< + BadDepth= -17, //!< input image depth is not supported by the function BadAlphaChannel= -18, //!< - BadOrder= -19, //!< - BadOrigin= -20, //!< - BadAlign= -21, //!< + BadOrder= -19, //!< number of dimensions is out of range + BadOrigin= -20, //!< incorrect input origin + BadAlign= -21, //!< incorrect input align BadCallBack= -22, //!< BadTileSize= -23, //!< - BadCOI= -24, //!< - BadROISize= -25, //!< + BadCOI= -24, //!< input COI is not supported + BadROISize= -25, //!< incorrect input roi MaskIsTiled= -26, //!< StsNullPtr= -27, //!< null pointer StsVecLengthErr= -28, //!< incorrect vector length - StsFilterStructContentErr= -29, //!< incorr. filter structure content - StsKernelStructContentErr= -30, //!< incorr. transform kernel content - StsFilterOffsetErr= -31, //!< incorrect filter ofset value + StsFilterStructContentErr= -29, //!< incorrect filter structure content + StsKernelStructContentErr= -30, //!< incorrect transform kernel content + StsFilterOffsetErr= -31, //!< incorrect filter offset value StsBadSize= -201, //!< the input/output structure size is incorrect StsDivByZero= -202, //!< division by zero StsInplaceNotSupported= -203, //!< in-place operation is not supported @@ -111,13 +113,13 @@ enum Code { StsNotImplemented= -213, //!< the requested function/feature is not implemented StsBadMemBlock= -214, //!< an allocated block has been corrupted StsAssert= -215, //!< assertion failed - GpuNotSupported= -216, - GpuApiCallError= -217, - OpenGlNotSupported= -218, - OpenGlApiCallError= -219, - OpenCLApiCallError= -220, + GpuNotSupported= -216, //!< no CUDA support + GpuApiCallError= -217, //!< GPU API call error + OpenGlNotSupported= -218, //!< no OpenGL support + OpenGlApiCallError= -219, //!< OpenGL API call error + OpenCLApiCallError= -220, //!< OpenCL API call error OpenCLDoubleNotSupported= -221, - OpenCLInitError= -222, + OpenCLInitError= -222, //!< OpenCL initialization error OpenCLNoAMDBlasFft= -223 }; } //Error @@ -150,28 +152,57 @@ enum DecompTypes { }; /** norm types -- For one array: -\f[norm = \forkthree{\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM\_INF}\) } -{ \| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM\_L1}\) } -{ \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if \(\texttt{normType} = \texttt{NORM\_L2}\) }\f] -- Absolute norm for two arrays -\f[norm = \forkthree{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM\_INF}\) } -{ \| \texttt{src1} - \texttt{src2} \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM\_L1}\) } -{ \| \texttt{src1} - \texttt{src2} \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if \(\texttt{normType} = \texttt{NORM\_L2}\) }\f] +src1 and src2 denote input arrays. +*/ -- Relative norm for two arrays -\f[norm = \forkthree{\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} }{\|\texttt{src2}\|_{L_{\infty}} }}{if \(\texttt{normType} = \texttt{NORM\_RELATIVE\_INF}\) } -{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if \(\texttt{normType} = \texttt{NORM\_RELATIVE\_L1}\) } -{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if \(\texttt{normType} = \texttt{NORM\_RELATIVE\_L2}\) }\f] - */ -enum NormTypes { NORM_INF = 1, +enum NormTypes { + /** + \f[ + norm = \forkthree + {\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) } + {\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) } + {\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} }{\|\texttt{src2}\|_{L_{\infty}} }}{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_INF}\) } + \f] + */ + NORM_INF = 1, + /** + \f[ + norm = \forkthree + {\| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\)} + { \| \texttt{src1} - \texttt{src2} \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\) } + { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L1}\) } + \f]*/ NORM_L1 = 2, + /** + \f[ + norm = \forkthree + { \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) } + { \| \texttt{src1} - \texttt{src2} \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) } + { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L2}\) } + \f] + */ NORM_L2 = 4, + /** + \f[ + norm = \forkthree + { \| \texttt{src1} \| _{L_2} ^{2} = \sum_I \texttt{src1}(I)^2} {if \(\texttt{normType} = \texttt{NORM_L2SQR}\)} + { \| \texttt{src1} - \texttt{src2} \| _{L_2} ^{2} = \sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2 }{if \(\texttt{normType} = \texttt{NORM_L2SQR}\) } + { \left(\frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}}\right)^2 }{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L2}\) } + \f] + */ NORM_L2SQR = 5, + /** + In the case of one input array, calculates the Hamming distance of the array from zero, + In the case of two input arrays, calculates the Hamming distance between the arrays. + */ NORM_HAMMING = 6, + /** + Similar to NORM_HAMMING, but in the calculation, each two bits of the input sequence will + be added and treated as a single bit to be used in the same calculation as NORM_HAMMING. + */ NORM_HAMMING2 = 7, - NORM_TYPE_MASK = 7, + NORM_TYPE_MASK = 7, //!< bit-mask which can be used to separate norm type from norm flags NORM_RELATIVE = 8, //!< flag NORM_MINMAX = 32 //!< flag }; @@ -219,6 +250,10 @@ enum DftFlags { into a real array and inverse transformation is executed, the function treats the input as a packed complex-conjugate symmetrical array, and the output will also be a real array). */ DFT_REAL_OUTPUT = 32, + /** specifies that input is complex input. If this flag is set, the input must have 2 channels. + On the other hand, for backwards compatibility reason, if input has 2 channels, input is + already considered complex. */ + DFT_COMPLEX_INPUT = 64, /** performs an inverse 1D or 2D transform instead of the default forward transform. */ DCT_INVERSE = DFT_INVERSE, /** performs a forward or inverse transform of every individual row of the input @@ -236,7 +271,7 @@ enum BorderTypes { BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb` BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg` BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba` - BORDER_TRANSPARENT = 5, //!< `uvwxyz|absdefgh|ijklmno` + BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno` BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 @@ -248,65 +283,6 @@ enum BorderTypes { //! @addtogroup core_utils //! @{ -//! @cond IGNORED - -//////////////// static assert ///////////////// -#define CVAUX_CONCAT_EXP(a, b) a##b -#define CVAUX_CONCAT(a, b) CVAUX_CONCAT_EXP(a,b) - -#if defined(__clang__) -# ifndef __has_extension -# define __has_extension __has_feature /* compatibility, for older versions of clang */ -# endif -# if __has_extension(cxx_static_assert) -# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) -# endif -#elif defined(__GNUC__) -# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) -# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) -# endif -#elif defined(_MSC_VER) -# if _MSC_VER >= 1600 /* MSVC 10 */ -# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) -# endif -#endif -#ifndef CV_StaticAssert -# if defined(__GNUC__) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) -# define CV_StaticAssert(condition, reason) ({ extern int __attribute__((error("CV_StaticAssert: " reason " " #condition))) CV_StaticAssert(); ((condition) ? 0 : CV_StaticAssert()); }) -# else - template struct CV_StaticAssert_failed; - template <> struct CV_StaticAssert_failed { enum { val = 1 }; }; - template struct CV_StaticAssert_test {}; -# define CV_StaticAssert(condition, reason)\ - typedef cv::CV_StaticAssert_test< sizeof(cv::CV_StaticAssert_failed< static_cast(condition) >) > CVAUX_CONCAT(CV_StaticAssert_failed_at_, __LINE__) -# endif -#endif - -// Suppress warning "-Wdeprecated-declarations" / C4996 -#if defined(_MSC_VER) - #define CV_DO_PRAGMA(x) __pragma(x) -#elif defined(__GNUC__) - #define CV_DO_PRAGMA(x) _Pragma (#x) -#else - #define CV_DO_PRAGMA(x) -#endif - -#ifdef _MSC_VER -#define CV_SUPPRESS_DEPRECATED_START \ - CV_DO_PRAGMA(warning(push)) \ - CV_DO_PRAGMA(warning(disable: 4996)) -#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(warning(pop)) -#elif defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) -#define CV_SUPPRESS_DEPRECATED_START \ - CV_DO_PRAGMA(GCC diagnostic push) \ - CV_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") -#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(GCC diagnostic pop) -#else -#define CV_SUPPRESS_DEPRECATED_START -#define CV_SUPPRESS_DEPRECATED_END -#endif -//! @endcond - /*! @brief Signals an error and raises the exception. By default the function prints information about the error to stderr, @@ -315,9 +291,9 @@ It is possible to alternate error processing by using redirectError(). @param _code - error code (Error::Code) @param _err - error description @param _func - function name. Available only when the compiler supports getting it -@param _file - source file name where the error has occured -@param _line - line number in the source file where the error has occured -@see CV_Error, CV_Error_, CV_ErrorNoReturn, CV_ErrorNoReturn_, CV_Assert, CV_DbgAssert +@param _file - source file name where the error has occurred +@param _line - line number in the source file where the error has occurred +@see CV_Error, CV_Error_, CV_Assert, CV_DbgAssert */ CV_EXPORTS void error(int _code, const String& _err, const char* _func, const char* _file, int _line); @@ -346,13 +322,17 @@ CV_INLINE CV_NORETURN void errorNoReturn(int _code, const String& _err, const ch # endif #endif -#if defined __GNUC__ -#define CV_Func __func__ -#elif defined _MSC_VER -#define CV_Func __FUNCTION__ -#else -#define CV_Func "" -#endif +#ifdef CV_STATIC_ANALYSIS + +// In practice, some macro are not processed correctly (noreturn is not detected). +// We need to use simplified definition for them. +#define CV_Error(...) do { abort(); } while (0) +#define CV_Error_( code, args ) do { cv::format args; abort(); } while (0) +#define CV_Assert( expr ) do { if (!(expr)) abort(); } while (0) +#define CV_ErrorNoReturn CV_Error +#define CV_ErrorNoReturn_ CV_Error_ + +#else // CV_STATIC_ANALYSIS /** @brief Call the error handler. @@ -372,7 +352,7 @@ This macro can be used to construct an error message on-fly to include some dyna for example: @code // note the extra parentheses around the formatted text message - CV_Error_( CV_StsOutOfRange, + CV_Error_(Error::StsOutOfRange, ("the value at (%d, %d)=%g is out of range", badPt.x, badPt.y, badValue)); @endcode @param code one of Error::Code @@ -386,18 +366,61 @@ The macros CV_Assert (and CV_DbgAssert(expr)) evaluate the specified expression. raise an error (see cv::error). The macro CV_Assert checks the condition in both Debug and Release configurations while CV_DbgAssert is only retained in the Debug configuration. */ -#define CV_Assert( expr ) if(!!(expr)) ; else cv::error( cv::Error::StsAssert, #expr, CV_Func, __FILE__, __LINE__ ) +#define CV_Assert( expr ) do { if(!!(expr)) ; else cv::error( cv::Error::StsAssert, #expr, CV_Func, __FILE__, __LINE__ ); } while(0) -/** same as CV_Error(code,msg), but does not return */ -#define CV_ErrorNoReturn( code, msg ) cv::errorNoReturn( code, msg, CV_Func, __FILE__, __LINE__ ) +//! @cond IGNORED +#define CV__ErrorNoReturn( code, msg ) cv::errorNoReturn( code, msg, CV_Func, __FILE__, __LINE__ ) +#define CV__ErrorNoReturn_( code, args ) cv::errorNoReturn( code, cv::format args, CV_Func, __FILE__, __LINE__ ) +#ifdef __OPENCV_BUILD +#undef CV_Error +#define CV_Error CV__ErrorNoReturn +#undef CV_Error_ +#define CV_Error_ CV__ErrorNoReturn_ +#undef CV_Assert +#define CV_Assert( expr ) do { if(!!(expr)) ; else cv::errorNoReturn( cv::Error::StsAssert, #expr, CV_Func, __FILE__, __LINE__ ); } while(0) +#else +// backward compatibility +#define CV_ErrorNoReturn CV__ErrorNoReturn +#define CV_ErrorNoReturn_ CV__ErrorNoReturn_ +#endif +//! @endcond -/** same as CV_Error_(code,args), but does not return */ -#define CV_ErrorNoReturn_( code, args ) cv::errorNoReturn( code, cv::format args, CV_Func, __FILE__, __LINE__ ) +#endif // CV_STATIC_ANALYSIS -/** replaced with CV_Assert(expr) in Debug configuration */ -#ifdef _DEBUG +//! @cond IGNORED + +#if defined OPENCV_FORCE_MULTIARG_ASSERT_CHECK && defined CV_STATIC_ANALYSIS +#warning "OPENCV_FORCE_MULTIARG_ASSERT_CHECK can't be used with CV_STATIC_ANALYSIS" +#undef OPENCV_FORCE_MULTIARG_ASSERT_CHECK +#endif + +#ifdef OPENCV_FORCE_MULTIARG_ASSERT_CHECK +#define CV_Assert_1( expr ) do { if(!!(expr)) ; else cv::error( cv::Error::StsAssert, #expr, CV_Func, __FILE__, __LINE__ ); } while(0) +#else +#define CV_Assert_1 CV_Assert +#endif +#define CV_Assert_2( expr1, expr2 ) CV_Assert_1(expr1); CV_Assert_1(expr2) +#define CV_Assert_3( expr1, expr2, expr3 ) CV_Assert_2(expr1, expr2); CV_Assert_1(expr3) +#define CV_Assert_4( expr1, expr2, expr3, expr4 ) CV_Assert_3(expr1, expr2, expr3); CV_Assert_1(expr4) +#define CV_Assert_5( expr1, expr2, expr3, expr4, expr5 ) CV_Assert_4(expr1, expr2, expr3, expr4); CV_Assert_1(expr5) +#define CV_Assert_6( expr1, expr2, expr3, expr4, expr5, expr6 ) CV_Assert_5(expr1, expr2, expr3, expr4, expr5); CV_Assert_1(expr6) +#define CV_Assert_7( expr1, expr2, expr3, expr4, expr5, expr6, expr7 ) CV_Assert_6(expr1, expr2, expr3, expr4, expr5, expr6 ); CV_Assert_1(expr7) +#define CV_Assert_8( expr1, expr2, expr3, expr4, expr5, expr6, expr7, expr8 ) CV_Assert_7(expr1, expr2, expr3, expr4, expr5, expr6, expr7 ); CV_Assert_1(expr8) +#define CV_Assert_9( expr1, expr2, expr3, expr4, expr5, expr6, expr7, expr8, expr9 ) CV_Assert_8(expr1, expr2, expr3, expr4, expr5, expr6, expr7, expr8 ); CV_Assert_1(expr9) +#define CV_Assert_10( expr1, expr2, expr3, expr4, expr5, expr6, expr7, expr8, expr9, expr10 ) CV_Assert_9(expr1, expr2, expr3, expr4, expr5, expr6, expr7, expr8, expr9 ); CV_Assert_1(expr10) + +#define CV_Assert_N(...) do { __CV_CAT(CV_Assert_, __CV_VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__); } while(0) + +#ifdef OPENCV_FORCE_MULTIARG_ASSERT_CHECK +#undef CV_Assert +#define CV_Assert CV_Assert_N +#endif +//! @endcond + +#if defined _DEBUG || defined CV_STATIC_ANALYSIS # define CV_DbgAssert(expr) CV_Assert(expr) #else +/** replaced with CV_Assert(expr) in Debug configuration */ # define CV_DbgAssert(expr) #endif @@ -644,12 +667,27 @@ namespace cudev namespace ipp { -CV_EXPORTS void setIppStatus(int status, const char * const funcname = NULL, const char * const filename = NULL, +#if OPENCV_ABI_COMPATIBILITY > 300 +CV_EXPORTS unsigned long long getIppFeatures(); +#else +CV_EXPORTS int getIppFeatures(); +#endif +CV_EXPORTS void setIppStatus(int status, const char * const funcname = NULL, const char * const filename = NULL, int line = 0); -CV_EXPORTS int getIppStatus(); -CV_EXPORTS String getIppErrorLocation(); -CV_EXPORTS bool useIPP(); -CV_EXPORTS void setUseIPP(bool flag); +CV_EXPORTS int getIppStatus(); +CV_EXPORTS String getIppErrorLocation(); +CV_EXPORTS_W bool useIPP(); +CV_EXPORTS_W void setUseIPP(bool flag); +CV_EXPORTS_W String getIppVersion(); + +// IPP Not-Exact mode. This function may force use of IPP then both IPP and OpenCV provide proper results +// but have internal accuracy differences which have too much direct or indirect impact on accuracy tests. +CV_EXPORTS_W bool useIPP_NotExact(); +CV_EXPORTS_W void setUseIPP_NotExact(bool flag); +#if OPENCV_ABI_COMPATIBILITY < 400 +CV_EXPORTS_W bool useIPP_NE(); +CV_EXPORTS_W void setUseIPP_NE(bool flag); +#endif } // ipp @@ -657,89 +695,13 @@ CV_EXPORTS void setUseIPP(bool flag); //! @} core_utils -//! @addtogroup core_utils_neon -//! @{ -#if CV_NEON -inline int32x2_t cv_vrnd_s32_f32(float32x2_t v) -{ - static int32x2_t v_sign = vdup_n_s32(1 << 31), - v_05 = vreinterpret_s32_f32(vdup_n_f32(0.5f)); - - int32x2_t v_addition = vorr_s32(v_05, vand_s32(v_sign, vreinterpret_s32_f32(v))); - return vcvt_s32_f32(vadd_f32(v, vreinterpret_f32_s32(v_addition))); -} - -inline int32x4_t cv_vrndq_s32_f32(float32x4_t v) -{ - static int32x4_t v_sign = vdupq_n_s32(1 << 31), - v_05 = vreinterpretq_s32_f32(vdupq_n_f32(0.5f)); - - int32x4_t v_addition = vorrq_s32(v_05, vandq_s32(v_sign, vreinterpretq_s32_f32(v))); - return vcvtq_s32_f32(vaddq_f32(v, vreinterpretq_f32_s32(v_addition))); -} - -inline uint32x2_t cv_vrnd_u32_f32(float32x2_t v) -{ - static float32x2_t v_05 = vdup_n_f32(0.5f); - return vcvt_u32_f32(vadd_f32(v, v_05)); -} - -inline uint32x4_t cv_vrndq_u32_f32(float32x4_t v) -{ - static float32x4_t v_05 = vdupq_n_f32(0.5f); - return vcvtq_u32_f32(vaddq_f32(v, v_05)); -} - -inline float32x4_t cv_vrecpq_f32(float32x4_t val) -{ - float32x4_t reciprocal = vrecpeq_f32(val); - reciprocal = vmulq_f32(vrecpsq_f32(val, reciprocal), reciprocal); - reciprocal = vmulq_f32(vrecpsq_f32(val, reciprocal), reciprocal); - return reciprocal; -} - -inline float32x2_t cv_vrecp_f32(float32x2_t val) -{ - float32x2_t reciprocal = vrecpe_f32(val); - reciprocal = vmul_f32(vrecps_f32(val, reciprocal), reciprocal); - reciprocal = vmul_f32(vrecps_f32(val, reciprocal), reciprocal); - return reciprocal; -} - -inline float32x4_t cv_vrsqrtq_f32(float32x4_t val) -{ - float32x4_t e = vrsqrteq_f32(val); - e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(e, e), val), e); - e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(e, e), val), e); - return e; -} - -inline float32x2_t cv_vrsqrt_f32(float32x2_t val) -{ - float32x2_t e = vrsqrte_f32(val); - e = vmul_f32(vrsqrts_f32(vmul_f32(e, e), val), e); - e = vmul_f32(vrsqrts_f32(vmul_f32(e, e), val), e); - return e; -} - -inline float32x4_t cv_vsqrtq_f32(float32x4_t val) -{ - return cv_vrecpq_f32(cv_vrsqrtq_f32(val)); -} - -inline float32x2_t cv_vsqrt_f32(float32x2_t val) -{ - return cv_vrecp_f32(cv_vrsqrt_f32(val)); -} - -#endif - -//! @} core_utils_neon } // cv -#include "sse_utils.hpp" +#include "opencv2/core/neon_utils.hpp" +#include "opencv2/core/vsx_utils.hpp" +#include "opencv2/core/check.hpp" -#endif //__OPENCV_CORE_BASE_HPP__ +#endif //OPENCV_CORE_BASE_HPP diff --git a/include/opencv2/core/bindings_utils.hpp b/include/opencv2/core/bindings_utils.hpp new file mode 100644 index 0000000..c1123f2 --- /dev/null +++ b/include/opencv2/core/bindings_utils.hpp @@ -0,0 +1,23 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_BINDINGS_UTILS_HPP +#define OPENCV_CORE_BINDINGS_UTILS_HPP + +namespace cv { namespace utils { +//! @addtogroup core_utils +//! @{ + +CV_EXPORTS_W String dumpInputArray(InputArray argument); + +CV_EXPORTS_W String dumpInputArrayOfArrays(InputArrayOfArrays argument); + +CV_EXPORTS_W String dumpInputOutputArray(InputOutputArray argument); + +CV_EXPORTS_W String dumpInputOutputArrayOfArrays(InputOutputArrayOfArrays argument); + +//! @} +}} // namespace + +#endif // OPENCV_CORE_BINDINGS_UTILS_HPP diff --git a/include/opencv2/core/bufferpool.hpp b/include/opencv2/core/bufferpool.hpp index 76df2d2..4698e5d 100644 --- a/include/opencv2/core/bufferpool.hpp +++ b/include/opencv2/core/bufferpool.hpp @@ -4,8 +4,13 @@ // // Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved. -#ifndef __OPENCV_CORE_BUFFER_POOL_HPP__ -#define __OPENCV_CORE_BUFFER_POOL_HPP__ +#ifndef OPENCV_CORE_BUFFER_POOL_HPP +#define OPENCV_CORE_BUFFER_POOL_HPP + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4265) +#endif namespace cv { @@ -28,4 +33,8 @@ public: } -#endif // __OPENCV_CORE_BUFFER_POOL_HPP__ +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // OPENCV_CORE_BUFFER_POOL_HPP diff --git a/include/opencv2/core/check.hpp b/include/opencv2/core/check.hpp new file mode 100644 index 0000000..bf44138 --- /dev/null +++ b/include/opencv2/core/check.hpp @@ -0,0 +1,157 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_CHECK_HPP +#define OPENCV_CORE_CHECK_HPP + +#include + +namespace cv { + +/** Returns string of cv::Mat depth value: CV_8U -> "CV_8U" or "" */ +CV_EXPORTS const char* depthToString(int depth); + +/** Returns string of cv::Mat depth value: CV_8UC3 -> "CV_8UC3" or "" */ +CV_EXPORTS const String typeToString(int type); + + +//! @cond IGNORED +namespace detail { + +/** Returns string of cv::Mat depth value: CV_8U -> "CV_8U" or NULL */ +CV_EXPORTS const char* depthToString_(int depth); + +/** Returns string of cv::Mat depth value: CV_8UC3 -> "CV_8UC3" or cv::String() */ +CV_EXPORTS const cv::String typeToString_(int type); + +enum TestOp { + TEST_CUSTOM = 0, + TEST_EQ = 1, + TEST_NE = 2, + TEST_LE = 3, + TEST_LT = 4, + TEST_GE = 5, + TEST_GT = 6, + CV__LAST_TEST_OP +}; + +struct CheckContext { + const char* func; + const char* file; + int line; + enum TestOp testOp; + const char* message; + const char* p1_str; + const char* p2_str; +}; + +#ifndef CV__CHECK_FILENAME +# define CV__CHECK_FILENAME __FILE__ +#endif + +#ifndef CV__CHECK_FUNCTION +# if defined _MSC_VER +# define CV__CHECK_FUNCTION __FUNCSIG__ +# elif defined __GNUC__ +# define CV__CHECK_FUNCTION __PRETTY_FUNCTION__ +# else +# define CV__CHECK_FUNCTION "" +# endif +#endif + +#define CV__CHECK_LOCATION_VARNAME(id) CVAUX_CONCAT(CVAUX_CONCAT(__cv_check_, id), __LINE__) +#define CV__DEFINE_CHECK_CONTEXT(id, message, testOp, p1_str, p2_str) \ + static const cv::detail::CheckContext CV__CHECK_LOCATION_VARNAME(id) = \ + { CV__CHECK_FUNCTION, CV__CHECK_FILENAME, __LINE__, testOp, message, p1_str, p2_str } + +CV_EXPORTS void CV_NORETURN check_failed_auto(const int v1, const int v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const size_t v1, const size_t v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const float v1, const float v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const double v1, const double v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatDepth(const int v1, const int v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatType(const int v1, const int v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatChannels(const int v1, const int v2, const CheckContext& ctx); + +CV_EXPORTS void CV_NORETURN check_failed_auto(const int v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const size_t v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const float v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const double v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatDepth(const int v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatType(const int v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatChannels(const int v, const CheckContext& ctx); + + +#define CV__TEST_EQ(v1, v2) ((v1) == (v2)) +#define CV__TEST_NE(v1, v2) ((v1) != (v2)) +#define CV__TEST_LE(v1, v2) ((v1) <= (v2)) +#define CV__TEST_LT(v1, v2) ((v1) < (v2)) +#define CV__TEST_GE(v1, v2) ((v1) >= (v2)) +#define CV__TEST_GT(v1, v2) ((v1) > (v2)) + +#define CV__CHECK(id, op, type, v1, v2, v1_str, v2_str, msg_str) do { \ + if(CV__TEST_##op((v1), (v2))) ; else { \ + CV__DEFINE_CHECK_CONTEXT(id, msg_str, cv::detail::TEST_ ## op, v1_str, v2_str); \ + cv::detail::check_failed_ ## type((v1), (v2), CV__CHECK_LOCATION_VARNAME(id)); \ + } \ +} while (0) + +#define CV__CHECK_CUSTOM_TEST(id, type, v, test_expr, v_str, test_expr_str, msg_str) do { \ + if(!!(test_expr)) ; else { \ + CV__DEFINE_CHECK_CONTEXT(id, msg_str, cv::detail::TEST_CUSTOM, v_str, test_expr_str); \ + cv::detail::check_failed_ ## type((v), CV__CHECK_LOCATION_VARNAME(id)); \ + } \ +} while (0) + +} // namespace +//! @endcond + + +/// Supported values of these types: int, float, double +#define CV_CheckEQ(v1, v2, msg) CV__CHECK(_, EQ, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckNE(v1, v2, msg) CV__CHECK(_, NE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckLE(v1, v2, msg) CV__CHECK(_, LE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckLT(v1, v2, msg) CV__CHECK(_, LT, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckGE(v1, v2, msg) CV__CHECK(_, GE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckGT(v1, v2, msg) CV__CHECK(_, GT, auto, v1, v2, #v1, #v2, msg) + +/// Check with additional "decoding" of type values in error message +#define CV_CheckTypeEQ(t1, t2, msg) CV__CHECK(_, EQ, MatType, t1, t2, #t1, #t2, msg) +/// Check with additional "decoding" of depth values in error message +#define CV_CheckDepthEQ(d1, d2, msg) CV__CHECK(_, EQ, MatDepth, d1, d2, #d1, #d2, msg) + +#define CV_CheckChannelsEQ(c1, c2, msg) CV__CHECK(_, EQ, MatChannels, c1, c2, #c1, #c2, msg) + +/// Example: type == CV_8UC1 || type == CV_8UC3 +#define CV_CheckType(t, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, MatType, t, (test_expr), #t, #test_expr, msg) + +/// Example: depth == CV_32F || depth == CV_64F +#define CV_CheckDepth(t, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, MatDepth, t, (test_expr), #t, #test_expr, msg) + +/// Example: v == A || v == B +#define CV_Check(v, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, auto, v, (test_expr), #v, #test_expr, msg) + +/// Some complex conditions: CV_Check(src2, src2.empty() || (src2.type() == src1.type() && src2.size() == src1.size()), "src2 should have same size/type as src1") +// TODO define pretty-printers + +#ifndef NDEBUG +#define CV_DbgCheck(v, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, auto, v, (test_expr), #v, #test_expr, msg) +#define CV_DbgCheckEQ(v1, v2, msg) CV__CHECK(_, EQ, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckNE(v1, v2, msg) CV__CHECK(_, NE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckLE(v1, v2, msg) CV__CHECK(_, LE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckLT(v1, v2, msg) CV__CHECK(_, LT, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckGE(v1, v2, msg) CV__CHECK(_, GE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckGT(v1, v2, msg) CV__CHECK(_, GT, auto, v1, v2, #v1, #v2, msg) +#else +#define CV_DbgCheck(v, test_expr, msg) do { } while (0) +#define CV_DbgCheckEQ(v1, v2, msg) do { } while (0) +#define CV_DbgCheckNE(v1, v2, msg) do { } while (0) +#define CV_DbgCheckLE(v1, v2, msg) do { } while (0) +#define CV_DbgCheckLT(v1, v2, msg) do { } while (0) +#define CV_DbgCheckGE(v1, v2, msg) do { } while (0) +#define CV_DbgCheckGT(v1, v2, msg) do { } while (0) +#endif + +} // namespace + +#endif // OPENCV_CORE_CHECK_HPP diff --git a/include/opencv2/core/core_c.h b/include/opencv2/core/core_c.h index a0ed632..e5fe516 100644 --- a/include/opencv2/core/core_c.h +++ b/include/opencv2/core/core_c.h @@ -42,8 +42,8 @@ //M*/ -#ifndef __OPENCV_CORE_C_H__ -#define __OPENCV_CORE_C_H__ +#ifndef OPENCV_CORE_C_H +#define OPENCV_CORE_C_H #include "opencv2/core/types_c.h" @@ -359,7 +359,7 @@ CVAPI(CvMat*) cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect ); /** @brief Returns array row or row span. -The functions return the header, corresponding to a specified row/row span of the input array. +The function returns the header, corresponding to a specified row/row span of the input array. cvGetRow(arr, submat, row) is a shortcut for cvGetRows(arr, submat, row, row+1). @param arr Input array @param submat Pointer to the resulting sub-array header @@ -385,7 +385,7 @@ CV_INLINE CvMat* cvGetRow( const CvArr* arr, CvMat* submat, int row ) /** @brief Returns one of more array columns. -The functions return the header, corresponding to a specified column span of the input array. That +The function returns the header, corresponding to a specified column span of the input array. That is, no data is copied. Therefore, any modifications of the submatrix will affect the original array. If you need to copy the columns, use cvCloneMat. cvGetCol(arr, submat, col) is a shortcut for @@ -1788,7 +1788,7 @@ CVAPI(int) cvGraphRemoveVtx( CvGraph* graph, int index ); CVAPI(int) cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx ); -/** Link two vertices specifed by indices or pointers if they +/** Link two vertices specified by indices or pointers if they are not connected or return pointer to already existing edge connecting the vertices. Functions return 1 if a new edge was created, 0 otherwise */ @@ -1976,8 +1976,12 @@ CVAPI(void) cvSetIPLAllocators( Cv_iplCreateImageHeader create_header, The function opens file storage for reading or writing data. In the latter case, a new file is created or an existing file is rewritten. The type of the read or written file is determined by the -filename extension: .xml for XML and .yml or .yaml for YAML. The function returns a pointer to the -CvFileStorage structure. If the file cannot be opened then the function returns NULL. +filename extension: .xml for XML, .yml or .yaml for YAML and .json for JSON. + +At the same time, it also supports adding parameters like "example.xml?base64". + +The function returns a pointer to the CvFileStorage structure. +If the file cannot be opened then the function returns NULL. @param filename Name of the file associated with the storage @param memstorage Memory storage used for temporary data and for : storing dynamic structures, such as CvSeq or CvGraph . If it is NULL, a temporary memory @@ -1985,6 +1989,7 @@ CvFileStorage structure. If the file cannot be opened then the function returns @param flags Can be one of the following: > - **CV_STORAGE_READ** the storage is open for reading > - **CV_STORAGE_WRITE** the storage is open for writing + (use **CV_STORAGE_WRITE | CV_STORAGE_WRITE_BASE64** to write rawdata in Base64) @param encoding */ CVAPI(CvFileStorage*) cvOpenFileStorage( const char* filename, CvMemStorage* memstorage, @@ -2022,7 +2027,8 @@ One and only one of the two above flags must be specified @param type_name Optional parameter - the object type name. In case of XML it is written as a type_id attribute of the structure opening tag. In the case of YAML it is written after a colon following the structure name (see the example in - CvFileStorage description). Mainly it is used with user objects. When the storage is read, the + CvFileStorage description). In case of JSON it is written as a name/value pair. + Mainly it is used with user objects. When the storage is read, the encoded type name is used to determine the object type (see CvTypeInfo and cvFindType ). @param attributes This parameter is not used in the current implementation */ @@ -2162,7 +2168,7 @@ the file with multiple streams looks like this: @endcode The YAML file will look like this: @code{.yaml} - %YAML:1.0 + %YAML 1.0 # stream #1 data ... --- @@ -2187,6 +2193,23 @@ to a sequence rather than a map. CVAPI(void) cvWriteRawData( CvFileStorage* fs, const void* src, int len, const char* dt ); +/** @brief Writes multiple numbers in Base64. + +If either CV_STORAGE_WRITE_BASE64 or cv::FileStorage::WRITE_BASE64 is used, +this function will be the same as cvWriteRawData. If neither, the main +difference is that it outputs a sequence in Base64 encoding rather than +in plain text. + +This function can only be used to write a sequence with a type "binary". + +@param fs File storage +@param src Pointer to the written array +@param len Number of the array elements to write +@param dt Specification of each array element, see @ref format_spec "format specification" +*/ +CVAPI(void) cvWriteRawDataBase64( CvFileStorage* fs, const void* src, + int len, const char* dt ); + /** @brief Returns a unique pointer for a given name. The function returns a unique pointer for each particular file node name. This pointer can be then @@ -2468,7 +2491,7 @@ CVAPI(void) cvReadRawData( const CvFileStorage* fs, const CvFileNode* src, /** @brief Writes a file node to another file storage. The function writes a copy of a file node to file storage. Possible applications of the function are -merging several file storages into one and conversion between XML and YAML formats. +merging several file storages into one and conversion between XML, YAML and JSON formats. @param fs Destination file storage @param new_node_name New name of the file node in the destination file storage. To keep the existing name, use cvcvGetFileNodeName @@ -2616,13 +2639,13 @@ CVAPI(void) cvSetErrStatus( int status ); #define CV_ErrModeParent 1 /* Print error and continue */ #define CV_ErrModeSilent 2 /* Don't print and continue */ -/** Retrives current error processing mode */ +/** Retrieves current error processing mode */ CVAPI(int) cvGetErrMode( void ); /** Sets error processing mode, returns previously used mode */ CVAPI(int) cvSetErrMode( int mode ); -/** Sets error status and performs some additonal actions (displaying message box, +/** Sets error status and performs some additional actions (displaying message box, writing message to stderr, terminating application etc.) depending on the current error mode */ CVAPI(void) cvError( int status, const char* func_name, @@ -2631,7 +2654,7 @@ CVAPI(void) cvError( int status, const char* func_name, /** Retrieves textual description of the error given its code */ CVAPI(const char*) cvErrorStr( int status ); -/** Retrieves detailed information about the last error occured */ +/** Retrieves detailed information about the last error occurred */ CVAPI(int) cvGetErrInfo( const char** errcode_desc, const char** description, const char** filename, int* line ); @@ -2706,7 +2729,7 @@ static char cvFuncName[] = Name /** CV_CALL macro calls CV (or IPL) function, checks error status and signals a error if the function failed. Useful in "parent node" - error procesing mode + error processing mode */ #define CV_CALL( Func ) \ { \ @@ -3041,7 +3064,7 @@ template inline void Seq<_Tp>::copyTo(std::vector<_Tp>& vec, const size_t len = !seq ? 0 : range == Range::all() ? seq->total : range.end - range.start; vec.resize(len); if( seq && len ) - cvCvtSeqToArray(seq, &vec[0], range); + cvCvtSeqToArray(seq, &vec[0], cvSlice(range)); } template inline Seq<_Tp>::operator std::vector<_Tp>() const diff --git a/include/opencv2/core/cuda.hpp b/include/opencv2/core/cuda.hpp index a9c7a39..820aba7 100644 --- a/include/opencv2/core/cuda.hpp +++ b/include/opencv2/core/cuda.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CORE_CUDA_HPP__ -#define __OPENCV_CORE_CUDA_HPP__ +#ifndef OPENCV_CORE_CUDA_HPP +#define OPENCV_CORE_CUDA_HPP #ifndef __cplusplus # error cuda.hpp header must be compiled as C++ @@ -56,7 +56,7 @@ @{ @defgroup cudacore Core part @{ - @defgroup cudacore_init Initalization and Information + @defgroup cudacore_init Initialization and Information @defgroup cudacore_struct Data Structures @} @} @@ -91,6 +91,15 @@ aligned to a size depending on the hardware. Single-row GpuMat is always a conti on its destructor. The destruction order of such variables and CUDA context is undefined. GPU memory release function returns error if the CUDA context has been destroyed before. +Some member functions are described as a "Blocking Call" while some are described as a +"Non-Blocking Call". Blocking functions are synchronous to host. It is guaranteed that the GPU +operation is finished when the function returns. However, non-blocking functions are asynchronous to +host. Those functions may return even if the GPU operation is not finished. + +Compared to their blocking counterpart, non-blocking functions accept Stream as an additional +argument. If a non-default stream is passed, the GPU operation may overlap with operations in other +streams. + @sa Mat */ class CV_EXPORTS GpuMat @@ -151,16 +160,38 @@ public: //! swaps with other smart pointer void swap(GpuMat& mat); - //! pefroms upload data to GpuMat (Blocking call) + /** @brief Performs data upload to GpuMat (Blocking call) + + This function copies data from host memory to device memory. As being a blocking call, it is + guaranteed that the copy operation is finished when this function returns. + */ void upload(InputArray arr); - //! pefroms upload data to GpuMat (Non-Blocking call) + /** @brief Performs data upload to GpuMat (Non-Blocking call) + + This function copies data from host memory to device memory. As being a non-blocking call, this + function may return even if the copy operation is not finished. + + The copy operation may be overlapped with operations in other non-default streams if \p stream is + not the default stream and \p dst is HostMem allocated with HostMem::PAGE_LOCKED option. + */ void upload(InputArray arr, Stream& stream); - //! pefroms download data from device to host memory (Blocking call) + /** @brief Performs data download from GpuMat (Blocking call) + + This function copies data from device memory to host memory. As being a blocking call, it is + guaranteed that the copy operation is finished when this function returns. + */ void download(OutputArray dst) const; - //! pefroms download data from device to host memory (Non-Blocking call) + /** @brief Performs data download from GpuMat (Non-Blocking call) + + This function copies data from device memory to host memory. As being a non-blocking call, this + function may return even if the copy operation is not finished. + + The copy operation may be overlapped with operations in other non-default streams if \p stream is + not the default stream and \p dst is HostMem allocated with HostMem::PAGE_LOCKED option. + */ void download(OutputArray dst, Stream& stream) const; //! returns deep copy of the GpuMat, i.e. the data is copied @@ -274,6 +305,9 @@ public: //! returns true if GpuMat data is NULL bool empty() const; + //! internal use method: updates the continuity flag + void updateContinuityFlag(); + /*! includes several bit-fields: - the magic signature - continuity flag @@ -327,6 +361,143 @@ The function does not reallocate memory if the matrix has proper attributes alre */ CV_EXPORTS void ensureSizeIsEnough(int rows, int cols, int type, OutputArray arr); +/** @brief BufferPool for use with CUDA streams + +BufferPool utilizes Stream's allocator to create new buffers for GpuMat's. It is +only useful when enabled with #setBufferPoolUsage. + +@code + setBufferPoolUsage(true); +@endcode + +@note #setBufferPoolUsage must be called \em before any Stream declaration. + +Users may specify custom allocator for Stream and may implement their own stream based +functions utilizing the same underlying GPU memory management. + +If custom allocator is not specified, BufferPool utilizes StackAllocator by +default. StackAllocator allocates a chunk of GPU device memory beforehand, +and when GpuMat is declared later on, it is given the pre-allocated memory. +This kind of strategy reduces the number of calls for memory allocating APIs +such as cudaMalloc or cudaMallocPitch. + +Below is an example that utilizes BufferPool with StackAllocator: + +@code + #include + + using namespace cv; + using namespace cv::cuda + + int main() + { + setBufferPoolUsage(true); // Tell OpenCV that we are going to utilize BufferPool + setBufferPoolConfig(getDevice(), 1024 * 1024 * 64, 2); // Allocate 64 MB, 2 stacks (default is 10 MB, 5 stacks) + + Stream stream1, stream2; // Each stream uses 1 stack + BufferPool pool1(stream1), pool2(stream2); + + GpuMat d_src1 = pool1.getBuffer(4096, 4096, CV_8UC1); // 16MB + GpuMat d_dst1 = pool1.getBuffer(4096, 4096, CV_8UC3); // 48MB, pool1 is now full + + GpuMat d_src2 = pool2.getBuffer(1024, 1024, CV_8UC1); // 1MB + GpuMat d_dst2 = pool2.getBuffer(1024, 1024, CV_8UC3); // 3MB + + cvtColor(d_src1, d_dst1, CV_GRAY2BGR, 0, stream1); + cvtColor(d_src2, d_dst2, CV_GRAY2BGR, 0, stream2); + } +@endcode + +If we allocate another GpuMat on pool1 in the above example, it will be carried out by +the DefaultAllocator since the stack for pool1 is full. + +@code + GpuMat d_add1 = pool1.getBuffer(1024, 1024, CV_8UC1); // Stack for pool1 is full, memory is allocated with DefaultAllocator +@endcode + +If a third stream is declared in the above example, allocating with #getBuffer +within that stream will also be carried out by the DefaultAllocator because we've run out of +stacks. + +@code + Stream stream3; // Only 2 stacks were allocated, we've run out of stacks + BufferPool pool3(stream3); + GpuMat d_src3 = pool3.getBuffer(1024, 1024, CV_8UC1); // Memory is allocated with DefaultAllocator +@endcode + +@warning When utilizing StackAllocator, deallocation order is important. + +Just like a stack, deallocation must be done in LIFO order. Below is an example of +erroneous usage that violates LIFO rule. If OpenCV is compiled in Debug mode, this +sample code will emit CV_Assert error. + +@code + int main() + { + setBufferPoolUsage(true); // Tell OpenCV that we are going to utilize BufferPool + Stream stream; // A default size (10 MB) stack is allocated to this stream + BufferPool pool(stream); + + GpuMat mat1 = pool.getBuffer(1024, 1024, CV_8UC1); // Allocate mat1 (1MB) + GpuMat mat2 = pool.getBuffer(1024, 1024, CV_8UC1); // Allocate mat2 (1MB) + + mat1.release(); // erroneous usage : mat2 must be deallocated before mat1 + } +@endcode + +Since C++ local variables are destroyed in the reverse order of construction, +the code sample below satisfies the LIFO rule. Local GpuMat's are deallocated +and the corresponding memory is automatically returned to the pool for later usage. + +@code + int main() + { + setBufferPoolUsage(true); // Tell OpenCV that we are going to utilize BufferPool + setBufferPoolConfig(getDevice(), 1024 * 1024 * 64, 2); // Allocate 64 MB, 2 stacks (default is 10 MB, 5 stacks) + + Stream stream1, stream2; // Each stream uses 1 stack + BufferPool pool1(stream1), pool2(stream2); + + for (int i = 0; i < 10; i++) + { + GpuMat d_src1 = pool1.getBuffer(4096, 4096, CV_8UC1); // 16MB + GpuMat d_dst1 = pool1.getBuffer(4096, 4096, CV_8UC3); // 48MB, pool1 is now full + + GpuMat d_src2 = pool2.getBuffer(1024, 1024, CV_8UC1); // 1MB + GpuMat d_dst2 = pool2.getBuffer(1024, 1024, CV_8UC3); // 3MB + + d_src1.setTo(Scalar(i), stream1); + d_src2.setTo(Scalar(i), stream2); + + cvtColor(d_src1, d_dst1, CV_GRAY2BGR, 0, stream1); + cvtColor(d_src2, d_dst2, CV_GRAY2BGR, 0, stream2); + // The order of destruction of the local variables is: + // d_dst2 => d_src2 => d_dst1 => d_src1 + // LIFO rule is satisfied, this code runs without error + } + } +@endcode + */ +class CV_EXPORTS BufferPool +{ +public: + + //! Gets the BufferPool for the given stream. + explicit BufferPool(Stream& stream); + + //! Allocates a new GpuMat of given size and type. + GpuMat getBuffer(int rows, int cols, int type); + + //! Allocates a new GpuMat of given size and type. + GpuMat getBuffer(Size size, int type) { return getBuffer(size.height, size.width, type); } + + //! Returns the allocator associated with the stream. + Ptr getAllocator() const { return allocator_; } + +private: + Ptr allocator_; +}; + //! BufferPool management (must be called before Stream creation) CV_EXPORTS void setBufferPoolUsage(bool on); CV_EXPORTS void setBufferPoolConfig(int deviceId, size_t stackSize, int stackCount); @@ -447,7 +618,26 @@ CV_EXPORTS void unregisterPageLocked(Mat& m); functions use the constant GPU memory, and next call may update the memory before the previous one has been finished. But calling different operations asynchronously is safe because each operation has its own constant buffer. Memory copy/upload/download/set operations to the buffers you hold are -also safe. : +also safe. + +@note The Stream class is not thread-safe. Please use different Stream objects for different CPU threads. + +@code +void thread1() +{ + cv::cuda::Stream stream1; + cv::cuda::func1(..., stream1); +} + +void thread2() +{ + cv::cuda::Stream stream2; + cv::cuda::func2(..., stream2); +} +@endcode + +@note By default all CUDA routines are launched in Stream::Null() object, if the stream is not specified by user. +In multi-threading environment the stream objects must be passed explicitly (see previous note). */ class CV_EXPORTS Stream { @@ -460,6 +650,9 @@ public: //! creates a new asynchronous stream Stream(); + //! creates a new asynchronous stream with custom allocator + Stream(const Ptr& allocator); + /** @brief Returns true if the current stream queue is finished. Otherwise, it returns false. */ bool queryIfComplete() const; @@ -528,6 +721,7 @@ public: private: Ptr impl_; + Event(const Ptr& impl); friend struct EventAccessor; }; @@ -544,7 +738,8 @@ private: /** @brief Returns the number of installed CUDA-enabled devices. Use this function before any other CUDA functions calls. If OpenCV is compiled without CUDA support, -this function returns 0. +this function returns 0. If the CUDA driver is not installed, or is incompatible, this function +returns -1. */ CV_EXPORTS int getCudaEnabledDeviceCount(); @@ -835,6 +1030,15 @@ private: CV_EXPORTS void printCudaDeviceInfo(int device); CV_EXPORTS void printShortCudaDeviceInfo(int device); +/** @brief Converts an array to half precision floating number. + +@param _src input array. +@param _dst output array. +@param stream Stream for the asynchronous version. +@sa convertFp16 +*/ +CV_EXPORTS void convertFp16(InputArray _src, OutputArray _dst, Stream& stream = Stream::Null()); + //! @} cudacore_init }} // namespace cv { namespace cuda { @@ -842,4 +1046,4 @@ CV_EXPORTS void printShortCudaDeviceInfo(int device); #include "opencv2/core/cuda.inl.hpp" -#endif /* __OPENCV_CORE_CUDA_HPP__ */ +#endif /* OPENCV_CORE_CUDA_HPP */ diff --git a/include/opencv2/core/cuda.inl.hpp b/include/opencv2/core/cuda.inl.hpp index 1285b1a..35ae2e4 100644 --- a/include/opencv2/core/cuda.inl.hpp +++ b/include/opencv2/core/cuda.inl.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CORE_CUDAINL_HPP__ -#define __OPENCV_CORE_CUDAINL_HPP__ +#ifndef OPENCV_CORE_CUDAINL_HPP +#define OPENCV_CORE_CUDAINL_HPP #include "opencv2/core/cuda.hpp" @@ -540,6 +540,16 @@ Stream::Stream(const Ptr& impl) { } +//=================================================================================== +// Event +//=================================================================================== + +inline +Event::Event(const Ptr& impl) + : impl_(impl) +{ +} + //=================================================================================== // Initialization & Info //=================================================================================== @@ -578,7 +588,7 @@ int DeviceInfo::deviceID() const inline size_t DeviceInfo::freeMemory() const { - size_t _totalMemory, _freeMemory; + size_t _totalMemory = 0, _freeMemory = 0; queryMemory(_totalMemory, _freeMemory); return _freeMemory; } @@ -586,7 +596,7 @@ size_t DeviceInfo::freeMemory() const inline size_t DeviceInfo::totalMemory() const { - size_t _totalMemory, _freeMemory; + size_t _totalMemory = 0, _freeMemory = 0; queryMemory(_totalMemory, _freeMemory); return _totalMemory; } @@ -618,4 +628,4 @@ Mat::Mat(const cuda::GpuMat& m) //! @endcond -#endif // __OPENCV_CORE_CUDAINL_HPP__ +#endif // OPENCV_CORE_CUDAINL_HPP diff --git a/include/opencv2/core/cuda/block.hpp b/include/opencv2/core/cuda/block.hpp index 0c6f063..c277f0e 100644 --- a/include/opencv2/core/cuda/block.hpp +++ b/include/opencv2/core/cuda/block.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_DEVICE_BLOCK_HPP__ -#define __OPENCV_CUDA_DEVICE_BLOCK_HPP__ +#ifndef OPENCV_CUDA_DEVICE_BLOCK_HPP +#define OPENCV_CUDA_DEVICE_BLOCK_HPP /** @file * @deprecated Use @ref cudev instead. @@ -106,7 +106,7 @@ namespace cv { namespace cuda { namespace device } template - static __device__ __forceinline__ void transfrom(InIt beg, InIt end, OutIt out, UnOp op) + static __device__ __forceinline__ void transform(InIt beg, InIt end, OutIt out, UnOp op) { int STRIDE = stride(); InIt t = beg + flattenedThreadId(); @@ -117,7 +117,7 @@ namespace cv { namespace cuda { namespace device } template - static __device__ __forceinline__ void transfrom(InIt1 beg1, InIt1 end1, InIt2 beg2, OutIt out, BinOp op) + static __device__ __forceinline__ void transform(InIt1 beg1, InIt1 end1, InIt2 beg2, OutIt out, BinOp op) { int STRIDE = stride(); InIt1 t1 = beg1 + flattenedThreadId(); @@ -208,4 +208,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif /* __OPENCV_CUDA_DEVICE_BLOCK_HPP__ */ +#endif /* OPENCV_CUDA_DEVICE_BLOCK_HPP */ diff --git a/include/opencv2/core/cuda/border_interpolate.hpp b/include/opencv2/core/cuda/border_interpolate.hpp index ba72669..874f705 100644 --- a/include/opencv2/core/cuda/border_interpolate.hpp +++ b/include/opencv2/core/cuda/border_interpolate.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__ -#define __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__ +#ifndef OPENCV_CUDA_BORDER_INTERPOLATE_HPP +#define OPENCV_CUDA_BORDER_INTERPOLATE_HPP #include "saturate_cast.hpp" #include "vec_traits.hpp" @@ -632,12 +632,12 @@ namespace cv { namespace cuda { namespace device __device__ __forceinline__ int idx_row_low(int y) const { - return (y >= 0) * y + (y < 0) * (y - ((y - height + 1) / height) * height); + return (y >= 0) ? y : (y - ((y - height + 1) / height) * height); } __device__ __forceinline__ int idx_row_high(int y) const { - return (y < height) * y + (y >= height) * (y % height); + return (y < height) ? y : (y % height); } __device__ __forceinline__ int idx_row(int y) const @@ -647,12 +647,12 @@ namespace cv { namespace cuda { namespace device __device__ __forceinline__ int idx_col_low(int x) const { - return (x >= 0) * x + (x < 0) * (x - ((x - width + 1) / width) * width); + return (x >= 0) ? x : (x - ((x - width + 1) / width) * width); } __device__ __forceinline__ int idx_col_high(int x) const { - return (x < width) * x + (x >= width) * (x % width); + return (x < width) ? x : (x % width); } __device__ __forceinline__ int idx_col(int x) const @@ -719,4 +719,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__ +#endif // OPENCV_CUDA_BORDER_INTERPOLATE_HPP diff --git a/include/opencv2/core/cuda/color.hpp b/include/opencv2/core/cuda/color.hpp index 6faf8c9..dcce280 100644 --- a/include/opencv2/core/cuda/color.hpp +++ b/include/opencv2/core/cuda/color.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_COLOR_HPP__ -#define __OPENCV_CUDA_COLOR_HPP__ +#ifndef OPENCV_CUDA_COLOR_HPP +#define OPENCV_CUDA_COLOR_HPP #include "detail/color_detail.hpp" @@ -306,4 +306,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__ +#endif // OPENCV_CUDA_COLOR_HPP diff --git a/include/opencv2/core/cuda/common.hpp b/include/opencv2/core/cuda/common.hpp index b93c3ef..14b1f3f 100644 --- a/include/opencv2/core/cuda/common.hpp +++ b/include/opencv2/core/cuda/common.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_COMMON_HPP__ -#define __OPENCV_CUDA_COMMON_HPP__ +#ifndef OPENCV_CUDA_COMMON_HPP +#define OPENCV_CUDA_COMMON_HPP #include #include "opencv2/core/cuda_types.hpp" @@ -106,4 +106,4 @@ namespace cv { namespace cuda //! @endcond -#endif // __OPENCV_CUDA_COMMON_HPP__ +#endif // OPENCV_CUDA_COMMON_HPP diff --git a/include/opencv2/core/cuda/datamov_utils.hpp b/include/opencv2/core/cuda/datamov_utils.hpp index bb02cf9..6820d0f 100644 --- a/include/opencv2/core/cuda/datamov_utils.hpp +++ b/include/opencv2/core/cuda/datamov_utils.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_DATAMOV_UTILS_HPP__ -#define __OPENCV_CUDA_DATAMOV_UTILS_HPP__ +#ifndef OPENCV_CUDA_DATAMOV_UTILS_HPP +#define OPENCV_CUDA_DATAMOV_UTILS_HPP #include "common.hpp" @@ -110,4 +110,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_DATAMOV_UTILS_HPP__ +#endif // OPENCV_CUDA_DATAMOV_UTILS_HPP diff --git a/include/opencv2/core/cuda/detail/color_detail.hpp b/include/opencv2/core/cuda/detail/color_detail.hpp index 1151806..bfb4055 100644 --- a/include/opencv2/core/cuda/detail/color_detail.hpp +++ b/include/opencv2/core/cuda/detail/color_detail.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_COLOR_DETAIL_HPP__ -#define __OPENCV_CUDA_COLOR_DETAIL_HPP__ +#ifndef OPENCV_CUDA_COLOR_DETAIL_HPP +#define OPENCV_CUDA_COLOR_DETAIL_HPP #include "../common.hpp" #include "../vec_traits.hpp" @@ -1977,4 +1977,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_COLOR_DETAIL_HPP__ +#endif // OPENCV_CUDA_COLOR_DETAIL_HPP diff --git a/include/opencv2/core/cuda/detail/reduce.hpp b/include/opencv2/core/cuda/detail/reduce.hpp index 0c35eab..8af20b0 100644 --- a/include/opencv2/core/cuda/detail/reduce.hpp +++ b/include/opencv2/core/cuda/detail/reduce.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_REDUCE_DETAIL_HPP__ -#define __OPENCV_CUDA_REDUCE_DETAIL_HPP__ +#ifndef OPENCV_CUDA_REDUCE_DETAIL_HPP +#define OPENCV_CUDA_REDUCE_DETAIL_HPP #include #include "../warp.hpp" @@ -275,9 +275,9 @@ namespace cv { namespace cuda { namespace device template static __device__ void reduce(Pointer smem, Reference val, unsigned int tid, Op op) { - #if __CUDA_ARCH__ >= 300 - (void) smem; - (void) tid; + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + CV_UNUSED(smem); + CV_UNUSED(tid); Unroll::loopShfl(val, op, N); #else @@ -298,7 +298,7 @@ namespace cv { namespace cuda { namespace device { const unsigned int laneId = Warp::laneId(); - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 Unroll<16, Pointer, Reference, Op>::loopShfl(val, op, warpSize); if (laneId == 0) @@ -321,7 +321,7 @@ namespace cv { namespace cuda { namespace device if (tid < 32) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 Unroll::loopShfl(val, op, M); #else Unroll::loop(smem, val, tid, op); @@ -362,4 +362,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_REDUCE_DETAIL_HPP__ +#endif // OPENCV_CUDA_REDUCE_DETAIL_HPP diff --git a/include/opencv2/core/cuda/detail/reduce_key_val.hpp b/include/opencv2/core/cuda/detail/reduce_key_val.hpp index bab85d7..df37c17 100644 --- a/include/opencv2/core/cuda/detail/reduce_key_val.hpp +++ b/include/opencv2/core/cuda/detail/reduce_key_val.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP__ -#define __OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP__ +#ifndef OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP +#define OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP #include #include "../warp.hpp" @@ -402,9 +402,9 @@ namespace cv { namespace cuda { namespace device static __device__ void reduce(KP skeys, KR key, VP svals, VR val, unsigned int tid, Cmp cmp) { #if 0 // __CUDA_ARCH__ >= 300 - (void) skeys; - (void) svals; - (void) tid; + CV_UNUSED(skeys); + CV_UNUSED(svals); + CV_UNUSED(tid); Unroll::loopShfl(key, val, cmp, N); #else @@ -499,4 +499,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP__ +#endif // OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP diff --git a/include/opencv2/core/cuda/detail/transform_detail.hpp b/include/opencv2/core/cuda/detail/transform_detail.hpp index 96031c8..1919848 100644 --- a/include/opencv2/core/cuda/detail/transform_detail.hpp +++ b/include/opencv2/core/cuda/detail/transform_detail.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_TRANSFORM_DETAIL_HPP__ -#define __OPENCV_CUDA_TRANSFORM_DETAIL_HPP__ +#ifndef OPENCV_CUDA_TRANSFORM_DETAIL_HPP +#define OPENCV_CUDA_TRANSFORM_DETAIL_HPP #include "../common.hpp" #include "../vec_traits.hpp" @@ -223,11 +223,7 @@ namespace cv { namespace cuda { namespace device if (x_shifted + ft::smart_shift - 1 < src_.cols) { const read_type src_n_el = ((const read_type*)src)[x]; - write_type dst_n_el = ((const write_type*)dst)[x]; - - OpUnroller::unroll(src_n_el, dst_n_el, mask, op, x_shifted, y); - - ((write_type*)dst)[x] = dst_n_el; + OpUnroller::unroll(src_n_el, ((write_type*)dst)[x], mask, op, x_shifted, y); } else { @@ -275,11 +271,8 @@ namespace cv { namespace cuda { namespace device { const read_type1 src1_n_el = ((const read_type1*)src1)[x]; const read_type2 src2_n_el = ((const read_type2*)src2)[x]; - write_type dst_n_el = ((const write_type*)dst)[x]; - OpUnroller::unroll(src1_n_el, src2_n_el, dst_n_el, mask, op, x_shifted, y); - - ((write_type*)dst)[x] = dst_n_el; + OpUnroller::unroll(src1_n_el, src2_n_el, ((write_type*)dst)[x], mask, op, x_shifted, y); } else { @@ -396,4 +389,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_TRANSFORM_DETAIL_HPP__ +#endif // OPENCV_CUDA_TRANSFORM_DETAIL_HPP diff --git a/include/opencv2/core/cuda/detail/type_traits_detail.hpp b/include/opencv2/core/cuda/detail/type_traits_detail.hpp index 3463c78..a78bd2c 100644 --- a/include/opencv2/core/cuda/detail/type_traits_detail.hpp +++ b/include/opencv2/core/cuda/detail/type_traits_detail.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP__ -#define __OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP__ +#ifndef OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP +#define OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP #include "../common.hpp" #include "../vec_traits.hpp" @@ -188,4 +188,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP__ +#endif // OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP diff --git a/include/opencv2/core/cuda/detail/vec_distance_detail.hpp b/include/opencv2/core/cuda/detail/vec_distance_detail.hpp index 9ca85a5..8283a99 100644 --- a/include/opencv2/core/cuda/detail/vec_distance_detail.hpp +++ b/include/opencv2/core/cuda/detail/vec_distance_detail.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP__ -#define __OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP__ +#ifndef OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP +#define OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP #include "../datamov_utils.hpp" @@ -118,4 +118,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP__ +#endif // OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP diff --git a/include/opencv2/core/cuda/dynamic_smem.hpp b/include/opencv2/core/cuda/dynamic_smem.hpp index 3488463..42570c6 100644 --- a/include/opencv2/core/cuda/dynamic_smem.hpp +++ b/include/opencv2/core/cuda/dynamic_smem.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_DYNAMIC_SMEM_HPP__ -#define __OPENCV_CUDA_DYNAMIC_SMEM_HPP__ +#ifndef OPENCV_CUDA_DYNAMIC_SMEM_HPP +#define OPENCV_CUDA_DYNAMIC_SMEM_HPP /** @file * @deprecated Use @ref cudev instead. @@ -85,4 +85,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_DYNAMIC_SMEM_HPP__ +#endif // OPENCV_CUDA_DYNAMIC_SMEM_HPP diff --git a/include/opencv2/core/cuda/emulation.hpp b/include/opencv2/core/cuda/emulation.hpp index d346865..17dc117 100644 --- a/include/opencv2/core/cuda/emulation.hpp +++ b/include/opencv2/core/cuda/emulation.hpp @@ -177,8 +177,8 @@ namespace cv { namespace cuda { namespace device } while (assumed != old); return __longlong_as_double(old); #else - (void) address; - (void) val; + CV_UNUSED(address); + CV_UNUSED(val); return 0.0; #endif } @@ -199,8 +199,8 @@ namespace cv { namespace cuda { namespace device } while (assumed != old); return __int_as_float(old); #else - (void) address; - (void) val; + CV_UNUSED(address); + CV_UNUSED(val); return 0.0f; #endif } @@ -216,8 +216,8 @@ namespace cv { namespace cuda { namespace device } while (assumed != old); return __longlong_as_double(old); #else - (void) address; - (void) val; + CV_UNUSED(address); + CV_UNUSED(val); return 0.0; #endif } @@ -238,8 +238,8 @@ namespace cv { namespace cuda { namespace device } while (assumed != old); return __int_as_float(old); #else - (void) address; - (void) val; + CV_UNUSED(address); + CV_UNUSED(val); return 0.0f; #endif } @@ -255,8 +255,8 @@ namespace cv { namespace cuda { namespace device } while (assumed != old); return __longlong_as_double(old); #else - (void) address; - (void) val; + CV_UNUSED(address); + CV_UNUSED(val); return 0.0; #endif } diff --git a/include/opencv2/core/cuda/filters.hpp b/include/opencv2/core/cuda/filters.hpp index 9adc00c..bb94212 100644 --- a/include/opencv2/core/cuda/filters.hpp +++ b/include/opencv2/core/cuda/filters.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_FILTERS_HPP__ -#define __OPENCV_CUDA_FILTERS_HPP__ +#ifndef OPENCV_CUDA_FILTERS_HPP +#define OPENCV_CUDA_FILTERS_HPP #include "saturate_cast.hpp" #include "vec_traits.hpp" @@ -64,8 +64,8 @@ namespace cv { namespace cuda { namespace device explicit __host__ __device__ __forceinline__ PointFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) : src(src_) { - (void)fx; - (void)fy; + CV_UNUSED(fx); + CV_UNUSED(fy); } __device__ __forceinline__ elem_type operator ()(float y, float x) const @@ -84,8 +84,8 @@ namespace cv { namespace cuda { namespace device explicit __host__ __device__ __forceinline__ LinearFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) : src(src_) { - (void)fx; - (void)fy; + CV_UNUSED(fx); + CV_UNUSED(fy); } __device__ __forceinline__ elem_type operator ()(float y, float x) const { @@ -125,8 +125,8 @@ namespace cv { namespace cuda { namespace device explicit __host__ __device__ __forceinline__ CubicFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) : src(src_) { - (void)fx; - (void)fy; + CV_UNUSED(fx); + CV_UNUSED(fy); } static __device__ __forceinline__ float bicubicCoeff(float x_) @@ -283,4 +283,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_FILTERS_HPP__ +#endif // OPENCV_CUDA_FILTERS_HPP diff --git a/include/opencv2/core/cuda/funcattrib.hpp b/include/opencv2/core/cuda/funcattrib.hpp index fbb236b..f582080 100644 --- a/include/opencv2/core/cuda/funcattrib.hpp +++ b/include/opencv2/core/cuda/funcattrib.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP_ -#define __OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP_ +#ifndef OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP +#define OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP #include @@ -76,4 +76,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif /* __OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP_ */ +#endif /* OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP */ diff --git a/include/opencv2/core/cuda/functional.hpp b/include/opencv2/core/cuda/functional.hpp index ed3943d..4944381 100644 --- a/include/opencv2/core/cuda/functional.hpp +++ b/include/opencv2/core/cuda/functional.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_FUNCTIONAL_HPP__ -#define __OPENCV_CUDA_FUNCTIONAL_HPP__ +#ifndef OPENCV_CUDA_FUNCTIONAL_HPP +#define OPENCV_CUDA_FUNCTIONAL_HPP #include #include "saturate_cast.hpp" @@ -58,8 +58,22 @@ namespace cv { namespace cuda { namespace device { // Function Objects +#ifdef CV_CXX11 + template struct unary_function + { + typedef Argument argument_type; + typedef Result result_type; + }; + template struct binary_function + { + typedef Argument1 first_argument_type; + typedef Argument2 second_argument_type; + typedef Result result_type; + }; +#else template struct unary_function : public std::unary_function {}; template struct binary_function : public std::binary_function {}; +#endif // Arithmetic Operations template struct plus : binary_function @@ -583,7 +597,7 @@ namespace cv { namespace cuda { namespace device template struct thresh_trunc_func : unary_function { - explicit __host__ __device__ __forceinline__ thresh_trunc_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {(void)maxVal_;} + explicit __host__ __device__ __forceinline__ thresh_trunc_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {CV_UNUSED(maxVal_);} __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const { @@ -599,7 +613,7 @@ namespace cv { namespace cuda { namespace device template struct thresh_to_zero_func : unary_function { - explicit __host__ __device__ __forceinline__ thresh_to_zero_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {(void)maxVal_;} + explicit __host__ __device__ __forceinline__ thresh_to_zero_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {CV_UNUSED(maxVal_);} __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const { @@ -615,7 +629,7 @@ namespace cv { namespace cuda { namespace device template struct thresh_to_zero_inv_func : unary_function { - explicit __host__ __device__ __forceinline__ thresh_to_zero_inv_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {(void)maxVal_;} + explicit __host__ __device__ __forceinline__ thresh_to_zero_inv_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {CV_UNUSED(maxVal_);} __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const { @@ -794,4 +808,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_FUNCTIONAL_HPP__ +#endif // OPENCV_CUDA_FUNCTIONAL_HPP diff --git a/include/opencv2/core/cuda/limits.hpp b/include/opencv2/core/cuda/limits.hpp index b98bdf2..7e15ed6 100644 --- a/include/opencv2/core/cuda/limits.hpp +++ b/include/opencv2/core/cuda/limits.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_LIMITS_HPP__ -#define __OPENCV_CUDA_LIMITS_HPP__ +#ifndef OPENCV_CUDA_LIMITS_HPP +#define OPENCV_CUDA_LIMITS_HPP #include #include @@ -125,4 +125,4 @@ template <> struct numeric_limits //! @endcond -#endif // __OPENCV_CUDA_LIMITS_HPP__ +#endif // OPENCV_CUDA_LIMITS_HPP diff --git a/include/opencv2/core/cuda/reduce.hpp b/include/opencv2/core/cuda/reduce.hpp index 3133c9a..5de3650 100644 --- a/include/opencv2/core/cuda/reduce.hpp +++ b/include/opencv2/core/cuda/reduce.hpp @@ -40,8 +40,12 @@ // //M*/ -#ifndef __OPENCV_CUDA_REDUCE_HPP__ -#define __OPENCV_CUDA_REDUCE_HPP__ +#ifndef OPENCV_CUDA_REDUCE_HPP +#define OPENCV_CUDA_REDUCE_HPP + +#ifndef THRUST_DEBUG // eliminate -Wundef warning +#define THRUST_DEBUG 0 +#endif #include #include "detail/reduce.hpp" @@ -202,4 +206,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_UTILITY_HPP__ +#endif // OPENCV_CUDA_REDUCE_HPP diff --git a/include/opencv2/core/cuda/saturate_cast.hpp b/include/opencv2/core/cuda/saturate_cast.hpp index e7633c7..c3a3d1c 100644 --- a/include/opencv2/core/cuda/saturate_cast.hpp +++ b/include/opencv2/core/cuda/saturate_cast.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_SATURATE_CAST_HPP__ -#define __OPENCV_CUDA_SATURATE_CAST_HPP__ +#ifndef OPENCV_CUDA_SATURATE_CAST_HPP +#define OPENCV_CUDA_SATURATE_CAST_HPP #include "common.hpp" @@ -101,7 +101,7 @@ namespace cv { namespace cuda { namespace device } template<> __device__ __forceinline__ uchar saturate_cast(double v) { - #if __CUDA_ARCH__ >= 130 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 uint res = 0; asm("cvt.rni.sat.u8.f64 %0, %1;" : "=r"(res) : "d"(v)); return res; @@ -149,7 +149,7 @@ namespace cv { namespace cuda { namespace device } template<> __device__ __forceinline__ schar saturate_cast(double v) { - #if __CUDA_ARCH__ >= 130 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 uint res = 0; asm("cvt.rni.sat.s8.f64 %0, %1;" : "=r"(res) : "d"(v)); return res; @@ -191,7 +191,7 @@ namespace cv { namespace cuda { namespace device } template<> __device__ __forceinline__ ushort saturate_cast(double v) { - #if __CUDA_ARCH__ >= 130 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 ushort res = 0; asm("cvt.rni.sat.u16.f64 %0, %1;" : "=h"(res) : "d"(v)); return res; @@ -226,7 +226,7 @@ namespace cv { namespace cuda { namespace device } template<> __device__ __forceinline__ short saturate_cast(double v) { - #if __CUDA_ARCH__ >= 130 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 short res = 0; asm("cvt.rni.sat.s16.f64 %0, %1;" : "=h"(res) : "d"(v)); return res; @@ -289,4 +289,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif /* __OPENCV_CUDA_SATURATE_CAST_HPP__ */ +#endif /* OPENCV_CUDA_SATURATE_CAST_HPP */ diff --git a/include/opencv2/core/cuda/scan.hpp b/include/opencv2/core/cuda/scan.hpp index 687abb5..e128fb0 100644 --- a/include/opencv2/core/cuda/scan.hpp +++ b/include/opencv2/core/cuda/scan.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_SCAN_HPP__ -#define __OPENCV_CUDA_SCAN_HPP__ +#ifndef OPENCV_CUDA_SCAN_HPP +#define OPENCV_CUDA_SCAN_HPP #include "opencv2/core/cuda/common.hpp" #include "opencv2/core/cuda/utility.hpp" @@ -61,7 +61,7 @@ namespace cv { namespace cuda { namespace device template struct WarpScan { __device__ __forceinline__ WarpScan() {} - __device__ __forceinline__ WarpScan(const WarpScan& other) { (void)other; } + __device__ __forceinline__ WarpScan(const WarpScan& other) { CV_UNUSED(other); } __device__ __forceinline__ T operator()( volatile T *ptr , const unsigned int idx) { @@ -95,7 +95,7 @@ namespace cv { namespace cuda { namespace device template struct WarpScanNoComp { __device__ __forceinline__ WarpScanNoComp() {} - __device__ __forceinline__ WarpScanNoComp(const WarpScanNoComp& other) { (void)other; } + __device__ __forceinline__ WarpScanNoComp(const WarpScanNoComp& other) { CV_UNUSED(other); } __device__ __forceinline__ T operator()( volatile T *ptr , const unsigned int idx) { @@ -135,7 +135,7 @@ namespace cv { namespace cuda { namespace device template struct BlockScan { __device__ __forceinline__ BlockScan() {} - __device__ __forceinline__ BlockScan(const BlockScan& other) { (void)other; } + __device__ __forceinline__ BlockScan(const BlockScan& other) { CV_UNUSED(other); } __device__ __forceinline__ T operator()(volatile T *ptr) { @@ -255,4 +255,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_SCAN_HPP__ +#endif // OPENCV_CUDA_SCAN_HPP diff --git a/include/opencv2/core/cuda/simd_functions.hpp b/include/opencv2/core/cuda/simd_functions.hpp index b9e0041..3d8c2e0 100644 --- a/include/opencv2/core/cuda/simd_functions.hpp +++ b/include/opencv2/core/cuda/simd_functions.hpp @@ -70,8 +70,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __OPENCV_CUDA_SIMD_FUNCTIONS_HPP__ -#define __OPENCV_CUDA_SIMD_FUNCTIONS_HPP__ +#ifndef OPENCV_CUDA_SIMD_FUNCTIONS_HPP +#define OPENCV_CUDA_SIMD_FUNCTIONS_HPP #include "common.hpp" @@ -866,4 +866,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_SIMD_FUNCTIONS_HPP__ +#endif // OPENCV_CUDA_SIMD_FUNCTIONS_HPP diff --git a/include/opencv2/core/cuda/transform.hpp b/include/opencv2/core/cuda/transform.hpp index 08a313d..42aa6ea 100644 --- a/include/opencv2/core/cuda/transform.hpp +++ b/include/opencv2/core/cuda/transform.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_TRANSFORM_HPP__ -#define __OPENCV_CUDA_TRANSFORM_HPP__ +#ifndef OPENCV_CUDA_TRANSFORM_HPP +#define OPENCV_CUDA_TRANSFORM_HPP #include "common.hpp" #include "utility.hpp" @@ -72,4 +72,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_TRANSFORM_HPP__ +#endif // OPENCV_CUDA_TRANSFORM_HPP diff --git a/include/opencv2/core/cuda/type_traits.hpp b/include/opencv2/core/cuda/type_traits.hpp index f2471eb..8b7a3fd 100644 --- a/include/opencv2/core/cuda/type_traits.hpp +++ b/include/opencv2/core/cuda/type_traits.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_TYPE_TRAITS_HPP__ -#define __OPENCV_CUDA_TYPE_TRAITS_HPP__ +#ifndef OPENCV_CUDA_TYPE_TRAITS_HPP +#define OPENCV_CUDA_TYPE_TRAITS_HPP #include "detail/type_traits_detail.hpp" @@ -87,4 +87,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_TYPE_TRAITS_HPP__ +#endif // OPENCV_CUDA_TYPE_TRAITS_HPP diff --git a/include/opencv2/core/cuda/utility.hpp b/include/opencv2/core/cuda/utility.hpp index ed60471..7f5db48 100644 --- a/include/opencv2/core/cuda/utility.hpp +++ b/include/opencv2/core/cuda/utility.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_UTILITY_HPP__ -#define __OPENCV_CUDA_UTILITY_HPP__ +#ifndef OPENCV_CUDA_UTILITY_HPP +#define OPENCV_CUDA_UTILITY_HPP #include "saturate_cast.hpp" #include "datamov_utils.hpp" @@ -54,6 +54,15 @@ namespace cv { namespace cuda { namespace device { + struct CV_EXPORTS ThrustAllocator + { + typedef uchar value_type; + virtual ~ThrustAllocator(); + virtual __device__ __host__ uchar* allocate(size_t numBytes) = 0; + virtual __device__ __host__ void deallocate(uchar* ptr, size_t numBytes) = 0; + static ThrustAllocator& getAllocator(); + static void setAllocator(ThrustAllocator* allocator); + }; #define OPENCV_CUDA_LOG_WARP_SIZE (5) #define OPENCV_CUDA_WARP_SIZE (1 << OPENCV_CUDA_LOG_WARP_SIZE) #define OPENCV_CUDA_LOG_MEM_BANKS ((__CUDA_ARCH__ >= 200) ? 5 : 4) // 32 banks on fermi, 16 on tesla @@ -218,4 +227,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_UTILITY_HPP__ +#endif // OPENCV_CUDA_UTILITY_HPP diff --git a/include/opencv2/core/cuda/vec_distance.hpp b/include/opencv2/core/cuda/vec_distance.hpp index 013b747..ef6e510 100644 --- a/include/opencv2/core/cuda/vec_distance.hpp +++ b/include/opencv2/core/cuda/vec_distance.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_VEC_DISTANCE_HPP__ -#define __OPENCV_CUDA_VEC_DISTANCE_HPP__ +#ifndef OPENCV_CUDA_VEC_DISTANCE_HPP +#define OPENCV_CUDA_VEC_DISTANCE_HPP #include "reduce.hpp" #include "functional.hpp" @@ -229,4 +229,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_VEC_DISTANCE_HPP__ +#endif // OPENCV_CUDA_VEC_DISTANCE_HPP diff --git a/include/opencv2/core/cuda/vec_math.hpp b/include/opencv2/core/cuda/vec_math.hpp index 8595fb8..9085b92 100644 --- a/include/opencv2/core/cuda/vec_math.hpp +++ b/include/opencv2/core/cuda/vec_math.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_VECMATH_HPP__ -#define __OPENCV_CUDA_VECMATH_HPP__ +#ifndef OPENCV_CUDA_VECMATH_HPP +#define OPENCV_CUDA_VECMATH_HPP #include "vec_traits.hpp" #include "saturate_cast.hpp" @@ -927,4 +927,4 @@ CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, double, double, double) //! @endcond -#endif // __OPENCV_CUDA_VECMATH_HPP__ +#endif // OPENCV_CUDA_VECMATH_HPP diff --git a/include/opencv2/core/cuda/vec_traits.hpp b/include/opencv2/core/cuda/vec_traits.hpp index 905e37f..b5ff281 100644 --- a/include/opencv2/core/cuda/vec_traits.hpp +++ b/include/opencv2/core/cuda/vec_traits.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_VEC_TRAITS_HPP__ -#define __OPENCV_CUDA_VEC_TRAITS_HPP__ +#ifndef OPENCV_CUDA_VEC_TRAITS_HPP +#define OPENCV_CUDA_VEC_TRAITS_HPP #include "common.hpp" @@ -285,4 +285,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif // __OPENCV_CUDA_VEC_TRAITS_HPP__ +#endif // OPENCV_CUDA_VEC_TRAITS_HPP diff --git a/include/opencv2/core/cuda/warp.hpp b/include/opencv2/core/cuda/warp.hpp index d93afe7..8af7e6a 100644 --- a/include/opencv2/core/cuda/warp.hpp +++ b/include/opencv2/core/cuda/warp.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_DEVICE_WARP_HPP__ -#define __OPENCV_CUDA_DEVICE_WARP_HPP__ +#ifndef OPENCV_CUDA_DEVICE_WARP_HPP +#define OPENCV_CUDA_DEVICE_WARP_HPP /** @file * @deprecated Use @ref cudev instead. @@ -64,7 +64,7 @@ namespace cv { namespace cuda { namespace device static __device__ __forceinline__ unsigned int laneId() { unsigned int ret; - asm("mov.u32 %0, %laneid;" : "=r"(ret) ); + asm("mov.u32 %0, %%laneid;" : "=r"(ret) ); return ret; } @@ -136,4 +136,4 @@ namespace cv { namespace cuda { namespace device //! @endcond -#endif /* __OPENCV_CUDA_DEVICE_WARP_HPP__ */ +#endif /* OPENCV_CUDA_DEVICE_WARP_HPP */ diff --git a/include/opencv2/core/cuda/warp_shuffle.hpp b/include/opencv2/core/cuda/warp_shuffle.hpp index 5cf42ec..0da54ae 100644 --- a/include/opencv2/core/cuda/warp_shuffle.hpp +++ b/include/opencv2/core/cuda/warp_shuffle.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CUDA_WARP_SHUFFLE_HPP__ -#define __OPENCV_CUDA_WARP_SHUFFLE_HPP__ +#ifndef OPENCV_CUDA_WARP_SHUFFLE_HPP +#define OPENCV_CUDA_WARP_SHUFFLE_HPP /** @file * @deprecated Use @ref cudev instead. @@ -51,10 +51,15 @@ namespace cv { namespace cuda { namespace device { +#if __CUDACC_VER_MAJOR__ >= 9 +# define __shfl(x, y, z) __shfl_sync(0xFFFFFFFFU, x, y, z) +# define __shfl_up(x, y, z) __shfl_up_sync(0xFFFFFFFFU, x, y, z) +# define __shfl_down(x, y, z) __shfl_down_sync(0xFFFFFFFFU, x, y, z) +#endif template __device__ __forceinline__ T shfl(T val, int srcLane, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 return __shfl(val, srcLane, width); #else return T(); @@ -62,7 +67,7 @@ namespace cv { namespace cuda { namespace device } __device__ __forceinline__ unsigned int shfl(unsigned int val, int srcLane, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 return (unsigned int) __shfl((int) val, srcLane, width); #else return 0; @@ -70,7 +75,7 @@ namespace cv { namespace cuda { namespace device } __device__ __forceinline__ double shfl(double val, int srcLane, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 int lo = __double2loint(val); int hi = __double2hiint(val); @@ -86,7 +91,7 @@ namespace cv { namespace cuda { namespace device template __device__ __forceinline__ T shfl_down(T val, unsigned int delta, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 return __shfl_down(val, delta, width); #else return T(); @@ -94,7 +99,7 @@ namespace cv { namespace cuda { namespace device } __device__ __forceinline__ unsigned int shfl_down(unsigned int val, unsigned int delta, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 return (unsigned int) __shfl_down((int) val, delta, width); #else return 0; @@ -102,7 +107,7 @@ namespace cv { namespace cuda { namespace device } __device__ __forceinline__ double shfl_down(double val, unsigned int delta, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 int lo = __double2loint(val); int hi = __double2hiint(val); @@ -118,7 +123,7 @@ namespace cv { namespace cuda { namespace device template __device__ __forceinline__ T shfl_up(T val, unsigned int delta, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 return __shfl_up(val, delta, width); #else return T(); @@ -126,7 +131,7 @@ namespace cv { namespace cuda { namespace device } __device__ __forceinline__ unsigned int shfl_up(unsigned int val, unsigned int delta, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 return (unsigned int) __shfl_up((int) val, delta, width); #else return 0; @@ -134,7 +139,7 @@ namespace cv { namespace cuda { namespace device } __device__ __forceinline__ double shfl_up(double val, unsigned int delta, int width = warpSize) { - #if __CUDA_ARCH__ >= 300 + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 int lo = __double2loint(val); int hi = __double2hiint(val); @@ -148,6 +153,10 @@ namespace cv { namespace cuda { namespace device } }}} +# undef __shfl +# undef __shfl_up +# undef __shfl_down + //! @endcond -#endif // __OPENCV_CUDA_WARP_SHUFFLE_HPP__ +#endif // OPENCV_CUDA_WARP_SHUFFLE_HPP diff --git a/include/opencv2/core/cuda_stream_accessor.hpp b/include/opencv2/core/cuda_stream_accessor.hpp index dd6589b..deaf356 100644 --- a/include/opencv2/core/cuda_stream_accessor.hpp +++ b/include/opencv2/core/cuda_stream_accessor.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP__ -#define __OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP__ +#ifndef OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP +#define OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP #ifndef __cplusplus # error cuda_stream_accessor.hpp header must be compiled as C++ @@ -52,7 +52,7 @@ */ #include -#include "opencv2/core/cvdef.h" +#include "opencv2/core/cuda.hpp" namespace cv { @@ -62,14 +62,12 @@ namespace cv //! @addtogroup cudacore_struct //! @{ - class Stream; - class Event; - /** @brief Class that enables getting cudaStream_t from cuda::Stream */ struct StreamAccessor { CV_EXPORTS static cudaStream_t getStream(const Stream& stream); + CV_EXPORTS static Stream wrapStream(cudaStream_t stream); }; /** @brief Class that enables getting cudaEvent_t from cuda::Event @@ -77,6 +75,7 @@ namespace cv struct EventAccessor { CV_EXPORTS static cudaEvent_t getEvent(const Event& event); + CV_EXPORTS static Event wrapEvent(cudaEvent_t event); }; //! @} @@ -84,4 +83,4 @@ namespace cv } } -#endif /* __OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP__ */ +#endif /* OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP */ diff --git a/include/opencv2/core/cuda_types.hpp b/include/opencv2/core/cuda_types.hpp index 8df816e..e2647c0 100644 --- a/include/opencv2/core/cuda_types.hpp +++ b/include/opencv2/core/cuda_types.hpp @@ -40,13 +40,20 @@ // //M*/ -#ifndef __OPENCV_CORE_CUDA_TYPES_HPP__ -#define __OPENCV_CORE_CUDA_TYPES_HPP__ +#ifndef OPENCV_CORE_CUDA_TYPES_HPP +#define OPENCV_CORE_CUDA_TYPES_HPP #ifndef __cplusplus # error cuda_types.hpp header must be compiled as C++ #endif +#if defined(__OPENCV_BUILD) && defined(__clang__) +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +#if defined(__OPENCV_BUILD) && defined(__GNUC__) && __GNUC__ >= 5 +#pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + /** @file * @deprecated Use @ref cudev instead. */ @@ -132,4 +139,4 @@ namespace cv //! @endcond -#endif /* __OPENCV_CORE_CUDA_TYPES_HPP__ */ +#endif /* OPENCV_CORE_CUDA_TYPES_HPP */ diff --git a/include/opencv2/core/cv_cpu_dispatch.h b/include/opencv2/core/cv_cpu_dispatch.h new file mode 100644 index 0000000..57aa0ce --- /dev/null +++ b/include/opencv2/core/cv_cpu_dispatch.h @@ -0,0 +1,247 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#if defined __OPENCV_BUILD \ + +#include "cv_cpu_config.h" +#include "cv_cpu_helper.h" + +#ifdef CV_CPU_DISPATCH_MODE +#define CV_CPU_OPTIMIZATION_NAMESPACE __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#else +#define CV_CPU_OPTIMIZATION_NAMESPACE cpu_baseline +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace cpu_baseline { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#endif + + +#define __CV_CPU_DISPATCH_CHAIN_END(fn, args, mode, ...) /* done */ +#define __CV_CPU_DISPATCH(fn, args, mode, ...) __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) +#define __CV_CPU_DISPATCH_EXPAND(fn, args, ...) __CV_EXPAND(__CV_CPU_DISPATCH(fn, args, __VA_ARGS__)) +#define CV_CPU_DISPATCH(fn, args, ...) __CV_CPU_DISPATCH_EXPAND(fn, args, __VA_ARGS__, END) // expand macros + + +#if defined CV_ENABLE_INTRINSICS \ + && !defined CV_DISABLE_OPTIMIZATION \ + && !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC compiler */ \ + +#ifdef CV_CPU_COMPILE_SSE2 +# include +# define CV_MMX 1 +# define CV_SSE 1 +# define CV_SSE2 1 +#endif +#ifdef CV_CPU_COMPILE_SSE3 +# include +# define CV_SSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSSE3 +# include +# define CV_SSSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_1 +# include +# define CV_SSE4_1 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_2 +# include +# define CV_SSE4_2 1 +#endif +#ifdef CV_CPU_COMPILE_POPCNT +# ifdef _MSC_VER +# include +# if defined(_M_X64) +# define CV_POPCNT_U64 _mm_popcnt_u64 +# endif +# define CV_POPCNT_U32 _mm_popcnt_u32 +# else +# include +# if defined(__x86_64__) +# define CV_POPCNT_U64 __builtin_popcountll +# endif +# define CV_POPCNT_U32 __builtin_popcount +# endif +# define CV_POPCNT 1 +#endif +#ifdef CV_CPU_COMPILE_AVX +# include +# define CV_AVX 1 +#endif +#ifdef CV_CPU_COMPILE_FP16 +# if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) +# include +# else +# include +# endif +# define CV_FP16 1 +#endif +#ifdef CV_CPU_COMPILE_AVX2 +# include +# define CV_AVX2 1 +#endif +#ifdef CV_CPU_COMPILE_AVX_512F +# include +# define CV_AVX_512F 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_SKX +# include +# define CV_AVX512_SKX 1 +#endif +#ifdef CV_CPU_COMPILE_FMA3 +# define CV_FMA3 1 +#endif + +#if defined _WIN32 && defined(_M_ARM) +# include +# include +# define CV_NEON 1 +#elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__)) +# include +# define CV_NEON 1 +#endif + +#if defined(__ARM_NEON__) || defined(__aarch64__) +# include +#endif + +#ifdef CV_CPU_COMPILE_VSX +# include +# undef vector +# undef pixel +# undef bool +# define CV_VSX 1 +#endif + +#ifdef CV_CPU_COMPILE_VSX3 +# define CV_VSX3 1 +#endif + +#endif // CV_ENABLE_INTRINSICS && !CV_DISABLE_OPTIMIZATION && !__CUDACC__ + +#if defined CV_CPU_COMPILE_AVX && !defined CV_CPU_BASELINE_COMPILE_AVX +struct VZeroUpperGuard { +#ifdef __GNUC__ + __attribute__((always_inline)) +#endif + inline ~VZeroUpperGuard() { _mm256_zeroupper(); } +}; +#define __CV_AVX_GUARD VZeroUpperGuard __vzeroupper_guard; CV_UNUSED(__vzeroupper_guard); +#endif + +#ifdef __CV_AVX_GUARD +#define CV_AVX_GUARD __CV_AVX_GUARD +#else +#define CV_AVX_GUARD +#endif + +#endif // __OPENCV_BUILD + + + +#if !defined __OPENCV_BUILD /* Compatibility code */ \ + && !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC compiler */ +#if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2) +# include +# define CV_MMX 1 +# define CV_SSE 1 +# define CV_SSE2 1 +#elif defined _WIN32 && defined(_M_ARM) +# include +# include +# define CV_NEON 1 +#elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__)) +# include +# define CV_NEON 1 +#elif defined(__VSX__) && defined(__PPC64__) && defined(__LITTLE_ENDIAN__) +# include +# undef vector +# undef pixel +# undef bool +# define CV_VSX 1 +#endif + +#endif // !__OPENCV_BUILD && !__CUDACC (Compatibility code) + + + +#ifndef CV_MMX +# define CV_MMX 0 +#endif +#ifndef CV_SSE +# define CV_SSE 0 +#endif +#ifndef CV_SSE2 +# define CV_SSE2 0 +#endif +#ifndef CV_SSE3 +# define CV_SSE3 0 +#endif +#ifndef CV_SSSE3 +# define CV_SSSE3 0 +#endif +#ifndef CV_SSE4_1 +# define CV_SSE4_1 0 +#endif +#ifndef CV_SSE4_2 +# define CV_SSE4_2 0 +#endif +#ifndef CV_POPCNT +# define CV_POPCNT 0 +#endif +#ifndef CV_AVX +# define CV_AVX 0 +#endif +#ifndef CV_FP16 +# define CV_FP16 0 +#endif +#ifndef CV_AVX2 +# define CV_AVX2 0 +#endif +#ifndef CV_FMA3 +# define CV_FMA3 0 +#endif +#ifndef CV_AVX_512F +# define CV_AVX_512F 0 +#endif +#ifndef CV_AVX_512BW +# define CV_AVX_512BW 0 +#endif +#ifndef CV_AVX_512CD +# define CV_AVX_512CD 0 +#endif +#ifndef CV_AVX_512DQ +# define CV_AVX_512DQ 0 +#endif +#ifndef CV_AVX_512ER +# define CV_AVX_512ER 0 +#endif +#ifndef CV_AVX_512IFMA512 +# define CV_AVX_512IFMA512 0 +#endif +#ifndef CV_AVX_512PF +# define CV_AVX_512PF 0 +#endif +#ifndef CV_AVX_512VBMI +# define CV_AVX_512VBMI 0 +#endif +#ifndef CV_AVX_512VL +# define CV_AVX_512VL 0 +#endif +#ifndef CV_AVX512_SKX +# define CV_AVX512_SKX 0 +#endif + +#ifndef CV_NEON +# define CV_NEON 0 +#endif + +#ifndef CV_VSX +# define CV_VSX 0 +#endif + +#ifndef CV_VSX3 +# define CV_VSX3 0 +#endif diff --git a/include/opencv2/core/cv_cpu_helper.h b/include/opencv2/core/cv_cpu_helper.h new file mode 100644 index 0000000..ad13397 --- /dev/null +++ b/include/opencv2/core/cv_cpu_helper.h @@ -0,0 +1,340 @@ +// AUTOGENERATED, DO NOT EDIT + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE +# define CV_TRY_SSE 1 +# define CV_CPU_FORCE_SSE 1 +# define CV_CPU_HAS_SUPPORT_SSE 1 +# define CV_CPU_CALL_SSE(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE_(fn, args) return (opt_SSE::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE +# define CV_TRY_SSE 1 +# define CV_CPU_FORCE_SSE 0 +# define CV_CPU_HAS_SUPPORT_SSE (cv::checkHardwareSupport(CV_CPU_SSE)) +# define CV_CPU_CALL_SSE(fn, args) if (CV_CPU_HAS_SUPPORT_SSE) return (opt_SSE::fn args) +# define CV_CPU_CALL_SSE_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE) return (opt_SSE::fn args) +#else +# define CV_TRY_SSE 0 +# define CV_CPU_FORCE_SSE 0 +# define CV_CPU_HAS_SUPPORT_SSE 0 +# define CV_CPU_CALL_SSE(fn, args) +# define CV_CPU_CALL_SSE_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE(fn, args, mode, ...) CV_CPU_CALL_SSE(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE2 +# define CV_TRY_SSE2 1 +# define CV_CPU_FORCE_SSE2 1 +# define CV_CPU_HAS_SUPPORT_SSE2 1 +# define CV_CPU_CALL_SSE2(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE2_(fn, args) return (opt_SSE2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE2 +# define CV_TRY_SSE2 1 +# define CV_CPU_FORCE_SSE2 0 +# define CV_CPU_HAS_SUPPORT_SSE2 (cv::checkHardwareSupport(CV_CPU_SSE2)) +# define CV_CPU_CALL_SSE2(fn, args) if (CV_CPU_HAS_SUPPORT_SSE2) return (opt_SSE2::fn args) +# define CV_CPU_CALL_SSE2_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE2) return (opt_SSE2::fn args) +#else +# define CV_TRY_SSE2 0 +# define CV_CPU_FORCE_SSE2 0 +# define CV_CPU_HAS_SUPPORT_SSE2 0 +# define CV_CPU_CALL_SSE2(fn, args) +# define CV_CPU_CALL_SSE2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE2(fn, args, mode, ...) CV_CPU_CALL_SSE2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE3 +# define CV_TRY_SSE3 1 +# define CV_CPU_FORCE_SSE3 1 +# define CV_CPU_HAS_SUPPORT_SSE3 1 +# define CV_CPU_CALL_SSE3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE3_(fn, args) return (opt_SSE3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE3 +# define CV_TRY_SSE3 1 +# define CV_CPU_FORCE_SSE3 0 +# define CV_CPU_HAS_SUPPORT_SSE3 (cv::checkHardwareSupport(CV_CPU_SSE3)) +# define CV_CPU_CALL_SSE3(fn, args) if (CV_CPU_HAS_SUPPORT_SSE3) return (opt_SSE3::fn args) +# define CV_CPU_CALL_SSE3_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE3) return (opt_SSE3::fn args) +#else +# define CV_TRY_SSE3 0 +# define CV_CPU_FORCE_SSE3 0 +# define CV_CPU_HAS_SUPPORT_SSE3 0 +# define CV_CPU_CALL_SSE3(fn, args) +# define CV_CPU_CALL_SSE3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE3(fn, args, mode, ...) CV_CPU_CALL_SSE3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSSE3 +# define CV_TRY_SSSE3 1 +# define CV_CPU_FORCE_SSSE3 1 +# define CV_CPU_HAS_SUPPORT_SSSE3 1 +# define CV_CPU_CALL_SSSE3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSSE3_(fn, args) return (opt_SSSE3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSSE3 +# define CV_TRY_SSSE3 1 +# define CV_CPU_FORCE_SSSE3 0 +# define CV_CPU_HAS_SUPPORT_SSSE3 (cv::checkHardwareSupport(CV_CPU_SSSE3)) +# define CV_CPU_CALL_SSSE3(fn, args) if (CV_CPU_HAS_SUPPORT_SSSE3) return (opt_SSSE3::fn args) +# define CV_CPU_CALL_SSSE3_(fn, args) if (CV_CPU_HAS_SUPPORT_SSSE3) return (opt_SSSE3::fn args) +#else +# define CV_TRY_SSSE3 0 +# define CV_CPU_FORCE_SSSE3 0 +# define CV_CPU_HAS_SUPPORT_SSSE3 0 +# define CV_CPU_CALL_SSSE3(fn, args) +# define CV_CPU_CALL_SSSE3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSSE3(fn, args, mode, ...) CV_CPU_CALL_SSSE3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_1 +# define CV_TRY_SSE4_1 1 +# define CV_CPU_FORCE_SSE4_1 1 +# define CV_CPU_HAS_SUPPORT_SSE4_1 1 +# define CV_CPU_CALL_SSE4_1(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE4_1_(fn, args) return (opt_SSE4_1::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_1 +# define CV_TRY_SSE4_1 1 +# define CV_CPU_FORCE_SSE4_1 0 +# define CV_CPU_HAS_SUPPORT_SSE4_1 (cv::checkHardwareSupport(CV_CPU_SSE4_1)) +# define CV_CPU_CALL_SSE4_1(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_1) return (opt_SSE4_1::fn args) +# define CV_CPU_CALL_SSE4_1_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_1) return (opt_SSE4_1::fn args) +#else +# define CV_TRY_SSE4_1 0 +# define CV_CPU_FORCE_SSE4_1 0 +# define CV_CPU_HAS_SUPPORT_SSE4_1 0 +# define CV_CPU_CALL_SSE4_1(fn, args) +# define CV_CPU_CALL_SSE4_1_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_1(fn, args, mode, ...) CV_CPU_CALL_SSE4_1(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_2 +# define CV_TRY_SSE4_2 1 +# define CV_CPU_FORCE_SSE4_2 1 +# define CV_CPU_HAS_SUPPORT_SSE4_2 1 +# define CV_CPU_CALL_SSE4_2(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE4_2_(fn, args) return (opt_SSE4_2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_2 +# define CV_TRY_SSE4_2 1 +# define CV_CPU_FORCE_SSE4_2 0 +# define CV_CPU_HAS_SUPPORT_SSE4_2 (cv::checkHardwareSupport(CV_CPU_SSE4_2)) +# define CV_CPU_CALL_SSE4_2(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_2) return (opt_SSE4_2::fn args) +# define CV_CPU_CALL_SSE4_2_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_2) return (opt_SSE4_2::fn args) +#else +# define CV_TRY_SSE4_2 0 +# define CV_CPU_FORCE_SSE4_2 0 +# define CV_CPU_HAS_SUPPORT_SSE4_2 0 +# define CV_CPU_CALL_SSE4_2(fn, args) +# define CV_CPU_CALL_SSE4_2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_2(fn, args, mode, ...) CV_CPU_CALL_SSE4_2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_POPCNT +# define CV_TRY_POPCNT 1 +# define CV_CPU_FORCE_POPCNT 1 +# define CV_CPU_HAS_SUPPORT_POPCNT 1 +# define CV_CPU_CALL_POPCNT(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_POPCNT_(fn, args) return (opt_POPCNT::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_POPCNT +# define CV_TRY_POPCNT 1 +# define CV_CPU_FORCE_POPCNT 0 +# define CV_CPU_HAS_SUPPORT_POPCNT (cv::checkHardwareSupport(CV_CPU_POPCNT)) +# define CV_CPU_CALL_POPCNT(fn, args) if (CV_CPU_HAS_SUPPORT_POPCNT) return (opt_POPCNT::fn args) +# define CV_CPU_CALL_POPCNT_(fn, args) if (CV_CPU_HAS_SUPPORT_POPCNT) return (opt_POPCNT::fn args) +#else +# define CV_TRY_POPCNT 0 +# define CV_CPU_FORCE_POPCNT 0 +# define CV_CPU_HAS_SUPPORT_POPCNT 0 +# define CV_CPU_CALL_POPCNT(fn, args) +# define CV_CPU_CALL_POPCNT_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_POPCNT(fn, args, mode, ...) CV_CPU_CALL_POPCNT(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX +# define CV_TRY_AVX 1 +# define CV_CPU_FORCE_AVX 1 +# define CV_CPU_HAS_SUPPORT_AVX 1 +# define CV_CPU_CALL_AVX(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX_(fn, args) return (opt_AVX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX +# define CV_TRY_AVX 1 +# define CV_CPU_FORCE_AVX 0 +# define CV_CPU_HAS_SUPPORT_AVX (cv::checkHardwareSupport(CV_CPU_AVX)) +# define CV_CPU_CALL_AVX(fn, args) if (CV_CPU_HAS_SUPPORT_AVX) return (opt_AVX::fn args) +# define CV_CPU_CALL_AVX_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX) return (opt_AVX::fn args) +#else +# define CV_TRY_AVX 0 +# define CV_CPU_FORCE_AVX 0 +# define CV_CPU_HAS_SUPPORT_AVX 0 +# define CV_CPU_CALL_AVX(fn, args) +# define CV_CPU_CALL_AVX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX(fn, args, mode, ...) CV_CPU_CALL_AVX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FP16 +# define CV_TRY_FP16 1 +# define CV_CPU_FORCE_FP16 1 +# define CV_CPU_HAS_SUPPORT_FP16 1 +# define CV_CPU_CALL_FP16(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_FP16_(fn, args) return (opt_FP16::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FP16 +# define CV_TRY_FP16 1 +# define CV_CPU_FORCE_FP16 0 +# define CV_CPU_HAS_SUPPORT_FP16 (cv::checkHardwareSupport(CV_CPU_FP16)) +# define CV_CPU_CALL_FP16(fn, args) if (CV_CPU_HAS_SUPPORT_FP16) return (opt_FP16::fn args) +# define CV_CPU_CALL_FP16_(fn, args) if (CV_CPU_HAS_SUPPORT_FP16) return (opt_FP16::fn args) +#else +# define CV_TRY_FP16 0 +# define CV_CPU_FORCE_FP16 0 +# define CV_CPU_HAS_SUPPORT_FP16 0 +# define CV_CPU_CALL_FP16(fn, args) +# define CV_CPU_CALL_FP16_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_FP16(fn, args, mode, ...) CV_CPU_CALL_FP16(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX2 +# define CV_TRY_AVX2 1 +# define CV_CPU_FORCE_AVX2 1 +# define CV_CPU_HAS_SUPPORT_AVX2 1 +# define CV_CPU_CALL_AVX2(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX2_(fn, args) return (opt_AVX2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX2 +# define CV_TRY_AVX2 1 +# define CV_CPU_FORCE_AVX2 0 +# define CV_CPU_HAS_SUPPORT_AVX2 (cv::checkHardwareSupport(CV_CPU_AVX2)) +# define CV_CPU_CALL_AVX2(fn, args) if (CV_CPU_HAS_SUPPORT_AVX2) return (opt_AVX2::fn args) +# define CV_CPU_CALL_AVX2_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX2) return (opt_AVX2::fn args) +#else +# define CV_TRY_AVX2 0 +# define CV_CPU_FORCE_AVX2 0 +# define CV_CPU_HAS_SUPPORT_AVX2 0 +# define CV_CPU_CALL_AVX2(fn, args) +# define CV_CPU_CALL_AVX2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX2(fn, args, mode, ...) CV_CPU_CALL_AVX2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FMA3 +# define CV_TRY_FMA3 1 +# define CV_CPU_FORCE_FMA3 1 +# define CV_CPU_HAS_SUPPORT_FMA3 1 +# define CV_CPU_CALL_FMA3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_FMA3_(fn, args) return (opt_FMA3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FMA3 +# define CV_TRY_FMA3 1 +# define CV_CPU_FORCE_FMA3 0 +# define CV_CPU_HAS_SUPPORT_FMA3 (cv::checkHardwareSupport(CV_CPU_FMA3)) +# define CV_CPU_CALL_FMA3(fn, args) if (CV_CPU_HAS_SUPPORT_FMA3) return (opt_FMA3::fn args) +# define CV_CPU_CALL_FMA3_(fn, args) if (CV_CPU_HAS_SUPPORT_FMA3) return (opt_FMA3::fn args) +#else +# define CV_TRY_FMA3 0 +# define CV_CPU_FORCE_FMA3 0 +# define CV_CPU_HAS_SUPPORT_FMA3 0 +# define CV_CPU_CALL_FMA3(fn, args) +# define CV_CPU_CALL_FMA3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_FMA3(fn, args, mode, ...) CV_CPU_CALL_FMA3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX_512F +# define CV_TRY_AVX_512F 1 +# define CV_CPU_FORCE_AVX_512F 1 +# define CV_CPU_HAS_SUPPORT_AVX_512F 1 +# define CV_CPU_CALL_AVX_512F(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX_512F_(fn, args) return (opt_AVX_512F::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX_512F +# define CV_TRY_AVX_512F 1 +# define CV_CPU_FORCE_AVX_512F 0 +# define CV_CPU_HAS_SUPPORT_AVX_512F (cv::checkHardwareSupport(CV_CPU_AVX_512F)) +# define CV_CPU_CALL_AVX_512F(fn, args) if (CV_CPU_HAS_SUPPORT_AVX_512F) return (opt_AVX_512F::fn args) +# define CV_CPU_CALL_AVX_512F_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX_512F) return (opt_AVX_512F::fn args) +#else +# define CV_TRY_AVX_512F 0 +# define CV_CPU_FORCE_AVX_512F 0 +# define CV_CPU_HAS_SUPPORT_AVX_512F 0 +# define CV_CPU_CALL_AVX_512F(fn, args) +# define CV_CPU_CALL_AVX_512F_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX_512F(fn, args, mode, ...) CV_CPU_CALL_AVX_512F(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_SKX +# define CV_TRY_AVX512_SKX 1 +# define CV_CPU_FORCE_AVX512_SKX 1 +# define CV_CPU_HAS_SUPPORT_AVX512_SKX 1 +# define CV_CPU_CALL_AVX512_SKX(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_SKX_(fn, args) return (opt_AVX512_SKX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_SKX +# define CV_TRY_AVX512_SKX 1 +# define CV_CPU_FORCE_AVX512_SKX 0 +# define CV_CPU_HAS_SUPPORT_AVX512_SKX (cv::checkHardwareSupport(CV_CPU_AVX512_SKX)) +# define CV_CPU_CALL_AVX512_SKX(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_SKX) return (opt_AVX512_SKX::fn args) +# define CV_CPU_CALL_AVX512_SKX_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_SKX) return (opt_AVX512_SKX::fn args) +#else +# define CV_TRY_AVX512_SKX 0 +# define CV_CPU_FORCE_AVX512_SKX 0 +# define CV_CPU_HAS_SUPPORT_AVX512_SKX 0 +# define CV_CPU_CALL_AVX512_SKX(fn, args) +# define CV_CPU_CALL_AVX512_SKX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_SKX(fn, args, mode, ...) CV_CPU_CALL_AVX512_SKX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_NEON +# define CV_TRY_NEON 1 +# define CV_CPU_FORCE_NEON 1 +# define CV_CPU_HAS_SUPPORT_NEON 1 +# define CV_CPU_CALL_NEON(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_NEON_(fn, args) return (opt_NEON::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_NEON +# define CV_TRY_NEON 1 +# define CV_CPU_FORCE_NEON 0 +# define CV_CPU_HAS_SUPPORT_NEON (cv::checkHardwareSupport(CV_CPU_NEON)) +# define CV_CPU_CALL_NEON(fn, args) if (CV_CPU_HAS_SUPPORT_NEON) return (opt_NEON::fn args) +# define CV_CPU_CALL_NEON_(fn, args) if (CV_CPU_HAS_SUPPORT_NEON) return (opt_NEON::fn args) +#else +# define CV_TRY_NEON 0 +# define CV_CPU_FORCE_NEON 0 +# define CV_CPU_HAS_SUPPORT_NEON 0 +# define CV_CPU_CALL_NEON(fn, args) +# define CV_CPU_CALL_NEON_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_NEON(fn, args, mode, ...) CV_CPU_CALL_NEON(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_VSX +# define CV_TRY_VSX 1 +# define CV_CPU_FORCE_VSX 1 +# define CV_CPU_HAS_SUPPORT_VSX 1 +# define CV_CPU_CALL_VSX(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_VSX_(fn, args) return (opt_VSX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_VSX +# define CV_TRY_VSX 1 +# define CV_CPU_FORCE_VSX 0 +# define CV_CPU_HAS_SUPPORT_VSX (cv::checkHardwareSupport(CV_CPU_VSX)) +# define CV_CPU_CALL_VSX(fn, args) if (CV_CPU_HAS_SUPPORT_VSX) return (opt_VSX::fn args) +# define CV_CPU_CALL_VSX_(fn, args) if (CV_CPU_HAS_SUPPORT_VSX) return (opt_VSX::fn args) +#else +# define CV_TRY_VSX 0 +# define CV_CPU_FORCE_VSX 0 +# define CV_CPU_HAS_SUPPORT_VSX 0 +# define CV_CPU_CALL_VSX(fn, args) +# define CV_CPU_CALL_VSX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_VSX(fn, args, mode, ...) CV_CPU_CALL_VSX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_VSX3 +# define CV_TRY_VSX3 1 +# define CV_CPU_FORCE_VSX3 1 +# define CV_CPU_HAS_SUPPORT_VSX3 1 +# define CV_CPU_CALL_VSX3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_VSX3_(fn, args) return (opt_VSX3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_VSX3 +# define CV_TRY_VSX3 1 +# define CV_CPU_FORCE_VSX3 0 +# define CV_CPU_HAS_SUPPORT_VSX3 (cv::checkHardwareSupport(CV_CPU_VSX3)) +# define CV_CPU_CALL_VSX3(fn, args) if (CV_CPU_HAS_SUPPORT_VSX3) return (opt_VSX3::fn args) +# define CV_CPU_CALL_VSX3_(fn, args) if (CV_CPU_HAS_SUPPORT_VSX3) return (opt_VSX3::fn args) +#else +# define CV_TRY_VSX3 0 +# define CV_CPU_FORCE_VSX3 0 +# define CV_CPU_HAS_SUPPORT_VSX3 0 +# define CV_CPU_CALL_VSX3(fn, args) +# define CV_CPU_CALL_VSX3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_VSX3(fn, args, mode, ...) CV_CPU_CALL_VSX3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#define CV_CPU_CALL_BASELINE(fn, args) return (cpu_baseline::fn args) +#define __CV_CPU_DISPATCH_CHAIN_BASELINE(fn, args, mode, ...) CV_CPU_CALL_BASELINE(fn, args) /* last in sequence */ diff --git a/include/opencv2/core/cvdef.h b/include/opencv2/core/cvdef.h index 1d933b5..1e8a697 100644 --- a/include/opencv2/core/cvdef.h +++ b/include/opencv2/core/cvdef.h @@ -42,12 +42,131 @@ // //M*/ -#ifndef __OPENCV_CORE_CVDEF_H__ -#define __OPENCV_CORE_CVDEF_H__ +#ifndef OPENCV_CORE_CVDEF_H +#define OPENCV_CORE_CVDEF_H -#if !defined _CRT_SECURE_NO_DEPRECATE && defined _MSC_VER && _MSC_VER > 1300 -# define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio warnings */ +//! @addtogroup core_utils +//! @{ + +#if !defined CV_DOXYGEN && !defined CV_IGNORE_DEBUG_BUILD_GUARD +#if (defined(_MSC_VER) && (defined(DEBUG) || defined(_DEBUG))) || \ + (defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_DEBUG_PEDANTIC)) +// Guard to prevent using of binary incompatible binaries / runtimes +// https://github.com/opencv/opencv/pull/9161 +#define CV__DEBUG_NS_BEGIN namespace debug_build_guard { +#define CV__DEBUG_NS_END } +namespace cv { namespace debug_build_guard { } using namespace debug_build_guard; } #endif +#endif + +#ifndef CV__DEBUG_NS_BEGIN +#define CV__DEBUG_NS_BEGIN +#define CV__DEBUG_NS_END +#endif + + +#ifdef __OPENCV_BUILD +#include "cvconfig.h" +#endif + +#ifndef __CV_EXPAND +#define __CV_EXPAND(x) x +#endif + +#ifndef __CV_CAT +#define __CV_CAT__(x, y) x ## y +#define __CV_CAT_(x, y) __CV_CAT__(x, y) +#define __CV_CAT(x, y) __CV_CAT_(x, y) +#endif + +#define __CV_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define __CV_VA_NUM_ARGS(...) __CV_VA_NUM_ARGS_HELPER(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +#if defined __GNUC__ +#define CV_Func __func__ +#elif defined _MSC_VER +#define CV_Func __FUNCTION__ +#else +#define CV_Func "" +#endif + +//! @cond IGNORED + +//////////////// static assert ///////////////// +#define CVAUX_CONCAT_EXP(a, b) a##b +#define CVAUX_CONCAT(a, b) CVAUX_CONCAT_EXP(a,b) + +#if defined(__clang__) +# ifndef __has_extension +# define __has_extension __has_feature /* compatibility, for older versions of clang */ +# endif +# if __has_extension(cxx_static_assert) +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# elif __has_extension(c_static_assert) +# define CV_StaticAssert(condition, reason) _Static_assert((condition), reason " " #condition) +# endif +#elif defined(__GNUC__) +# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# endif +#elif defined(_MSC_VER) +# if _MSC_VER >= 1600 /* MSVC 10 */ +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# endif +#endif +#ifndef CV_StaticAssert +# if !defined(__clang__) && defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 302) +# define CV_StaticAssert(condition, reason) ({ extern int __attribute__((error("CV_StaticAssert: " reason " " #condition))) CV_StaticAssert(); ((condition) ? 0 : CV_StaticAssert()); }) +# else + template struct CV_StaticAssert_failed; + template <> struct CV_StaticAssert_failed { enum { val = 1 }; }; + template struct CV_StaticAssert_test {}; +# define CV_StaticAssert(condition, reason)\ + typedef cv::CV_StaticAssert_test< sizeof(cv::CV_StaticAssert_failed< static_cast(condition) >) > CVAUX_CONCAT(CV_StaticAssert_failed_at_, __LINE__) +# endif +#endif + +// Suppress warning "-Wdeprecated-declarations" / C4996 +#if defined(_MSC_VER) + #define CV_DO_PRAGMA(x) __pragma(x) +#elif defined(__GNUC__) + #define CV_DO_PRAGMA(x) _Pragma (#x) +#else + #define CV_DO_PRAGMA(x) +#endif + +#ifdef _MSC_VER +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(warning(push)) \ + CV_DO_PRAGMA(warning(disable: 4996)) +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(warning(pop)) +#elif defined (__clang__) || ((__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 405)) +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(GCC diagnostic push) \ + CV_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(GCC diagnostic pop) +#else +#define CV_SUPPRESS_DEPRECATED_START +#define CV_SUPPRESS_DEPRECATED_END +#endif + +#define CV_UNUSED(name) (void)name + +#if defined __GNUC__ && !defined __EXCEPTIONS +#define CV_TRY +#define CV_CATCH(A, B) for (A B; false; ) +#define CV_CATCH_ALL if (false) +#define CV_THROW(A) abort() +#define CV_RETHROW() abort() +#else +#define CV_TRY try +#define CV_CATCH(A, B) catch(const A & B) +#define CV_CATCH_ALL catch(...) +#define CV_THROW(A) throw A +#define CV_RETHROW() throw +#endif + +//! @endcond // undef problematic defines sometimes defined by system headers (windows.h in particular) #undef small @@ -56,20 +175,205 @@ #undef abs #undef Complex -#include "opencv2/hal/defs.h" +#include +#include "opencv2/core/hal/interface.h" + +#if defined __ICL +# define CV_ICC __ICL +#elif defined __ICC +# define CV_ICC __ICC +#elif defined __ECL +# define CV_ICC __ECL +#elif defined __ECC +# define CV_ICC __ECC +#elif defined __INTEL_COMPILER +# define CV_ICC __INTEL_COMPILER +#endif + +#ifndef CV_INLINE +# if defined __cplusplus +# define CV_INLINE static inline +# elif defined _MSC_VER +# define CV_INLINE __inline +# else +# define CV_INLINE static +# endif +#endif + +#if defined CV_DISABLE_OPTIMIZATION || (defined CV_ICC && !defined CV_ENABLE_UNROLLED) +# define CV_ENABLE_UNROLLED 0 +#else +# define CV_ENABLE_UNROLLED 1 +#endif + +#ifdef __GNUC__ +# define CV_DECL_ALIGNED(x) __attribute__ ((aligned (x))) +#elif defined _MSC_VER +# define CV_DECL_ALIGNED(x) __declspec(align(x)) +#else +# define CV_DECL_ALIGNED(x) +#endif + +/* CPU features and intrinsics support */ +#define CV_CPU_NONE 0 +#define CV_CPU_MMX 1 +#define CV_CPU_SSE 2 +#define CV_CPU_SSE2 3 +#define CV_CPU_SSE3 4 +#define CV_CPU_SSSE3 5 +#define CV_CPU_SSE4_1 6 +#define CV_CPU_SSE4_2 7 +#define CV_CPU_POPCNT 8 +#define CV_CPU_FP16 9 +#define CV_CPU_AVX 10 +#define CV_CPU_AVX2 11 +#define CV_CPU_FMA3 12 + +#define CV_CPU_AVX_512F 13 +#define CV_CPU_AVX_512BW 14 +#define CV_CPU_AVX_512CD 15 +#define CV_CPU_AVX_512DQ 16 +#define CV_CPU_AVX_512ER 17 +#define CV_CPU_AVX_512IFMA512 18 // deprecated +#define CV_CPU_AVX_512IFMA 18 +#define CV_CPU_AVX_512PF 19 +#define CV_CPU_AVX_512VBMI 20 +#define CV_CPU_AVX_512VL 21 + +#define CV_CPU_NEON 100 + +#define CV_CPU_VSX 200 +#define CV_CPU_VSX3 201 + +// CPU features groups +#define CV_CPU_AVX512_SKX 256 + +// when adding to this list remember to update the following enum +#define CV_HARDWARE_MAX_FEATURE 512 + +/** @brief Available CPU features. +*/ +enum CpuFeatures { + CPU_MMX = 1, + CPU_SSE = 2, + CPU_SSE2 = 3, + CPU_SSE3 = 4, + CPU_SSSE3 = 5, + CPU_SSE4_1 = 6, + CPU_SSE4_2 = 7, + CPU_POPCNT = 8, + CPU_FP16 = 9, + CPU_AVX = 10, + CPU_AVX2 = 11, + CPU_FMA3 = 12, + + CPU_AVX_512F = 13, + CPU_AVX_512BW = 14, + CPU_AVX_512CD = 15, + CPU_AVX_512DQ = 16, + CPU_AVX_512ER = 17, + CPU_AVX_512IFMA512 = 18, // deprecated + CPU_AVX_512IFMA = 18, + CPU_AVX_512PF = 19, + CPU_AVX_512VBMI = 20, + CPU_AVX_512VL = 21, + + CPU_NEON = 100, + + CPU_VSX = 200, + CPU_VSX3 = 201, + + CPU_AVX512_SKX = 256, //!< Skylake-X with AVX-512F/CD/BW/DQ/VL + + CPU_MAX_FEATURE = 512 // see CV_HARDWARE_MAX_FEATURE +}; + + +#include "cv_cpu_dispatch.h" + + +/* fundamental constants */ +#define CV_PI 3.1415926535897932384626433832795 +#define CV_2PI 6.283185307179586476925286766559 +#define CV_LOG2 0.69314718055994530941723212145818 + +#if defined __ARM_FP16_FORMAT_IEEE \ + && !defined __CUDACC__ +# define CV_FP16_TYPE 1 +#else +# define CV_FP16_TYPE 0 +#endif + +typedef union Cv16suf +{ + short i; + ushort u; +#if CV_FP16_TYPE + __fp16 h; +#endif +} +Cv16suf; + +typedef union Cv32suf +{ + int i; + unsigned u; + float f; +} +Cv32suf; + +typedef union Cv64suf +{ + int64 i; + uint64 u; + double f; +} +Cv64suf; + +#define OPENCV_ABI_COMPATIBILITY 300 #ifdef __OPENCV_BUILD # define DISABLE_OPENCV_24_COMPATIBILITY +# define OPENCV_DISABLE_DEPRECATED_COMPATIBILITY #endif -#if (defined WIN32 || defined _WIN32 || defined WINCE || defined __CYGWIN__) && defined CVAPI_EXPORTS -# define CV_EXPORTS __declspec(dllexport) -#elif defined __GNUC__ && __GNUC__ >= 4 -# define CV_EXPORTS __attribute__ ((visibility ("default"))) -#else -# define CV_EXPORTS +#ifdef CVAPI_EXPORTS +# if (defined _WIN32 || defined WINCE || defined __CYGWIN__) +# define CV_EXPORTS __declspec(dllexport) +# elif defined __GNUC__ && __GNUC__ >= 4 +# define CV_EXPORTS __attribute__ ((visibility ("default"))) +# endif #endif +#ifndef CV_EXPORTS +# define CV_EXPORTS +#endif + +#ifdef _MSC_VER +# define CV_EXPORTS_TEMPLATE +#else +# define CV_EXPORTS_TEMPLATE CV_EXPORTS +#endif + +#ifndef CV_DEPRECATED +# if defined(__GNUC__) +# define CV_DEPRECATED __attribute__ ((deprecated)) +# elif defined(_MSC_VER) +# define CV_DEPRECATED __declspec(deprecated) +# else +# define CV_DEPRECATED +# endif +#endif + +#ifndef CV_DEPRECATED_EXTERNAL +# if defined(__OPENCV_BUILD) +# define CV_DEPRECATED_EXTERNAL /* nothing */ +# else +# define CV_DEPRECATED_EXTERNAL CV_DEPRECATED +# endif +#endif + + #ifndef CV_EXTERN_C # ifdef __cplusplus # define CV_EXTERN_C extern "C" @@ -94,67 +398,6 @@ * Matrix type (Mat) * \****************************************************************************************/ -#define CV_CN_MAX 512 -#define CV_CN_SHIFT 3 -#define CV_DEPTH_MAX (1 << CV_CN_SHIFT) - -#define CV_8U 0 -#define CV_8S 1 -#define CV_16U 2 -#define CV_16S 3 -#define CV_32S 4 -#define CV_32F 5 -#define CV_64F 6 -#define CV_USRTYPE1 7 - -#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) -#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK) - -#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT)) -#define CV_MAKE_TYPE CV_MAKETYPE - -#define CV_8UC1 CV_MAKETYPE(CV_8U,1) -#define CV_8UC2 CV_MAKETYPE(CV_8U,2) -#define CV_8UC3 CV_MAKETYPE(CV_8U,3) -#define CV_8UC4 CV_MAKETYPE(CV_8U,4) -#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n)) - -#define CV_8SC1 CV_MAKETYPE(CV_8S,1) -#define CV_8SC2 CV_MAKETYPE(CV_8S,2) -#define CV_8SC3 CV_MAKETYPE(CV_8S,3) -#define CV_8SC4 CV_MAKETYPE(CV_8S,4) -#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n)) - -#define CV_16UC1 CV_MAKETYPE(CV_16U,1) -#define CV_16UC2 CV_MAKETYPE(CV_16U,2) -#define CV_16UC3 CV_MAKETYPE(CV_16U,3) -#define CV_16UC4 CV_MAKETYPE(CV_16U,4) -#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n)) - -#define CV_16SC1 CV_MAKETYPE(CV_16S,1) -#define CV_16SC2 CV_MAKETYPE(CV_16S,2) -#define CV_16SC3 CV_MAKETYPE(CV_16S,3) -#define CV_16SC4 CV_MAKETYPE(CV_16S,4) -#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n)) - -#define CV_32SC1 CV_MAKETYPE(CV_32S,1) -#define CV_32SC2 CV_MAKETYPE(CV_32S,2) -#define CV_32SC3 CV_MAKETYPE(CV_32S,3) -#define CV_32SC4 CV_MAKETYPE(CV_32S,4) -#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n)) - -#define CV_32FC1 CV_MAKETYPE(CV_32F,1) -#define CV_32FC2 CV_MAKETYPE(CV_32F,2) -#define CV_32FC3 CV_MAKETYPE(CV_32F,3) -#define CV_32FC4 CV_MAKETYPE(CV_32F,4) -#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n)) - -#define CV_64FC1 CV_MAKETYPE(CV_64F,1) -#define CV_64FC2 CV_MAKETYPE(CV_64F,2) -#define CV_64FC3 CV_MAKETYPE(CV_64F,3) -#define CV_64FC4 CV_MAKETYPE(CV_64F,4) -#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n)) - #define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) #define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) #define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) @@ -167,12 +410,12 @@ #define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT) #define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG) -/* Size of each channel item, - 0x124489 = 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */ +/** Size of each channel item, + 0x8442211 = 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */ #define CV_ELEM_SIZE1(type) \ ((((sizeof(size_t)<<28)|0x8442211) >> CV_MAT_DEPTH(type)*4) & 15) -/* 0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) */ +/** 0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) */ #define CV_ELEM_SIZE(type) \ (CV_MAT_CN(type) << ((((sizeof(size_t)/4+1)*16384|0x3a50) >> CV_MAT_DEPTH(type)*2) & 3)) @@ -184,14 +427,42 @@ # define MAX(a,b) ((a) < (b) ? (b) : (a)) #endif +/****************************************************************************************\ +* static analysys * +\****************************************************************************************/ + +// In practice, some macro are not processed correctly (noreturn is not detected). +// We need to use simplified definition for them. +#ifndef CV_STATIC_ANALYSIS +# if defined(__KLOCWORK__) || defined(__clang_analyzer__) || defined(__COVERITY__) +# define CV_STATIC_ANALYSIS 1 +# endif +#else +# if defined(CV_STATIC_ANALYSIS) && !(__CV_CAT(1, CV_STATIC_ANALYSIS) == 1) // defined and not empty +# if 0 == CV_STATIC_ANALYSIS +# undef CV_STATIC_ANALYSIS +# endif +# endif +#endif + +/****************************************************************************************\ +* Thread sanitizer * +\****************************************************************************************/ +#ifndef CV_THREAD_SANITIZER +# if defined(__has_feature) +# if __has_feature(thread_sanitizer) +# define CV_THREAD_SANITIZER +# endif +# endif +#endif + /****************************************************************************************\ * exchange-add operation for atomic operations on reference counters * \****************************************************************************************/ -#if defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) - // atomic increment on the linux version of the Intel(tm) compiler -# define CV_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) -#elif defined __GNUC__ +#ifdef CV_XADD + // allow to use user-defined macro +#elif defined __GNUC__ || defined __clang__ # if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) # ifdef __ATOMIC_ACQ_REL # define CV_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) @@ -228,4 +499,255 @@ # endif #endif -#endif // __OPENCV_CORE_CVDEF_H__ + +/****************************************************************************************\ +* CV_NODISCARD attribute * +* encourages the compiler to issue a warning if the return value is discarded (C++17) * +\****************************************************************************************/ +#ifndef CV_NODISCARD +# if defined(__GNUC__) +# define CV_NODISCARD __attribute__((__warn_unused_result__)) // at least available with GCC 3.4 +# elif defined(__clang__) && defined(__has_attribute) +# if __has_attribute(__warn_unused_result__) +# define CV_NODISCARD __attribute__((__warn_unused_result__)) +# endif +# endif +#endif +#ifndef CV_NODISCARD +# define CV_NODISCARD /* nothing by default */ +#endif + + +/****************************************************************************************\ +* C++ 11 * +\****************************************************************************************/ +#ifndef CV_CXX11 +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) +# define CV_CXX11 1 +# endif +#else +# if CV_CXX11 == 0 +# undef CV_CXX11 +# endif +#endif + + +/****************************************************************************************\ +* C++ Move semantics * +\****************************************************************************************/ + +#ifndef CV_CXX_MOVE_SEMANTICS +# if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(_MSC_VER) && _MSC_VER >= 1600) +# define CV_CXX_MOVE_SEMANTICS 1 +# elif defined(__clang) +# if __has_feature(cxx_rvalue_references) +# define CV_CXX_MOVE_SEMANTICS 1 +# endif +# endif +#else +# if CV_CXX_MOVE_SEMANTICS == 0 +# undef CV_CXX_MOVE_SEMANTICS +# endif +#endif + +/****************************************************************************************\ +* C++11 std::array * +\****************************************************************************************/ + +#ifndef CV_CXX_STD_ARRAY +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900/*MSVS 2015*/) +# define CV_CXX_STD_ARRAY 1 +# include +# endif +#else +# if CV_CXX_STD_ARRAY == 0 +# undef CV_CXX_STD_ARRAY +# endif +#endif + + +/****************************************************************************************\ +* C++11 override / final * +\****************************************************************************************/ + +#ifndef CV_OVERRIDE +# ifdef CV_CXX11 +# define CV_OVERRIDE override +# endif +#endif +#ifndef CV_OVERRIDE +# define CV_OVERRIDE +#endif + +#ifndef CV_FINAL +# ifdef CV_CXX11 +# define CV_FINAL final +# endif +#endif +#ifndef CV_FINAL +# define CV_FINAL +#endif + + + +// Integer types portatibility +#ifdef OPENCV_STDINT_HEADER +#include OPENCV_STDINT_HEADER +#elif defined(__cplusplus) +#if defined(_MSC_VER) && _MSC_VER < 1600 /* MSVS 2010 */ +namespace cv { +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +} +#elif defined(_MSC_VER) || __cplusplus >= 201103L +#include +namespace cv { +using std::int8_t; +using std::uint8_t; +using std::int16_t; +using std::uint16_t; +using std::int32_t; +using std::uint32_t; +using std::int64_t; +using std::uint64_t; +} +#else +#include +namespace cv { +typedef ::int8_t int8_t; +typedef ::uint8_t uint8_t; +typedef ::int16_t int16_t; +typedef ::uint16_t uint16_t; +typedef ::int32_t int32_t; +typedef ::uint32_t uint32_t; +typedef ::int64_t int64_t; +typedef ::uint64_t uint64_t; +} +#endif +#else // pure C +#include +#endif + +#ifdef __cplusplus +namespace cv +{ + +class float16_t +{ +public: +#if CV_FP16_TYPE + + float16_t() {} + explicit float16_t(float x) { h = (__fp16)x; } + operator float() const { return (float)h; } + static float16_t fromBits(ushort w) + { + Cv16suf u; + u.u = w; + float16_t result; + result.h = u.h; + return result; + } + static float16_t zero() + { + float16_t result; + result.h = (__fp16)0; + return result; + } + ushort bits() const + { + Cv16suf u; + u.h = h; + return u.u; + } +protected: + __fp16 h; + +#else + float16_t() {} + explicit float16_t(float x) + { + #if CV_AVX2 + __m128 v = _mm_load_ss(&x); + w = (ushort)_mm_cvtsi128_si32(_mm_cvtps_ph(v, 0)); + #else + Cv32suf in; + in.f = x; + unsigned sign = in.u & 0x80000000; + in.u ^= sign; + + if( in.u >= 0x47800000 ) + w = (ushort)(in.u > 0x7f800000 ? 0x7e00 : 0x7c00); + else + { + if (in.u < 0x38800000) + { + in.f += 0.5f; + w = (ushort)(in.u - 0x3f000000); + } + else + { + unsigned t = in.u + 0xc8000fff; + w = (ushort)((t + ((in.u >> 13) & 1)) >> 13); + } + } + + w = (ushort)(w | (sign >> 16)); + #endif + } + + operator float() const + { + #if CV_AVX2 + float f; + _mm_store_ss(&f, _mm_cvtph_ps(_mm_cvtsi32_si128(w))); + return f; + #else + Cv32suf out; + + unsigned t = ((w & 0x7fff) << 13) + 0x38000000; + unsigned sign = (w & 0x8000) << 16; + unsigned e = w & 0x7c00; + + out.u = t + (1 << 23); + out.u = (e >= 0x7c00 ? t + 0x38000000 : + e == 0 ? (out.f -= 6.103515625e-05f, out.u) : t) | sign; + return out.f; + #endif + } + + static float16_t fromBits(ushort b) + { + float16_t result; + result.w = b; + return result; + } + static float16_t zero() + { + float16_t result; + result.w = (ushort)0; + return result; + } + ushort bits() const { return w; } +protected: + ushort w; + +#endif +}; + +} +#endif + +//! @} + +#ifndef __cplusplus +#include "opencv2/core/fast_math.hpp" // define cvRound(double) +#endif + +#endif // OPENCV_CORE_CVDEF_H diff --git a/include/opencv2/core/cvstd.hpp b/include/opencv2/core/cvstd.hpp index a229f53..0a3f553 100644 --- a/include/opencv2/core/cvstd.hpp +++ b/include/opencv2/core/cvstd.hpp @@ -41,25 +41,21 @@ // //M*/ -#ifndef __OPENCV_CORE_CVSTD_HPP__ -#define __OPENCV_CORE_CVSTD_HPP__ +#ifndef OPENCV_CORE_CVSTD_HPP +#define OPENCV_CORE_CVSTD_HPP #ifndef __cplusplus # error cvstd.hpp header must be compiled as C++ #endif #include "opencv2/core/cvdef.h" - #include #include #include -#ifndef OPENCV_NOSTL -# include -#endif +#include // import useful primitives from stl -#ifndef OPENCV_NOSTL_TRANSITIONAL # include # include # include //for abs(int) @@ -67,6 +63,11 @@ namespace cv { + static inline uchar abs(uchar a) { return a; } + static inline ushort abs(ushort a) { return a; } + static inline unsigned abs(unsigned a) { return a; } + static inline uint64 abs(uint64 a) { return a; } + using std::min; using std::max; using std::abs; @@ -77,29 +78,6 @@ namespace cv using std::log; } -namespace std -{ - static inline uchar abs(uchar a) { return a; } - static inline ushort abs(ushort a) { return a; } - static inline unsigned abs(unsigned a) { return a; } - static inline uint64 abs(uint64 a) { return a; } -} - -#else -namespace cv -{ - template static inline T min(T a, T b) { return a < b ? a : b; } - template static inline T max(T a, T b) { return a > b ? a : b; } - template static inline T abs(T a) { return a < 0 ? -a : a; } - template static inline void swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } - - template<> inline uchar abs(uchar a) { return a; } - template<> inline ushort abs(ushort a) { return a; } - template<> inline unsigned abs(unsigned a) { return a; } - template<> inline uint64 abs(uint64 a) { return a; } -} -#endif - namespace cv { //! @addtogroup core_utils @@ -411,6 +389,11 @@ struct Ptr template Ptr dynamicCast() const; +#ifdef CV_CXX_MOVE_SEMANTICS + Ptr(Ptr&& o); + Ptr& operator = (Ptr&& o); +#endif + private: detail::PtrOwner* owner; T* stored; @@ -487,7 +470,7 @@ public: static const size_t npos = size_t(-1); - explicit String(); + String(); String(const String& str); String(const String& str, size_t pos, size_t len = npos); String(const char* s); @@ -554,7 +537,6 @@ public: String toLowerCase() const; -#ifndef OPENCV_NOSTL String(const std::string& str); String(const std::string& str, size_t pos, size_t len = npos); String& operator=(const std::string& str); @@ -563,7 +545,6 @@ public: friend String operator+ (const String& lhs, const std::string& rhs); friend String operator+ (const std::string& lhs, const String& rhs); -#endif private: char* cstr_; @@ -571,6 +552,8 @@ private: char* allocate(size_t len); // len without trailing 0 void deallocate(); + + String(int); // disabled and invalid. Catch invalid usages like, commandLineParser.has(0) problem }; //! @} core_basic @@ -615,6 +598,7 @@ String::String(const char* s) { if (!s) return; size_t len = strlen(s); + if (!len) return; memcpy(allocate(len), s, len); } @@ -623,6 +607,7 @@ String::String(const char* s, size_t n) : cstr_(0), len_(0) { if (!n) return; + if (!s) return; memcpy(allocate(n), s, n); } @@ -630,6 +615,7 @@ inline String::String(size_t n, char c) : cstr_(0), len_(0) { + if (!n) return; memset(allocate(n), c, n); } @@ -638,6 +624,7 @@ String::String(const char* first, const char* last) : cstr_(0), len_(0) { size_t len = (size_t)(last - first); + if (!len) return; memcpy(allocate(len), first, len); } @@ -646,6 +633,7 @@ String::String(Iterator first, Iterator last) : cstr_(0), len_(0) { size_t len = (size_t)(last - first); + if (!len) return; char* str = allocate(len); while (first != last) { @@ -678,7 +666,7 @@ String& String::operator=(const char* s) deallocate(); if (!s) return *this; size_t len = strlen(s); - memcpy(allocate(len), s, len); + if (len) memcpy(allocate(len), s, len); return *this; } @@ -744,7 +732,7 @@ const char* String::begin() const inline const char* String::end() const { - return len_ ? cstr_ + 1 : 0; + return len_ ? cstr_ + len_ : NULL; } inline @@ -896,6 +884,7 @@ size_t String::find_first_of(const String& str, size_t pos) const inline size_t String::find_first_of(const char* s, size_t pos) const { + if (len_ == 0) return npos; if (pos >= len_ || !s[0]) return npos; const char* lmax = cstr_ + len_; for (const char* i = cstr_ + pos; i < lmax; ++i) @@ -910,6 +899,7 @@ size_t String::find_first_of(const char* s, size_t pos) const inline size_t String::find_last_of(const char* s, size_t pos, size_t n) const { + if (len_ == 0) return npos; if (pos >= len_) pos = len_ - 1; for (const char* i = cstr_ + pos; i >= cstr_; --i) { @@ -935,6 +925,7 @@ size_t String::find_last_of(const String& str, size_t pos) const inline size_t String::find_last_of(const char* s, size_t pos) const { + if (len_ == 0) return npos; if (pos >= len_) pos = len_ - 1; for (const char* i = cstr_ + pos; i >= cstr_; --i) { @@ -948,8 +939,9 @@ size_t String::find_last_of(const char* s, size_t pos) const inline String String::toLowerCase() const { + if (!cstr_) + return String(); String res(cstr_, len_); - for (size_t i = 0; i < len_; ++i) res.cstr_[i] = (char) ::tolower(cstr_[i]); @@ -968,8 +960,8 @@ String operator + (const String& lhs, const String& rhs) { String s; s.allocate(lhs.len_ + rhs.len_); - memcpy(s.cstr_, lhs.cstr_, lhs.len_); - memcpy(s.cstr_ + lhs.len_, rhs.cstr_, rhs.len_); + if (lhs.len_) memcpy(s.cstr_, lhs.cstr_, lhs.len_); + if (rhs.len_) memcpy(s.cstr_ + lhs.len_, rhs.cstr_, rhs.len_); return s; } @@ -979,8 +971,8 @@ String operator + (const String& lhs, const char* rhs) String s; size_t rhslen = strlen(rhs); s.allocate(lhs.len_ + rhslen); - memcpy(s.cstr_, lhs.cstr_, lhs.len_); - memcpy(s.cstr_ + lhs.len_, rhs, rhslen); + if (lhs.len_) memcpy(s.cstr_, lhs.cstr_, lhs.len_); + if (rhslen) memcpy(s.cstr_ + lhs.len_, rhs, rhslen); return s; } @@ -990,8 +982,8 @@ String operator + (const char* lhs, const String& rhs) String s; size_t lhslen = strlen(lhs); s.allocate(lhslen + rhs.len_); - memcpy(s.cstr_, lhs, lhslen); - memcpy(s.cstr_ + lhslen, rhs.cstr_, rhs.len_); + if (lhslen) memcpy(s.cstr_, lhs, lhslen); + if (rhs.len_) memcpy(s.cstr_ + lhslen, rhs.cstr_, rhs.len_); return s; } @@ -1000,7 +992,7 @@ String operator + (const String& lhs, char rhs) { String s; s.allocate(lhs.len_ + 1); - memcpy(s.cstr_, lhs.cstr_, lhs.len_); + if (lhs.len_) memcpy(s.cstr_, lhs.cstr_, lhs.len_); s.cstr_[lhs.len_] = rhs; return s; } @@ -1011,7 +1003,7 @@ String operator + (char lhs, const String& rhs) String s; s.allocate(rhs.len_ + 1); s.cstr_[0] = lhs; - memcpy(s.cstr_ + 1, rhs.cstr_, rhs.len_); + if (rhs.len_) memcpy(s.cstr_ + 1, rhs.cstr_, rhs.len_); return s; } @@ -1038,22 +1030,11 @@ static inline bool operator>= (const String& lhs, const char* rhs) { return lh } // cv -#ifndef OPENCV_NOSTL_TRANSITIONAL namespace std { static inline void swap(cv::String& a, cv::String& b) { a.swap(b); } } -#else -namespace cv -{ - template<> inline - void swap(cv::String& a, cv::String& b) - { - a.swap(b); - } -} -#endif #include "opencv2/core/ptr.inl.hpp" -#endif //__OPENCV_CORE_CVSTD_HPP__ +#endif //OPENCV_CORE_CVSTD_HPP diff --git a/include/opencv2/core/cvstd.inl.hpp b/include/opencv2/core/cvstd.inl.hpp index 03bac37..ed37cac 100644 --- a/include/opencv2/core/cvstd.inl.hpp +++ b/include/opencv2/core/cvstd.inl.hpp @@ -41,19 +41,21 @@ // //M*/ -#ifndef __OPENCV_CORE_CVSTDINL_HPP__ -#define __OPENCV_CORE_CVSTDINL_HPP__ +#ifndef OPENCV_CORE_CVSTDINL_HPP +#define OPENCV_CORE_CVSTDINL_HPP -#ifndef OPENCV_NOSTL -# include -# include -#endif +#include +#include //! @cond IGNORED +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable: 4127 ) +#endif + namespace cv { -#ifndef OPENCV_NOSTL template class DataType< std::complex<_Tp> > { @@ -75,11 +77,8 @@ inline String::String(const std::string& str) : cstr_(0), len_(0) { - if (!str.empty()) - { - size_t len = str.size(); - memcpy(allocate(len), str.c_str(), len); - } + size_t len = str.size(); + if (len) memcpy(allocate(len), str.c_str(), len); } inline @@ -87,7 +86,7 @@ String::String(const std::string& str, size_t pos, size_t len) : cstr_(0), len_(0) { size_t strlen = str.size(); - pos = max(pos, strlen); + pos = min(pos, strlen); len = min(strlen - pos, len); if (!len) return; memcpy(allocate(len), str.c_str() + pos, len); @@ -97,11 +96,8 @@ inline String& String::operator = (const std::string& str) { deallocate(); - if (!str.empty()) - { - size_t len = str.size(); - memcpy(allocate(len), str.c_str(), len); - } + size_t len = str.size(); + if (len) memcpy(allocate(len), str.c_str(), len); return *this; } @@ -124,8 +120,8 @@ String operator + (const String& lhs, const std::string& rhs) String s; size_t rhslen = rhs.size(); s.allocate(lhs.len_ + rhslen); - memcpy(s.cstr_, lhs.cstr_, lhs.len_); - memcpy(s.cstr_ + lhs.len_, rhs.c_str(), rhslen); + if (lhs.len_) memcpy(s.cstr_, lhs.cstr_, lhs.len_); + if (rhslen) memcpy(s.cstr_ + lhs.len_, rhs.c_str(), rhslen); return s; } @@ -135,8 +131,8 @@ String operator + (const std::string& lhs, const String& rhs) String s; size_t lhslen = lhs.size(); s.allocate(lhslen + rhs.len_); - memcpy(s.cstr_, lhs.c_str(), lhslen); - memcpy(s.cstr_ + lhslen, rhs.cstr_, rhs.len_); + if (lhslen) memcpy(s.cstr_, lhs.c_str(), lhslen); + if (rhs.len_) memcpy(s.cstr_ + lhslen, rhs.cstr_, rhs.len_); return s; } @@ -151,9 +147,7 @@ FileNode::operator std::string() const template<> inline void operator >> (const FileNode& n, std::string& value) { - String val; - read(n, val, val); - value = val; + read(n, value, std::string()); } template<> inline @@ -183,6 +177,18 @@ std::ostream& operator << (std::ostream& out, const Mat& mtx) return out << Formatter::get()->format(mtx); } +static inline +std::ostream& operator << (std::ostream& out, const UMat& m) +{ + return out << m.getMat(ACCESS_READ); +} + +template static inline +std::ostream& operator << (std::ostream& out, const Complex<_Tp>& c) +{ + return out << "(" << c.re << "," << c.im << ")"; +} + template static inline std::ostream& operator << (std::ostream& out, const std::vector >& vec) { @@ -221,14 +227,7 @@ template static inline std::ostream& operator << (std::ostream& out, const Vec<_Tp, n>& vec) { out << "["; -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable: 4127 ) -#endif - if(Vec<_Tp, n>::depth < CV_32F) -#ifdef _MSC_VER -#pragma warning( pop ) -#endif + if (cv::traits::Depth<_Tp>::value <= CV_32S) { for (int i = 0; i < n - 1; ++i) { out << (int)vec[i] << ", "; @@ -258,10 +257,29 @@ std::ostream& operator << (std::ostream& out, const Rect_<_Tp>& rect) return out << "[" << rect.width << " x " << rect.height << " from (" << rect.x << ", " << rect.y << ")]"; } +static inline std::ostream& operator << (std::ostream& out, const MatSize& msize) +{ + int i, dims = msize.dims(); + for( i = 0; i < dims; i++ ) + { + out << msize[i]; + if( i < dims-1 ) + out << " x "; + } + return out; +} + +static inline std::ostream &operator<< (std::ostream &s, cv::Range &r) +{ + return s << "[" << r.start << " : " << r.end << ")"; +} -#endif // OPENCV_NOSTL } // cv +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + //! @endcond -#endif // __OPENCV_CORE_CVSTDINL_HPP__ +#endif // OPENCV_CORE_CVSTDINL_HPP diff --git a/include/opencv2/core/directx.hpp b/include/opencv2/core/directx.hpp index 837548e..056a85a 100644 --- a/include/opencv2/core/directx.hpp +++ b/include/opencv2/core/directx.hpp @@ -39,8 +39,8 @@ // //M*/ -#ifndef __OPENCV_CORE_DIRECTX_HPP__ -#define __OPENCV_CORE_DIRECTX_HPP__ +#ifndef OPENCV_CORE_DIRECTX_HPP +#define OPENCV_CORE_DIRECTX_HPP #include "mat.hpp" #include "ocl.hpp" @@ -68,12 +68,38 @@ namespace ocl { using namespace cv::ocl; //! @addtogroup core_directx +// This section describes OpenCL and DirectX interoperability. +// +// To enable DirectX support, configure OpenCV using CMake with WITH_DIRECTX=ON . Note, DirectX is +// supported only on Windows. +// +// To use OpenCL functionality you should first initialize OpenCL context from DirectX resource. +// //! @{ // TODO static functions in the Context class +//! @brief Creates OpenCL context from D3D11 device +// +//! @param pD3D11Device - pointer to D3D11 device +//! @return Returns reference to OpenCL Context CV_EXPORTS Context& initializeContextFromD3D11Device(ID3D11Device* pD3D11Device); + +//! @brief Creates OpenCL context from D3D10 device +// +//! @param pD3D10Device - pointer to D3D10 device +//! @return Returns reference to OpenCL Context CV_EXPORTS Context& initializeContextFromD3D10Device(ID3D10Device* pD3D10Device); + +//! @brief Creates OpenCL context from Direct3DDevice9Ex device +// +//! @param pDirect3DDevice9Ex - pointer to Direct3DDevice9Ex device +//! @return Returns reference to OpenCL Context CV_EXPORTS Context& initializeContextFromDirect3DDevice9Ex(IDirect3DDevice9Ex* pDirect3DDevice9Ex); + +//! @brief Creates OpenCL context from Direct3DDevice9 device +// +//! @param pDirect3DDevice9 - pointer to Direct3Device9 device +//! @return Returns reference to OpenCL Context CV_EXPORTS Context& initializeContextFromDirect3DDevice9(IDirect3DDevice9* pDirect3DDevice9); //! @} @@ -83,23 +109,76 @@ CV_EXPORTS Context& initializeContextFromDirect3DDevice9(IDirect3DDevice9* pDire //! @addtogroup core_directx //! @{ +//! @brief Converts InputArray to ID3D11Texture2D. If destination texture format is DXGI_FORMAT_NV12 then +//! input UMat expected to be in BGR format and data will be downsampled and color-converted to NV12. +// +//! @note Note: Destination texture must be allocated by application. Function does memory copy from src to +//! pD3D11Texture2D +// +//! @param src - source InputArray +//! @param pD3D11Texture2D - destination D3D11 texture CV_EXPORTS void convertToD3D11Texture2D(InputArray src, ID3D11Texture2D* pD3D11Texture2D); + +//! @brief Converts ID3D11Texture2D to OutputArray. If input texture format is DXGI_FORMAT_NV12 then +//! data will be upsampled and color-converted to BGR format. +// +//! @note Note: Destination matrix will be re-allocated if it has not enough memory to match texture size. +//! function does memory copy from pD3D11Texture2D to dst +// +//! @param pD3D11Texture2D - source D3D11 texture +//! @param dst - destination OutputArray CV_EXPORTS void convertFromD3D11Texture2D(ID3D11Texture2D* pD3D11Texture2D, OutputArray dst); +//! @brief Converts InputArray to ID3D10Texture2D +// +//! @note Note: function does memory copy from src to +//! pD3D10Texture2D +// +//! @param src - source InputArray +//! @param pD3D10Texture2D - destination D3D10 texture CV_EXPORTS void convertToD3D10Texture2D(InputArray src, ID3D10Texture2D* pD3D10Texture2D); + +//! @brief Converts ID3D10Texture2D to OutputArray +// +//! @note Note: function does memory copy from pD3D10Texture2D +//! to dst +// +//! @param pD3D10Texture2D - source D3D10 texture +//! @param dst - destination OutputArray CV_EXPORTS void convertFromD3D10Texture2D(ID3D10Texture2D* pD3D10Texture2D, OutputArray dst); +//! @brief Converts InputArray to IDirect3DSurface9 +// +//! @note Note: function does memory copy from src to +//! pDirect3DSurface9 +// +//! @param src - source InputArray +//! @param pDirect3DSurface9 - destination D3D10 texture +//! @param surfaceSharedHandle - shared handle CV_EXPORTS void convertToDirect3DSurface9(InputArray src, IDirect3DSurface9* pDirect3DSurface9, void* surfaceSharedHandle = NULL); + +//! @brief Converts IDirect3DSurface9 to OutputArray +// +//! @note Note: function does memory copy from pDirect3DSurface9 +//! to dst +// +//! @param pDirect3DSurface9 - source D3D10 texture +//! @param dst - destination OutputArray +//! @param surfaceSharedHandle - shared handle CV_EXPORTS void convertFromDirect3DSurface9(IDirect3DSurface9* pDirect3DSurface9, OutputArray dst, void* surfaceSharedHandle = NULL); -// Get OpenCV type from DirectX type, return -1 if there is no equivalent +//! @brief Get OpenCV type from DirectX type +//! @param iDXGI_FORMAT - enum DXGI_FORMAT for D3D10/D3D11 +//! @return OpenCV type or -1 if there is no equivalent CV_EXPORTS int getTypeFromDXGI_FORMAT(const int iDXGI_FORMAT); // enum DXGI_FORMAT for D3D10/D3D11 -// Get OpenCV type from DirectX type, return -1 if there is no equivalent +//! @brief Get OpenCV type from DirectX type +//! @param iD3DFORMAT - enum D3DTYPE for D3D9 +//! @return OpenCV type or -1 if there is no equivalent CV_EXPORTS int getTypeFromD3DFORMAT(const int iD3DFORMAT); // enum D3DTYPE for D3D9 //! @} } } // namespace cv::directx -#endif // __OPENCV_CORE_DIRECTX_HPP__ +#endif // OPENCV_CORE_DIRECTX_HPP diff --git a/include/opencv2/core/eigen.hpp b/include/opencv2/core/eigen.hpp index 44df04c..741648e 100644 --- a/include/opencv2/core/eigen.hpp +++ b/include/opencv2/core/eigen.hpp @@ -42,8 +42,8 @@ //M*/ -#ifndef __OPENCV_CORE_EIGEN_HPP__ -#define __OPENCV_CORE_EIGEN_HPP__ +#ifndef OPENCV_CORE_EIGEN_HPP +#define OPENCV_CORE_EIGEN_HPP #include "opencv2/core.hpp" @@ -60,18 +60,18 @@ namespace cv //! @{ template static inline -void eigen2cv( const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, Mat& dst ) +void eigen2cv( const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, OutputArray dst ) { if( !(src.Flags & Eigen::RowMajorBit) ) { - Mat _src(src.cols(), src.rows(), DataType<_Tp>::type, - (void*)src.data(), src.stride()*sizeof(_Tp)); + Mat _src(src.cols(), src.rows(), traits::Type<_Tp>::value, + (void*)src.data(), src.outerStride()*sizeof(_Tp)); transpose(_src, dst); } else { - Mat _src(src.rows(), src.cols(), DataType<_Tp>::type, - (void*)src.data(), src.stride()*sizeof(_Tp)); + Mat _src(src.rows(), src.cols(), traits::Type<_Tp>::value, + (void*)src.data(), src.outerStride()*sizeof(_Tp)); _src.copyTo(dst); } } @@ -98,8 +98,8 @@ void cv2eigen( const Mat& src, CV_DbgAssert(src.rows == _rows && src.cols == _cols); if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(src.cols, src.rows, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); if( src.type() == _dst.type() ) transpose(src, _dst); else if( src.cols == src.rows ) @@ -112,8 +112,8 @@ void cv2eigen( const Mat& src, } else { - const Mat _dst(src.rows, src.cols, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); src.convertTo(_dst, _dst.type()); } } @@ -125,14 +125,14 @@ void cv2eigen( const Matx<_Tp, _rows, _cols>& src, { if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(_cols, _rows, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(_cols, _rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); transpose(src, _dst); } else { - const Mat _dst(_rows, _cols, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(_rows, _cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); Mat(src).copyTo(_dst); } } @@ -144,8 +144,8 @@ void cv2eigen( const Mat& src, dst.resize(src.rows, src.cols); if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(src.cols, src.rows, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); if( src.type() == _dst.type() ) transpose(src, _dst); else if( src.cols == src.rows ) @@ -158,8 +158,8 @@ void cv2eigen( const Mat& src, } else { - const Mat _dst(src.rows, src.cols, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); src.convertTo(_dst, _dst.type()); } } @@ -172,14 +172,14 @@ void cv2eigen( const Matx<_Tp, _rows, _cols>& src, dst.resize(_rows, _cols); if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(_cols, _rows, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(_cols, _rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); transpose(src, _dst); } else { - const Mat _dst(_rows, _cols, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(_rows, _cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); Mat(src).copyTo(_dst); } } @@ -193,8 +193,8 @@ void cv2eigen( const Mat& src, if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(src.cols, src.rows, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); if( src.type() == _dst.type() ) transpose(src, _dst); else @@ -202,8 +202,8 @@ void cv2eigen( const Mat& src, } else { - const Mat _dst(src.rows, src.cols, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); src.convertTo(_dst, _dst.type()); } } @@ -217,14 +217,14 @@ void cv2eigen( const Matx<_Tp, _rows, 1>& src, if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(1, _rows, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(1, _rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); transpose(src, _dst); } else { - const Mat _dst(_rows, 1, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(_rows, 1, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); src.copyTo(_dst); } } @@ -238,8 +238,8 @@ void cv2eigen( const Mat& src, dst.resize(src.cols); if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(src.cols, src.rows, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); if( src.type() == _dst.type() ) transpose(src, _dst); else @@ -247,8 +247,8 @@ void cv2eigen( const Mat& src, } else { - const Mat _dst(src.rows, src.cols, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); src.convertTo(_dst, _dst.type()); } } @@ -261,14 +261,14 @@ void cv2eigen( const Matx<_Tp, 1, _cols>& src, dst.resize(_cols); if( !(dst.Flags & Eigen::RowMajorBit) ) { - const Mat _dst(_cols, 1, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(_cols, 1, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); transpose(src, _dst); } else { - const Mat _dst(1, _cols, DataType<_Tp>::type, - dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + const Mat _dst(1, _cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); Mat(src).copyTo(_dst); } } diff --git a/include/opencv2/core/fast_math.hpp b/include/opencv2/core/fast_math.hpp new file mode 100644 index 0000000..d9ea28e --- /dev/null +++ b/include/opencv2/core/fast_math.hpp @@ -0,0 +1,271 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_FAST_MATH_HPP +#define OPENCV_CORE_FAST_MATH_HPP + +#include "opencv2/core/cvdef.h" + +#if ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ + && defined __SSE2__ && !defined __APPLE__)) && !defined(__CUDACC__) +#include +#endif + + +//! @addtogroup core_utils +//! @{ + +/****************************************************************************************\ +* fast math * +\****************************************************************************************/ + +#ifdef __cplusplus +# include +#else +# ifdef __BORLANDC__ +# include +# else +# include +# endif +#endif + +#ifdef HAVE_TEGRA_OPTIMIZATION +# include "tegra_round.hpp" +#endif + +#if defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__ || defined __ARM_NEON__) && !defined __SOFTFP__ && !defined(__CUDACC__) + // 1. general scheme + #define ARM_ROUND(_value, _asm_string) \ + int res; \ + float temp; \ + CV_UNUSED(temp); \ + __asm__(_asm_string : [res] "=r" (res), [temp] "=w" (temp) : [value] "w" (_value)); \ + return res + // 2. version for double + #ifdef __clang__ + #define ARM_ROUND_DBL(value) ARM_ROUND(value, "vcvtr.s32.f64 %[temp], %[value] \n vmov %[res], %[temp]") + #else + #define ARM_ROUND_DBL(value) ARM_ROUND(value, "vcvtr.s32.f64 %[temp], %P[value] \n vmov %[res], %[temp]") + #endif + // 3. version for float + #define ARM_ROUND_FLT(value) ARM_ROUND(value, "vcvtr.s32.f32 %[temp], %[value]\n vmov %[res], %[temp]") +#endif + +/** @brief Rounds floating-point number to the nearest integer + + @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the + result is not defined. + */ +CV_INLINE int +cvRound( double value ) +{ +#if ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ + && defined __SSE2__ && !defined __APPLE__) || CV_SSE2) && !defined(__CUDACC__) + __m128d t = _mm_set_sd( value ); + return _mm_cvtsd_si32(t); +#elif defined _MSC_VER && defined _M_IX86 + int t; + __asm + { + fld value; + fistp t; + } + return t; +#elif ((defined _MSC_VER && defined _M_ARM) || defined CV_ICC || \ + defined __GNUC__) && defined HAVE_TEGRA_OPTIMIZATION + TEGRA_ROUND_DBL(value); +#elif defined CV_ICC || defined __GNUC__ +# if defined ARM_ROUND_DBL + ARM_ROUND_DBL(value); +# else + return (int)lrint(value); +# endif +#else + /* it's ok if round does not comply with IEEE754 standard; + the tests should allow +/-1 difference when the tested functions use round */ + return (int)(value + (value >= 0 ? 0.5 : -0.5)); +#endif +} + + +/** @brief Rounds floating-point number to the nearest integer not larger than the original. + + The function computes an integer i such that: + \f[i \le \texttt{value} < i+1\f] + @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the + result is not defined. + */ +CV_INLINE int cvFloor( double value ) +{ + int i = (int)value; + return i - (i > value); +} + +/** @brief Rounds floating-point number to the nearest integer not smaller than the original. + + The function computes an integer i such that: + \f[i \le \texttt{value} < i+1\f] + @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the + result is not defined. + */ +CV_INLINE int cvCeil( double value ) +{ + int i = (int)value; + return i + (i < value); +} + +/** @brief Determines if the argument is Not A Number. + + @param value The input floating-point value + + The function returns 1 if the argument is Not A Number (as defined by IEEE754 standard), 0 + otherwise. */ +CV_INLINE int cvIsNaN( double value ) +{ + Cv64suf ieee754; + ieee754.f = value; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) + + ((unsigned)ieee754.u != 0) > 0x7ff00000; +} + +/** @brief Determines if the argument is Infinity. + + @param value The input floating-point value + + The function returns 1 if the argument is a plus or minus infinity (as defined by IEEE754 standard) + and 0 otherwise. */ +CV_INLINE int cvIsInf( double value ) +{ + Cv64suf ieee754; + ieee754.f = value; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + (unsigned)ieee754.u == 0; +} + +#ifdef __cplusplus + +/** @overload */ +CV_INLINE int cvRound(float value) +{ +#if ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ + && defined __SSE2__ && !defined __APPLE__) || CV_SSE2) && !defined(__CUDACC__) + __m128 t = _mm_set_ss( value ); + return _mm_cvtss_si32(t); +#elif defined _MSC_VER && defined _M_IX86 + int t; + __asm + { + fld value; + fistp t; + } + return t; +#elif ((defined _MSC_VER && defined _M_ARM) || defined CV_ICC || \ + defined __GNUC__) && defined HAVE_TEGRA_OPTIMIZATION + TEGRA_ROUND_FLT(value); +#elif defined CV_ICC || defined __GNUC__ +# if defined ARM_ROUND_FLT + ARM_ROUND_FLT(value); +# else + return (int)lrintf(value); +# endif +#else + /* it's ok if round does not comply with IEEE754 standard; + the tests should allow +/-1 difference when the tested functions use round */ + return (int)(value + (value >= 0 ? 0.5f : -0.5f)); +#endif +} + +/** @overload */ +CV_INLINE int cvRound( int value ) +{ + return value; +} + +/** @overload */ +CV_INLINE int cvFloor( float value ) +{ + int i = (int)value; + return i - (i > value); +} + +/** @overload */ +CV_INLINE int cvFloor( int value ) +{ + return value; +} + +/** @overload */ +CV_INLINE int cvCeil( float value ) +{ + int i = (int)value; + return i + (i < value); +} + +/** @overload */ +CV_INLINE int cvCeil( int value ) +{ + return value; +} + +/** @overload */ +CV_INLINE int cvIsNaN( float value ) +{ + Cv32suf ieee754; + ieee754.f = value; + return (ieee754.u & 0x7fffffff) > 0x7f800000; +} + +/** @overload */ +CV_INLINE int cvIsInf( float value ) +{ + Cv32suf ieee754; + ieee754.f = value; + return (ieee754.u & 0x7fffffff) == 0x7f800000; +} + +#endif // __cplusplus + +//! @} core_utils + +#endif diff --git a/include/opencv2/core/hal/hal.hpp b/include/opencv2/core/hal/hal.hpp new file mode 100644 index 0000000..68900ec --- /dev/null +++ b/include/opencv2/core/hal/hal.hpp @@ -0,0 +1,250 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_HAL_HPP +#define OPENCV_HAL_HPP + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" +#include "opencv2/core/hal/interface.h" + +namespace cv { namespace hal { + +//! @addtogroup core_hal_functions +//! @{ + +CV_EXPORTS int normHamming(const uchar* a, int n); +CV_EXPORTS int normHamming(const uchar* a, const uchar* b, int n); + +CV_EXPORTS int normHamming(const uchar* a, int n, int cellSize); +CV_EXPORTS int normHamming(const uchar* a, const uchar* b, int n, int cellSize); + +CV_EXPORTS int LU32f(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS int LU64f(double* A, size_t astep, int m, double* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky32f(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky64f(double* A, size_t astep, int m, double* b, size_t bstep, int n); +CV_EXPORTS void SVD32f(float* At, size_t astep, float* W, float* U, size_t ustep, float* Vt, size_t vstep, int m, int n, int flags); +CV_EXPORTS void SVD64f(double* At, size_t astep, double* W, double* U, size_t ustep, double* Vt, size_t vstep, int m, int n, int flags); +CV_EXPORTS int QR32f(float* A, size_t astep, int m, int n, int k, float* b, size_t bstep, float* hFactors); +CV_EXPORTS int QR64f(double* A, size_t astep, int m, int n, int k, double* b, size_t bstep, double* hFactors); + +CV_EXPORTS void gemm32f(const float* src1, size_t src1_step, const float* src2, size_t src2_step, + float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); +CV_EXPORTS void gemm64f(const double* src1, size_t src1_step, const double* src2, size_t src2_step, + double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); +CV_EXPORTS void gemm32fc(const float* src1, size_t src1_step, const float* src2, size_t src2_step, + float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); +CV_EXPORTS void gemm64fc(const double* src1, size_t src1_step, const double* src2, size_t src2_step, + double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); + +CV_EXPORTS int normL1_(const uchar* a, const uchar* b, int n); +CV_EXPORTS float normL1_(const float* a, const float* b, int n); +CV_EXPORTS float normL2Sqr_(const float* a, const float* b, int n); + +CV_EXPORTS void exp32f(const float* src, float* dst, int n); +CV_EXPORTS void exp64f(const double* src, double* dst, int n); +CV_EXPORTS void log32f(const float* src, float* dst, int n); +CV_EXPORTS void log64f(const double* src, double* dst, int n); + +CV_EXPORTS void fastAtan32f(const float* y, const float* x, float* dst, int n, bool angleInDegrees); +CV_EXPORTS void fastAtan64f(const double* y, const double* x, double* dst, int n, bool angleInDegrees); +CV_EXPORTS void magnitude32f(const float* x, const float* y, float* dst, int n); +CV_EXPORTS void magnitude64f(const double* x, const double* y, double* dst, int n); +CV_EXPORTS void sqrt32f(const float* src, float* dst, int len); +CV_EXPORTS void sqrt64f(const double* src, double* dst, int len); +CV_EXPORTS void invSqrt32f(const float* src, float* dst, int len); +CV_EXPORTS void invSqrt64f(const double* src, double* dst, int len); + +CV_EXPORTS void split8u(const uchar* src, uchar** dst, int len, int cn ); +CV_EXPORTS void split16u(const ushort* src, ushort** dst, int len, int cn ); +CV_EXPORTS void split32s(const int* src, int** dst, int len, int cn ); +CV_EXPORTS void split64s(const int64* src, int64** dst, int len, int cn ); + +CV_EXPORTS void merge8u(const uchar** src, uchar* dst, int len, int cn ); +CV_EXPORTS void merge16u(const ushort** src, ushort* dst, int len, int cn ); +CV_EXPORTS void merge32s(const int** src, int* dst, int len, int cn ); +CV_EXPORTS void merge64s(const int64** src, int64* dst, int len, int cn ); + +CV_EXPORTS void add8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void sub8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void max8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void min8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void absdiff8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void and8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void or8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void xor8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void not8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void cmp8u(const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp8s(const schar* src1, size_t step1, const schar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp16u(const ushort* src1, size_t step1, const ushort* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp16s(const short* src1, size_t step1, const short* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp32s(const int* src1, size_t step1, const int* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp32f(const float* src1, size_t step1, const float* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp64f(const double* src1, size_t step1, const double* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); + +CV_EXPORTS void mul8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scale); + +CV_EXPORTS void div8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scale); + +CV_EXPORTS void recip8u( const uchar *, size_t, const uchar * src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip8s( const schar *, size_t, const schar * src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip16u( const ushort *, size_t, const ushort * src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip16s( const short *, size_t, const short * src2, size_t step2, short* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip32s( const int *, size_t, const int * src2, size_t step2, int* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip32f( const float *, size_t, const float * src2, size_t step2, float* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip64f( const double *, size_t, const double * src2, size_t step2, double* dst, size_t step, int width, int height, void* scale); + +CV_EXPORTS void addWeighted8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _scalars ); +CV_EXPORTS void addWeighted8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scalars ); + +struct CV_EXPORTS DFT1D +{ + static Ptr create(int len, int count, int depth, int flags, bool * useBuffer = 0); + virtual void apply(const uchar *src, uchar *dst) = 0; + virtual ~DFT1D() {} +}; + +struct CV_EXPORTS DFT2D +{ + static Ptr create(int width, int height, int depth, + int src_channels, int dst_channels, + int flags, int nonzero_rows = 0); + virtual void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) = 0; + virtual ~DFT2D() {} +}; + +struct CV_EXPORTS DCT2D +{ + static Ptr create(int width, int height, int depth, int flags); + virtual void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) = 0; + virtual ~DCT2D() {} +}; + +//! @} core_hal + +//============================================================================= +// for binary compatibility with 3.0 + +//! @cond IGNORED + +CV_EXPORTS int LU(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS int LU(double* A, size_t astep, int m, double* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky(double* A, size_t astep, int m, double* b, size_t bstep, int n); + +CV_EXPORTS void exp(const float* src, float* dst, int n); +CV_EXPORTS void exp(const double* src, double* dst, int n); +CV_EXPORTS void log(const float* src, float* dst, int n); +CV_EXPORTS void log(const double* src, double* dst, int n); + +CV_EXPORTS void fastAtan2(const float* y, const float* x, float* dst, int n, bool angleInDegrees); +CV_EXPORTS void magnitude(const float* x, const float* y, float* dst, int n); +CV_EXPORTS void magnitude(const double* x, const double* y, double* dst, int n); +CV_EXPORTS void sqrt(const float* src, float* dst, int len); +CV_EXPORTS void sqrt(const double* src, double* dst, int len); +CV_EXPORTS void invSqrt(const float* src, float* dst, int len); +CV_EXPORTS void invSqrt(const double* src, double* dst, int len); + +//! @endcond + +}} //cv::hal + +#endif //OPENCV_HAL_HPP diff --git a/include/opencv2/core/hal/interface.h b/include/opencv2/core/hal/interface.h new file mode 100644 index 0000000..8f64025 --- /dev/null +++ b/include/opencv2/core/hal/interface.h @@ -0,0 +1,182 @@ +#ifndef OPENCV_CORE_HAL_INTERFACE_H +#define OPENCV_CORE_HAL_INTERFACE_H + +//! @addtogroup core_hal_interface +//! @{ + +//! @name Return codes +//! @{ +#define CV_HAL_ERROR_OK 0 +#define CV_HAL_ERROR_NOT_IMPLEMENTED 1 +#define CV_HAL_ERROR_UNKNOWN -1 +//! @} + +#ifdef __cplusplus +#include +#else +#include +#include +#endif + +//! @name Data types +//! primitive types +//! - schar - signed 1 byte integer +//! - uchar - unsigned 1 byte integer +//! - short - signed 2 byte integer +//! - ushort - unsigned 2 byte integer +//! - int - signed 4 byte integer +//! - uint - unsigned 4 byte integer +//! - int64 - signed 8 byte integer +//! - uint64 - unsigned 8 byte integer +//! @{ +#if !defined _MSC_VER && !defined __BORLANDC__ +# if defined __cplusplus && __cplusplus >= 201103L && !defined __APPLE__ +# include +# ifdef __NEWLIB__ + typedef unsigned int uint; +# else + typedef std::uint32_t uint; +# endif +# else +# include + typedef uint32_t uint; +# endif +#else + typedef unsigned uint; +#endif + +typedef signed char schar; + +#ifndef __IPL_H__ + typedef unsigned char uchar; + typedef unsigned short ushort; +#endif + +#if defined _MSC_VER || defined __BORLANDC__ + typedef __int64 int64; + typedef unsigned __int64 uint64; +# define CV_BIG_INT(n) n##I64 +# define CV_BIG_UINT(n) n##UI64 +#else + typedef int64_t int64; + typedef uint64_t uint64; +# define CV_BIG_INT(n) n##LL +# define CV_BIG_UINT(n) n##ULL +#endif + +#define CV_CN_MAX 512 +#define CV_CN_SHIFT 3 +#define CV_DEPTH_MAX (1 << CV_CN_SHIFT) + +#define CV_8U 0 +#define CV_8S 1 +#define CV_16U 2 +#define CV_16S 3 +#define CV_32S 4 +#define CV_32F 5 +#define CV_64F 6 +#define CV_USRTYPE1 7 + +#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) +#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK) + +#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT)) +#define CV_MAKE_TYPE CV_MAKETYPE + +#define CV_8UC1 CV_MAKETYPE(CV_8U,1) +#define CV_8UC2 CV_MAKETYPE(CV_8U,2) +#define CV_8UC3 CV_MAKETYPE(CV_8U,3) +#define CV_8UC4 CV_MAKETYPE(CV_8U,4) +#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n)) + +#define CV_8SC1 CV_MAKETYPE(CV_8S,1) +#define CV_8SC2 CV_MAKETYPE(CV_8S,2) +#define CV_8SC3 CV_MAKETYPE(CV_8S,3) +#define CV_8SC4 CV_MAKETYPE(CV_8S,4) +#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n)) + +#define CV_16UC1 CV_MAKETYPE(CV_16U,1) +#define CV_16UC2 CV_MAKETYPE(CV_16U,2) +#define CV_16UC3 CV_MAKETYPE(CV_16U,3) +#define CV_16UC4 CV_MAKETYPE(CV_16U,4) +#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n)) + +#define CV_16SC1 CV_MAKETYPE(CV_16S,1) +#define CV_16SC2 CV_MAKETYPE(CV_16S,2) +#define CV_16SC3 CV_MAKETYPE(CV_16S,3) +#define CV_16SC4 CV_MAKETYPE(CV_16S,4) +#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n)) + +#define CV_32SC1 CV_MAKETYPE(CV_32S,1) +#define CV_32SC2 CV_MAKETYPE(CV_32S,2) +#define CV_32SC3 CV_MAKETYPE(CV_32S,3) +#define CV_32SC4 CV_MAKETYPE(CV_32S,4) +#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n)) + +#define CV_32FC1 CV_MAKETYPE(CV_32F,1) +#define CV_32FC2 CV_MAKETYPE(CV_32F,2) +#define CV_32FC3 CV_MAKETYPE(CV_32F,3) +#define CV_32FC4 CV_MAKETYPE(CV_32F,4) +#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n)) + +#define CV_64FC1 CV_MAKETYPE(CV_64F,1) +#define CV_64FC2 CV_MAKETYPE(CV_64F,2) +#define CV_64FC3 CV_MAKETYPE(CV_64F,3) +#define CV_64FC4 CV_MAKETYPE(CV_64F,4) +#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n)) +//! @} + +//! @name Comparison operation +//! @sa cv::CmpTypes +//! @{ +#define CV_HAL_CMP_EQ 0 +#define CV_HAL_CMP_GT 1 +#define CV_HAL_CMP_GE 2 +#define CV_HAL_CMP_LT 3 +#define CV_HAL_CMP_LE 4 +#define CV_HAL_CMP_NE 5 +//! @} + +//! @name Border processing modes +//! @sa cv::BorderTypes +//! @{ +#define CV_HAL_BORDER_CONSTANT 0 +#define CV_HAL_BORDER_REPLICATE 1 +#define CV_HAL_BORDER_REFLECT 2 +#define CV_HAL_BORDER_WRAP 3 +#define CV_HAL_BORDER_REFLECT_101 4 +#define CV_HAL_BORDER_TRANSPARENT 5 +#define CV_HAL_BORDER_ISOLATED 16 +//! @} + +//! @name DFT flags +//! @{ +#define CV_HAL_DFT_INVERSE 1 +#define CV_HAL_DFT_SCALE 2 +#define CV_HAL_DFT_ROWS 4 +#define CV_HAL_DFT_COMPLEX_OUTPUT 16 +#define CV_HAL_DFT_REAL_OUTPUT 32 +#define CV_HAL_DFT_TWO_STAGE 64 +#define CV_HAL_DFT_STAGE_COLS 128 +#define CV_HAL_DFT_IS_CONTINUOUS 512 +#define CV_HAL_DFT_IS_INPLACE 1024 +//! @} + +//! @name SVD flags +//! @{ +#define CV_HAL_SVD_NO_UV 1 +#define CV_HAL_SVD_SHORT_UV 2 +#define CV_HAL_SVD_MODIFY_A 4 +#define CV_HAL_SVD_FULL_UV 8 +//! @} + +//! @name Gemm flags +//! @{ +#define CV_HAL_GEMM_1_T 1 +#define CV_HAL_GEMM_2_T 2 +#define CV_HAL_GEMM_3_T 4 +//! @} + +//! @} + +#endif diff --git a/include/opencv2/core/hal/intrin.hpp b/include/opencv2/core/hal/intrin.hpp new file mode 100644 index 0000000..ef74176 --- /dev/null +++ b/include/opencv2/core/hal/intrin.hpp @@ -0,0 +1,420 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_HAL_INTRIN_HPP +#define OPENCV_HAL_INTRIN_HPP + +#include +#include +#include +#include "opencv2/core/cvdef.h" + +#define OPENCV_HAL_ADD(a, b) ((a) + (b)) +#define OPENCV_HAL_AND(a, b) ((a) & (b)) +#define OPENCV_HAL_NOP(a) (a) +#define OPENCV_HAL_1ST(a, b) (a) + +// unlike HAL API, which is in cv::hal, +// we put intrinsics into cv namespace to make its +// access from within opencv code more accessible +namespace cv { + +namespace hal { + +enum StoreMode +{ + STORE_UNALIGNED = 0, + STORE_ALIGNED = 1, + STORE_ALIGNED_NOCACHE = 2 +}; + +} + +template struct V_TypeTraits +{ +}; + +#define CV_INTRIN_DEF_TYPE_TRAITS(type, int_type_, uint_type_, abs_type_, w_type_, q_type_, sum_type_, nlanes128_) \ + template<> struct V_TypeTraits \ + { \ + typedef type value_type; \ + typedef int_type_ int_type; \ + typedef abs_type_ abs_type; \ + typedef uint_type_ uint_type; \ + typedef w_type_ w_type; \ + typedef q_type_ q_type; \ + typedef sum_type_ sum_type; \ + enum { nlanes128 = nlanes128_ }; \ + \ + static inline int_type reinterpret_int(type x) \ + { \ + union { type l; int_type i; } v; \ + v.l = x; \ + return v.i; \ + } \ + \ + static inline type reinterpret_from_int(int_type x) \ + { \ + union { type l; int_type i; } v; \ + v.i = x; \ + return v.l; \ + } \ + } + +CV_INTRIN_DEF_TYPE_TRAITS(uchar, schar, uchar, uchar, ushort, unsigned, unsigned, 16); +CV_INTRIN_DEF_TYPE_TRAITS(schar, schar, uchar, uchar, short, int, int, 16); +CV_INTRIN_DEF_TYPE_TRAITS(ushort, short, ushort, ushort, unsigned, uint64, unsigned, 8); +CV_INTRIN_DEF_TYPE_TRAITS(short, short, ushort, ushort, int, int64, int, 8); +CV_INTRIN_DEF_TYPE_TRAITS(unsigned, int, unsigned, unsigned, uint64, void, unsigned, 4); +CV_INTRIN_DEF_TYPE_TRAITS(int, int, unsigned, unsigned, int64, void, int, 4); +CV_INTRIN_DEF_TYPE_TRAITS(float, int, unsigned, float, double, void, float, 4); +CV_INTRIN_DEF_TYPE_TRAITS(uint64, int64, uint64, uint64, void, void, uint64, 2); +CV_INTRIN_DEF_TYPE_TRAITS(int64, int64, uint64, uint64, void, void, int64, 2); +CV_INTRIN_DEF_TYPE_TRAITS(double, int64, uint64, double, void, void, double, 2); + +#ifndef CV_DOXYGEN + +#ifdef CV_CPU_DISPATCH_MODE + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) { + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } +#else + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE hal_baseline + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace hal_baseline { + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } +#endif + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE; +#endif +} + +#ifdef CV_DOXYGEN +# undef CV_AVX2 +# undef CV_SSE2 +# undef CV_NEON +# undef CV_VSX +# undef CV_FP16 +#endif + +#if CV_SSE2 || CV_NEON || CV_VSX +#define CV__SIMD_FORWARD 128 +#include "opencv2/core/hal/intrin_forward.hpp" +#endif + +#if CV_SSE2 + +#include "opencv2/core/hal/intrin_sse_em.hpp" +#include "opencv2/core/hal/intrin_sse.hpp" + +#elif CV_NEON + +#include "opencv2/core/hal/intrin_neon.hpp" + +#elif CV_VSX + +#include "opencv2/core/hal/intrin_vsx.hpp" + +#else + +#define CV_SIMD128_CPP 1 +#include "opencv2/core/hal/intrin_cpp.hpp" + +#endif + +// AVX2 can be used together with SSE2, so +// we define those two sets of intrinsics at once. +// Most of the intrinsics do not conflict (the proper overloaded variant is +// resolved by the argument types, e.g. v_float32x4 ~ SSE2, v_float32x8 ~ AVX2), +// but some of AVX2 intrinsics get v256_ prefix instead of v_, e.g. v256_load() vs v_load(). +// Correspondingly, the wide intrinsics (which are mapped to the "widest" +// available instruction set) will get vx_ prefix +// (and will be mapped to v256_ counterparts) (e.g. vx_load() => v256_load()) +#if CV_AVX2 + +#define CV__SIMD_FORWARD 256 +#include "opencv2/core/hal/intrin_forward.hpp" +#include "opencv2/core/hal/intrin_avx.hpp" + +#endif + +//! @cond IGNORED + +namespace cv { + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +#endif + +#ifndef CV_SIMD128 +#define CV_SIMD128 0 +#endif + +#ifndef CV_SIMD128_64F +#define CV_SIMD128_64F 0 +#endif + +#ifndef CV_SIMD256 +#define CV_SIMD256 0 +#endif + +#ifndef CV_SIMD256_64F +#define CV_SIMD256_64F 0 +#endif + +#ifndef CV_SIMD512 +#define CV_SIMD512 0 +#endif + +#ifndef CV_SIMD512_64F +#define CV_SIMD512_64F 0 +#endif + +#ifndef CV_SIMD128_FP16 +#define CV_SIMD128_FP16 0 +#endif + +#ifndef CV_SIMD256_FP16 +#define CV_SIMD256_FP16 0 +#endif + +#ifndef CV_SIMD512_FP16 +#define CV_SIMD512_FP16 0 +#endif + +//================================================================================================== + +#define CV_INTRIN_DEFINE_WIDE_INTRIN(typ, vtyp, short_typ, prefix, loadsfx) \ + inline vtyp vx_setall_##short_typ(typ v) { return prefix##_setall_##short_typ(v); } \ + inline vtyp vx_setzero_##short_typ() { return prefix##_setzero_##short_typ(); } \ + inline vtyp vx_##loadsfx(const typ* ptr) { return prefix##_##loadsfx(ptr); } \ + inline vtyp vx_##loadsfx##_aligned(const typ* ptr) { return prefix##_##loadsfx##_aligned(ptr); } \ + inline vtyp vx_##loadsfx##_low(const typ* ptr) { return prefix##_##loadsfx##_low(ptr); } \ + inline vtyp vx_##loadsfx##_halves(const typ* ptr0, const typ* ptr1) { return prefix##_##loadsfx##_halves(ptr0, ptr1); } \ + inline void vx_store(typ* ptr, const vtyp& v) { return v_store(ptr, v); } \ + inline void vx_store_aligned(typ* ptr, const vtyp& v) { return v_store_aligned(ptr, v); } + +#define CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(typ, wtyp, prefix) \ + inline wtyp vx_load_expand(const typ* ptr) { return prefix##_load_expand(ptr); } + +#define CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND_Q(typ, qtyp, prefix) \ + inline qtyp vx_load_expand_q(const typ* ptr) { return prefix##_load_expand_q(ptr); } + +#define CV_INTRIN_DEFINE_WIDE_INTRIN_WITH_EXPAND(typ, vtyp, short_typ, wtyp, qtyp, prefix, loadsfx) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(typ, vtyp, short_typ, prefix, loadsfx) \ + CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(typ, wtyp, prefix) \ + CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND_Q(typ, qtyp, prefix) + +#define CV_INTRIN_DEFINE_WIDE_INTRIN_ALL_TYPES(prefix) \ + CV_INTRIN_DEFINE_WIDE_INTRIN_WITH_EXPAND(uchar, v_uint8, u8, v_uint16, v_uint32, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_INTRIN_WITH_EXPAND(schar, v_int8, s8, v_int16, v_int32, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(ushort, v_uint16, u16, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(ushort, v_uint32, prefix) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(short, v_int16, s16, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(short, v_int32, prefix) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(int, v_int32, s32, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(int, v_int64, prefix) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(unsigned, v_uint32, u32, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(unsigned, v_uint64, prefix) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(float, v_float32, f32, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(int64, v_int64, s64, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_INTRIN(uint64, v_uint64, u64, prefix, load) \ + CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(float16_t, v_float32, prefix) + +template struct V_RegTraits +{ +}; + +#define CV_DEF_REG_TRAITS(prefix, _reg, lane_type, suffix, _u_reg, _w_reg, _q_reg, _int_reg, _round_reg) \ + template<> struct V_RegTraits<_reg> \ + { \ + typedef _reg reg; \ + typedef _u_reg u_reg; \ + typedef _w_reg w_reg; \ + typedef _q_reg q_reg; \ + typedef _int_reg int_reg; \ + typedef _round_reg round_reg; \ + } + +#if CV_SIMD128 || CV_SIMD128_CPP + CV_DEF_REG_TRAITS(v, v_uint8x16, uchar, u8, v_uint8x16, v_uint16x8, v_uint32x4, v_int8x16, void); + CV_DEF_REG_TRAITS(v, v_int8x16, schar, s8, v_uint8x16, v_int16x8, v_int32x4, v_int8x16, void); + CV_DEF_REG_TRAITS(v, v_uint16x8, ushort, u16, v_uint16x8, v_uint32x4, v_uint64x2, v_int16x8, void); + CV_DEF_REG_TRAITS(v, v_int16x8, short, s16, v_uint16x8, v_int32x4, v_int64x2, v_int16x8, void); + CV_DEF_REG_TRAITS(v, v_uint32x4, unsigned, u32, v_uint32x4, v_uint64x2, void, v_int32x4, void); + CV_DEF_REG_TRAITS(v, v_int32x4, int, s32, v_uint32x4, v_int64x2, void, v_int32x4, void); +#if CV_SIMD128_64F + CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, v_float64x2, void, v_int32x4, v_int32x4); +#else + CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, void, void, v_int32x4, v_int32x4); +#endif + CV_DEF_REG_TRAITS(v, v_uint64x2, uint64, u64, v_uint64x2, void, void, v_int64x2, void); + CV_DEF_REG_TRAITS(v, v_int64x2, int64, s64, v_uint64x2, void, void, v_int64x2, void); +#if CV_SIMD128_64F + CV_DEF_REG_TRAITS(v, v_float64x2, double, f64, v_float64x2, void, void, v_int64x2, v_int32x4); +#endif +#endif + +#if CV_SIMD256 + CV_DEF_REG_TRAITS(v256, v_uint8x32, uchar, u8, v_uint8x32, v_uint16x16, v_uint32x8, v_int8x32, void); + CV_DEF_REG_TRAITS(v256, v_int8x32, schar, s8, v_uint8x32, v_int16x16, v_int32x8, v_int8x32, void); + CV_DEF_REG_TRAITS(v256, v_uint16x16, ushort, u16, v_uint16x16, v_uint32x8, v_uint64x4, v_int16x16, void); + CV_DEF_REG_TRAITS(v256, v_int16x16, short, s16, v_uint16x16, v_int32x8, v_int64x4, v_int16x16, void); + CV_DEF_REG_TRAITS(v256, v_uint32x8, unsigned, u32, v_uint32x8, v_uint64x4, void, v_int32x8, void); + CV_DEF_REG_TRAITS(v256, v_int32x8, int, s32, v_uint32x8, v_int64x4, void, v_int32x8, void); + CV_DEF_REG_TRAITS(v256, v_float32x8, float, f32, v_float32x8, v_float64x4, void, v_int32x8, v_int32x8); + CV_DEF_REG_TRAITS(v256, v_uint64x4, uint64, u64, v_uint64x4, void, void, v_int64x4, void); + CV_DEF_REG_TRAITS(v256, v_int64x4, int64, s64, v_uint64x4, void, void, v_int64x4, void); + CV_DEF_REG_TRAITS(v256, v_float64x4, double, f64, v_float64x4, void, void, v_int64x4, v_int32x8); +#endif + +#if CV_SIMD512 && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 512) +#define CV__SIMD_NAMESPACE simd512 +namespace CV__SIMD_NAMESPACE { + #define CV_SIMD 1 + #define CV_SIMD_64F CV_SIMD512_64F + #define CV_SIMD_WIDTH 64 + // TODO typedef v_uint8 / v_int32 / etc types here +} // namespace +using namespace CV__SIMD_NAMESPACE; +#elif CV_SIMD256 && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 256) +#define CV__SIMD_NAMESPACE simd256 +namespace CV__SIMD_NAMESPACE { + #define CV_SIMD 1 + #define CV_SIMD_64F CV_SIMD256_64F + #define CV_SIMD_FP16 CV_SIMD256_FP16 + #define CV_SIMD_WIDTH 32 + typedef v_uint8x32 v_uint8; + typedef v_int8x32 v_int8; + typedef v_uint16x16 v_uint16; + typedef v_int16x16 v_int16; + typedef v_uint32x8 v_uint32; + typedef v_int32x8 v_int32; + typedef v_uint64x4 v_uint64; + typedef v_int64x4 v_int64; + typedef v_float32x8 v_float32; + #if CV_SIMD256_64F + typedef v_float64x4 v_float64; + #endif + CV_INTRIN_DEFINE_WIDE_INTRIN_ALL_TYPES(v256) + CV_INTRIN_DEFINE_WIDE_INTRIN(double, v_float64, f64, v256, load) + inline void vx_cleanup() { v256_cleanup(); } +} // namespace +using namespace CV__SIMD_NAMESPACE; +#elif (CV_SIMD128 || CV_SIMD128_CPP) && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 128) +#define CV__SIMD_NAMESPACE simd128 +namespace CV__SIMD_NAMESPACE { + #define CV_SIMD CV_SIMD128 + #define CV_SIMD_64F CV_SIMD128_64F + #define CV_SIMD_WIDTH 16 + typedef v_uint8x16 v_uint8; + typedef v_int8x16 v_int8; + typedef v_uint16x8 v_uint16; + typedef v_int16x8 v_int16; + typedef v_uint32x4 v_uint32; + typedef v_int32x4 v_int32; + typedef v_uint64x2 v_uint64; + typedef v_int64x2 v_int64; + typedef v_float32x4 v_float32; + #if CV_SIMD128_64F + typedef v_float64x2 v_float64; + #endif + CV_INTRIN_DEFINE_WIDE_INTRIN_ALL_TYPES(v) + #if CV_SIMD128_64F + CV_INTRIN_DEFINE_WIDE_INTRIN(double, v_float64, f64, v, load) + #endif + inline void vx_cleanup() { v_cleanup(); } +} // namespace +using namespace CV__SIMD_NAMESPACE; +#endif + +inline unsigned int trailingZeros32(unsigned int value) { +#if defined(_MSC_VER) +#if (_MSC_VER < 1700) || defined(_M_ARM) + unsigned long index = 0; + _BitScanForward(&index, value); + return (unsigned int)index; +#elif defined(__clang__) + // clang-cl doesn't export _tzcnt_u32 for non BMI systems + return value ? __builtin_ctz(value) : 32; +#else + return _tzcnt_u32(value); +#endif +#elif defined(__GNUC__) || defined(__GNUG__) + return __builtin_ctz(value); +#elif defined(__ICC) || defined(__INTEL_COMPILER) + return _bit_scan_forward(value); +#elif defined(__clang__) + return llvm.cttz.i32(value, true); +#else + static const int MultiplyDeBruijnBitPosition[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; + return MultiplyDeBruijnBitPosition[((uint32_t)((value & -value) * 0x077CB531U)) >> 27]; +#endif +} + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +#endif + +#ifndef CV_SIMD_64F +#define CV_SIMD_64F 0 +#endif + +#ifndef CV_SIMD_FP16 +#define CV_SIMD_FP16 0 //!< Defined to 1 on native support of operations with float16x8_t / float16x16_t (SIMD256) types +#endif + + +#ifndef CV_SIMD +#define CV_SIMD 0 +#endif + +} // cv:: + +//! @endcond + +#endif diff --git a/include/opencv2/core/hal/intrin_avx.hpp b/include/opencv2/core/hal/intrin_avx.hpp new file mode 100644 index 0000000..c3797d6 --- /dev/null +++ b/include/opencv2/core/hal/intrin_avx.hpp @@ -0,0 +1,2628 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_INTRIN_AVX_HPP +#define OPENCV_HAL_INTRIN_AVX_HPP + +#define CV_SIMD256 1 +#define CV_SIMD256_64F 1 +#define CV_SIMD256_FP16 0 // no native operations with FP16 type. Only load/store from float32x8 are available (if CV_FP16 == 1) + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +///////// Utils //////////// + +inline __m256i _v256_combine(const __m128i& lo, const __m128i& hi) +{ return _mm256_inserti128_si256(_mm256_castsi128_si256(lo), hi, 1); } + +inline __m256 _v256_combine(const __m128& lo, const __m128& hi) +{ return _mm256_insertf128_ps(_mm256_castps128_ps256(lo), hi, 1); } + +inline __m256d _v256_combine(const __m128d& lo, const __m128d& hi) +{ return _mm256_insertf128_pd(_mm256_castpd128_pd256(lo), hi, 1); } + +inline int _v_cvtsi256_si32(const __m256i& a) +{ return _mm_cvtsi128_si32(_mm256_castsi256_si128(a)); } + +inline __m256i _v256_shuffle_odd_64(const __m256i& v) +{ return _mm256_permute4x64_epi64(v, _MM_SHUFFLE(3, 1, 2, 0)); } + +inline __m256d _v256_shuffle_odd_64(const __m256d& v) +{ return _mm256_permute4x64_pd(v, _MM_SHUFFLE(3, 1, 2, 0)); } + +template +inline __m256i _v256_permute2x128(const __m256i& a, const __m256i& b) +{ return _mm256_permute2x128_si256(a, b, imm); } + +template +inline __m256 _v256_permute2x128(const __m256& a, const __m256& b) +{ return _mm256_permute2f128_ps(a, b, imm); } + +template +inline __m256d _v256_permute2x128(const __m256d& a, const __m256d& b) +{ return _mm256_permute2f128_pd(a, b, imm); } + +template +inline _Tpvec v256_permute2x128(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(_v256_permute2x128(a.val, b.val)); } + +template +inline __m256i _v256_permute4x64(const __m256i& a) +{ return _mm256_permute4x64_epi64(a, imm); } + +template +inline __m256d _v256_permute4x64(const __m256d& a) +{ return _mm256_permute4x64_pd(a, imm); } + +template +inline _Tpvec v256_permute4x64(const _Tpvec& a) +{ return _Tpvec(_v256_permute4x64(a.val)); } + +inline __m128i _v256_extract_high(const __m256i& v) +{ return _mm256_extracti128_si256(v, 1); } + +inline __m128 _v256_extract_high(const __m256& v) +{ return _mm256_extractf128_ps(v, 1); } + +inline __m128d _v256_extract_high(const __m256d& v) +{ return _mm256_extractf128_pd(v, 1); } + +inline __m128i _v256_extract_low(const __m256i& v) +{ return _mm256_castsi256_si128(v); } + +inline __m128 _v256_extract_low(const __m256& v) +{ return _mm256_castps256_ps128(v); } + +inline __m128d _v256_extract_low(const __m256d& v) +{ return _mm256_castpd256_pd128(v); } + +inline __m256i _v256_packs_epu32(const __m256i& a, const __m256i& b) +{ + const __m256i m = _mm256_set1_epi32(65535); + __m256i am = _mm256_min_epu32(a, m); + __m256i bm = _mm256_min_epu32(b, m); + return _mm256_packus_epi32(am, bm); +} + +///////// Types //////////// + +struct v_uint8x32 +{ + typedef uchar lane_type; + enum { nlanes = 32 }; + __m256i val; + + explicit v_uint8x32(__m256i v) : val(v) {} + v_uint8x32(uchar v0, uchar v1, uchar v2, uchar v3, + uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, + uchar v12, uchar v13, uchar v14, uchar v15, + uchar v16, uchar v17, uchar v18, uchar v19, + uchar v20, uchar v21, uchar v22, uchar v23, + uchar v24, uchar v25, uchar v26, uchar v27, + uchar v28, uchar v29, uchar v30, uchar v31) + { + val = _mm256_setr_epi8((char)v0, (char)v1, (char)v2, (char)v3, + (char)v4, (char)v5, (char)v6 , (char)v7, (char)v8, (char)v9, + (char)v10, (char)v11, (char)v12, (char)v13, (char)v14, (char)v15, + (char)v16, (char)v17, (char)v18, (char)v19, (char)v20, (char)v21, + (char)v22, (char)v23, (char)v24, (char)v25, (char)v26, (char)v27, + (char)v28, (char)v29, (char)v30, (char)v31); + } + v_uint8x32() : val(_mm256_setzero_si256()) {} + uchar get0() const { return (uchar)_v_cvtsi256_si32(val); } +}; + +struct v_int8x32 +{ + typedef schar lane_type; + enum { nlanes = 32 }; + __m256i val; + + explicit v_int8x32(__m256i v) : val(v) {} + v_int8x32(schar v0, schar v1, schar v2, schar v3, + schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, + schar v12, schar v13, schar v14, schar v15, + schar v16, schar v17, schar v18, schar v19, + schar v20, schar v21, schar v22, schar v23, + schar v24, schar v25, schar v26, schar v27, + schar v28, schar v29, schar v30, schar v31) + { + val = _mm256_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, + v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); + } + v_int8x32() : val(_mm256_setzero_si256()) {} + schar get0() const { return (schar)_v_cvtsi256_si32(val); } +}; + +struct v_uint16x16 +{ + typedef ushort lane_type; + enum { nlanes = 16 }; + __m256i val; + + explicit v_uint16x16(__m256i v) : val(v) {} + v_uint16x16(ushort v0, ushort v1, ushort v2, ushort v3, + ushort v4, ushort v5, ushort v6, ushort v7, + ushort v8, ushort v9, ushort v10, ushort v11, + ushort v12, ushort v13, ushort v14, ushort v15) + { + val = _mm256_setr_epi16((short)v0, (short)v1, (short)v2, (short)v3, + (short)v4, (short)v5, (short)v6, (short)v7, (short)v8, (short)v9, + (short)v10, (short)v11, (short)v12, (short)v13, (short)v14, (short)v15); + } + v_uint16x16() : val(_mm256_setzero_si256()) {} + ushort get0() const { return (ushort)_v_cvtsi256_si32(val); } +}; + +struct v_int16x16 +{ + typedef short lane_type; + enum { nlanes = 16 }; + __m256i val; + + explicit v_int16x16(__m256i v) : val(v) {} + v_int16x16(short v0, short v1, short v2, short v3, + short v4, short v5, short v6, short v7, + short v8, short v9, short v10, short v11, + short v12, short v13, short v14, short v15) + { + val = _mm256_setr_epi16(v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15); + } + v_int16x16() : val(_mm256_setzero_si256()) {} + short get0() const { return (short)_v_cvtsi256_si32(val); } +}; + +struct v_uint32x8 +{ + typedef unsigned lane_type; + enum { nlanes = 8 }; + __m256i val; + + explicit v_uint32x8(__m256i v) : val(v) {} + v_uint32x8(unsigned v0, unsigned v1, unsigned v2, unsigned v3, + unsigned v4, unsigned v5, unsigned v6, unsigned v7) + { + val = _mm256_setr_epi32((unsigned)v0, (unsigned)v1, (unsigned)v2, + (unsigned)v3, (unsigned)v4, (unsigned)v5, (unsigned)v6, (unsigned)v7); + } + v_uint32x8() : val(_mm256_setzero_si256()) {} + unsigned get0() const { return (unsigned)_v_cvtsi256_si32(val); } +}; + +struct v_int32x8 +{ + typedef int lane_type; + enum { nlanes = 8 }; + __m256i val; + + explicit v_int32x8(__m256i v) : val(v) {} + v_int32x8(int v0, int v1, int v2, int v3, + int v4, int v5, int v6, int v7) + { + val = _mm256_setr_epi32(v0, v1, v2, v3, v4, v5, v6, v7); + } + v_int32x8() : val(_mm256_setzero_si256()) {} + int get0() const { return _v_cvtsi256_si32(val); } +}; + +struct v_float32x8 +{ + typedef float lane_type; + enum { nlanes = 8 }; + __m256 val; + + explicit v_float32x8(__m256 v) : val(v) {} + v_float32x8(float v0, float v1, float v2, float v3, + float v4, float v5, float v6, float v7) + { + val = _mm256_setr_ps(v0, v1, v2, v3, v4, v5, v6, v7); + } + v_float32x8() : val(_mm256_setzero_ps()) {} + float get0() const { return _mm_cvtss_f32(_mm256_castps256_ps128(val)); } +}; + +struct v_uint64x4 +{ + typedef uint64 lane_type; + enum { nlanes = 4 }; + __m256i val; + + explicit v_uint64x4(__m256i v) : val(v) {} + v_uint64x4(uint64 v0, uint64 v1, uint64 v2, uint64 v3) + { val = _mm256_setr_epi64x((int64)v0, (int64)v1, (int64)v2, (int64)v3); } + v_uint64x4() : val(_mm256_setzero_si256()) {} + uint64 get0() const + { + #if defined __x86_64__ || defined _M_X64 + return (uint64)_mm_cvtsi128_si64(_mm256_castsi256_si128(val)); + #else + int a = _mm_cvtsi128_si32(_mm256_castsi256_si128(val)); + int b = _mm_cvtsi128_si32(_mm256_castsi256_si128(_mm256_srli_epi64(val, 32))); + return (unsigned)a | ((uint64)(unsigned)b << 32); + #endif + } +}; + +struct v_int64x4 +{ + typedef int64 lane_type; + enum { nlanes = 4 }; + __m256i val; + + explicit v_int64x4(__m256i v) : val(v) {} + v_int64x4(int64 v0, int64 v1, int64 v2, int64 v3) + { val = _mm256_setr_epi64x(v0, v1, v2, v3); } + v_int64x4() : val(_mm256_setzero_si256()) {} + + int64 get0() const + { + #if defined __x86_64__ || defined _M_X64 + return (int64)_mm_cvtsi128_si64(_mm256_castsi256_si128(val)); + #else + int a = _mm_cvtsi128_si32(_mm256_castsi256_si128(val)); + int b = _mm_cvtsi128_si32(_mm256_castsi256_si128(_mm256_srli_epi64(val, 32))); + return (int64)((unsigned)a | ((uint64)(unsigned)b << 32)); + #endif + } +}; + +struct v_float64x4 +{ + typedef double lane_type; + enum { nlanes = 4 }; + __m256d val; + + explicit v_float64x4(__m256d v) : val(v) {} + v_float64x4(double v0, double v1, double v2, double v3) + { val = _mm256_setr_pd(v0, v1, v2, v3); } + v_float64x4() : val(_mm256_setzero_pd()) {} + double get0() const { return _mm_cvtsd_f64(_mm256_castpd256_pd128(val)); } +}; + +//////////////// Load and store operations /////////////// + +#define OPENCV_HAL_IMPL_AVX_LOADSTORE(_Tpvec, _Tp) \ + inline _Tpvec v256_load(const _Tp* ptr) \ + { return _Tpvec(_mm256_loadu_si256((const __m256i*)ptr)); } \ + inline _Tpvec v256_load_aligned(const _Tp* ptr) \ + { return _Tpvec(_mm256_load_si256((const __m256i*)ptr)); } \ + inline _Tpvec v256_load_low(const _Tp* ptr) \ + { \ + __m128i v128 = _mm_loadu_si128((const __m128i*)ptr); \ + return _Tpvec(_mm256_castsi128_si256(v128)); \ + } \ + inline _Tpvec v256_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ + { \ + __m128i vlo = _mm_loadu_si128((const __m128i*)ptr0); \ + __m128i vhi = _mm_loadu_si128((const __m128i*)ptr1); \ + return _Tpvec(_v256_combine(vlo, vhi)); \ + } \ + inline void v_store(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_si256((__m256i*)ptr, a.val); } \ + inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ + { _mm256_store_si256((__m256i*)ptr, a.val); } \ + inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ + { _mm256_stream_si256((__m256i*)ptr, a.val); } \ + inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ + { \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm256_storeu_si256((__m256i*)ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm256_stream_si256((__m256i*)ptr, a.val); \ + else \ + _mm256_store_si256((__m256i*)ptr, a.val); \ + } \ + inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_si128((__m128i*)ptr, _v256_extract_low(a.val)); } \ + inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_si128((__m128i*)ptr, _v256_extract_high(a.val)); } + +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint8x32, uchar) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int8x32, schar) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint16x16, ushort) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int16x16, short) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint32x8, unsigned) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int32x8, int) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint64x4, uint64) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int64x4, int64) + +#define OPENCV_HAL_IMPL_AVX_LOADSTORE_FLT(_Tpvec, _Tp, suffix, halfreg) \ + inline _Tpvec v256_load(const _Tp* ptr) \ + { return _Tpvec(_mm256_loadu_##suffix(ptr)); } \ + inline _Tpvec v256_load_aligned(const _Tp* ptr) \ + { return _Tpvec(_mm256_load_##suffix(ptr)); } \ + inline _Tpvec v256_load_low(const _Tp* ptr) \ + { \ + return _Tpvec(_mm256_cast##suffix##128_##suffix##256 \ + (_mm_loadu_##suffix(ptr))); \ + } \ + inline _Tpvec v256_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ + { \ + halfreg vlo = _mm_loadu_##suffix(ptr0); \ + halfreg vhi = _mm_loadu_##suffix(ptr1); \ + return _Tpvec(_v256_combine(vlo, vhi)); \ + } \ + inline void v_store(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_##suffix(ptr, a.val); } \ + inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ + { _mm256_store_##suffix(ptr, a.val); } \ + inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ + { _mm256_stream_##suffix(ptr, a.val); } \ + inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ + { \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm256_storeu_##suffix(ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm256_stream_##suffix(ptr, a.val); \ + else \ + _mm256_store_##suffix(ptr, a.val); \ + } \ + inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_##suffix(ptr, _v256_extract_low(a.val)); } \ + inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_##suffix(ptr, _v256_extract_high(a.val)); } + +OPENCV_HAL_IMPL_AVX_LOADSTORE_FLT(v_float32x8, float, ps, __m128) +OPENCV_HAL_IMPL_AVX_LOADSTORE_FLT(v_float64x4, double, pd, __m128d) + +#define OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, _Tpvecf, suffix, cast) \ + inline _Tpvec v_reinterpret_as_##suffix(const _Tpvecf& a) \ + { return _Tpvec(cast(a.val)); } + +#define OPENCV_HAL_IMPL_AVX_INIT(_Tpvec, _Tp, suffix, ssuffix, ctype_s) \ + inline _Tpvec v256_setzero_##suffix() \ + { return _Tpvec(_mm256_setzero_si256()); } \ + inline _Tpvec v256_setall_##suffix(_Tp v) \ + { return _Tpvec(_mm256_set1_##ssuffix((ctype_s)v)); } \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint8x32, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int8x32, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint16x16, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int16x16, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint32x8, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int32x8, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint64x4, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int64x4, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_float32x8, suffix, _mm256_castps_si256) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_float64x4, suffix, _mm256_castpd_si256) + +OPENCV_HAL_IMPL_AVX_INIT(v_uint8x32, uchar, u8, epi8, char) +OPENCV_HAL_IMPL_AVX_INIT(v_int8x32, schar, s8, epi8, char) +OPENCV_HAL_IMPL_AVX_INIT(v_uint16x16, ushort, u16, epi16, short) +OPENCV_HAL_IMPL_AVX_INIT(v_int16x16, short, s16, epi16, short) +OPENCV_HAL_IMPL_AVX_INIT(v_uint32x8, unsigned, u32, epi32, int) +OPENCV_HAL_IMPL_AVX_INIT(v_int32x8, int, s32, epi32, int) +OPENCV_HAL_IMPL_AVX_INIT(v_uint64x4, uint64, u64, epi64x, int64) +OPENCV_HAL_IMPL_AVX_INIT(v_int64x4, int64, s64, epi64x, int64) + +#define OPENCV_HAL_IMPL_AVX_INIT_FLT(_Tpvec, _Tp, suffix, zsuffix, cast) \ + inline _Tpvec v256_setzero_##suffix() \ + { return _Tpvec(_mm256_setzero_##zsuffix()); } \ + inline _Tpvec v256_setall_##suffix(_Tp v) \ + { return _Tpvec(_mm256_set1_##zsuffix(v)); } \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint8x32, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int8x32, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint16x16, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int16x16, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint32x8, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int32x8, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint64x4, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int64x4, suffix, cast) + +OPENCV_HAL_IMPL_AVX_INIT_FLT(v_float32x8, float, f32, ps, _mm256_castsi256_ps) +OPENCV_HAL_IMPL_AVX_INIT_FLT(v_float64x4, double, f64, pd, _mm256_castsi256_pd) + +inline v_float32x8 v_reinterpret_as_f32(const v_float32x8& a) +{ return a; } +inline v_float32x8 v_reinterpret_as_f32(const v_float64x4& a) +{ return v_float32x8(_mm256_castpd_ps(a.val)); } + +inline v_float64x4 v_reinterpret_as_f64(const v_float64x4& a) +{ return a; } +inline v_float64x4 v_reinterpret_as_f64(const v_float32x8& a) +{ return v_float64x4(_mm256_castps_pd(a.val)); } + +#if CV_FP16 +inline v_float32x8 v256_load_fp16_f32(const short* ptr) +{ + return v_float32x8(_mm256_cvtph_ps(_mm_loadu_si128((const __m128i*)ptr))); +} + +inline void v_store_fp16(short* ptr, const v_float32x8& a) +{ + __m128i fp16_value = _mm256_cvtps_ph(a.val, 0); + _mm_store_si128((__m128i*)ptr, fp16_value); +} +#endif + +/* Recombine */ +/*#define OPENCV_HAL_IMPL_AVX_COMBINE(_Tpvec, perm) \ + inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(perm(a.val, b.val, 0x20)); } \ + inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(perm(a.val, b.val, 0x31)); } \ + inline void v_recombine(const _Tpvec& a, const _Tpvec& b, \ + _Tpvec& c, _Tpvec& d) \ + { c = v_combine_low(a, b); d = v_combine_high(a, b); } + +#define OPENCV_HAL_IMPL_AVX_UNPACKS(_Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_COMBINE(_Tpvec, _mm256_permute2x128_si256) \ + inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, \ + _Tpvec& b0, _Tpvec& b1) \ + { \ + __m256i v0 = _v256_shuffle_odd_64(a0.val); \ + __m256i v1 = _v256_shuffle_odd_64(a1.val); \ + b0.val = _mm256_unpacklo_##suffix(v0, v1); \ + b1.val = _mm256_unpackhi_##suffix(v0, v1); \ + } + +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint64x4, epi64) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int64x4, epi64) +OPENCV_HAL_IMPL_AVX_COMBINE(v_float32x8, _mm256_permute2f128_ps) +OPENCV_HAL_IMPL_AVX_COMBINE(v_float64x4, _mm256_permute2f128_pd) + +inline void v_zip(const v_float32x8& a0, const v_float32x8& a1, v_float32x8& b0, v_float32x8& b1) +{ + __m256 v0 = _mm256_unpacklo_ps(a0.val, a1.val); + __m256 v1 = _mm256_unpackhi_ps(a0.val, a1.val); + v_recombine(v_float32x8(v0), v_float32x8(v1), b0, b1); +} + +inline void v_zip(const v_float64x4& a0, const v_float64x4& a1, v_float64x4& b0, v_float64x4& b1) +{ + __m256d v0 = _v_shuffle_odd_64(a0.val); + __m256d v1 = _v_shuffle_odd_64(a1.val); + b0.val = _mm256_unpacklo_pd(v0, v1); + b1.val = _mm256_unpackhi_pd(v0, v1); +}*/ + +//////////////// Variant Value reordering /////////////// + +// unpacks +#define OPENCV_HAL_IMPL_AVX_UNPACK(_Tpvec, suffix) \ + inline _Tpvec v256_unpacklo(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_unpacklo_##suffix(a.val, b.val)); } \ + inline _Tpvec v256_unpackhi(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_unpackhi_##suffix(a.val, b.val)); } + +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint64x4, epi64) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int64x4, epi64) +OPENCV_HAL_IMPL_AVX_UNPACK(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_UNPACK(v_float64x4, pd) + +// blend +#define OPENCV_HAL_IMPL_AVX_BLEND(_Tpvec, suffix) \ + template \ + inline _Tpvec v256_blend(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_blend_##suffix(a.val, b.val, m)); } + +OPENCV_HAL_IMPL_AVX_BLEND(v_uint16x16, epi16) +OPENCV_HAL_IMPL_AVX_BLEND(v_int16x16, epi16) +OPENCV_HAL_IMPL_AVX_BLEND(v_uint32x8, epi32) +OPENCV_HAL_IMPL_AVX_BLEND(v_int32x8, epi32) +OPENCV_HAL_IMPL_AVX_BLEND(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_BLEND(v_float64x4, pd) + +template +inline v_uint64x4 v256_blend(const v_uint64x4& a, const v_uint64x4& b) +{ + enum {M0 = m}; + enum {M1 = (M0 | (M0 << 2)) & 0x33}; + enum {M2 = (M1 | (M1 << 1)) & 0x55}; + enum {MM = M2 | (M2 << 1)}; + return v_uint64x4(_mm256_blend_epi32(a.val, b.val, MM)); +} +template +inline v_int64x4 v256_blend(const v_int64x4& a, const v_int64x4& b) +{ return v_int64x4(v256_blend(v_uint64x4(a.val), v_uint64x4(b.val)).val); } + +// shuffle +// todo: emluate 64bit +#define OPENCV_HAL_IMPL_AVX_SHUFFLE(_Tpvec, intrin) \ + template \ + inline _Tpvec v256_shuffle(const _Tpvec& a) \ + { return _Tpvec(_mm256_##intrin(a.val, m)); } + +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_uint32x8, shuffle_epi32) +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_int32x8, shuffle_epi32) +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_float32x8, permute_ps) +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_float64x4, permute_pd) + +template +inline void v256_zip(const _Tpvec& a, const _Tpvec& b, _Tpvec& ab0, _Tpvec& ab1) +{ + ab0 = v256_unpacklo(a, b); + ab1 = v256_unpackhi(a, b); +} + +template +inline _Tpvec v256_combine_diagonal(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(_mm256_blend_epi32(a.val, b.val, 0xf0)); } + +inline v_float32x8 v256_combine_diagonal(const v_float32x8& a, const v_float32x8& b) +{ return v256_blend<0xf0>(a, b); } + +inline v_float64x4 v256_combine_diagonal(const v_float64x4& a, const v_float64x4& b) +{ return v256_blend<0xc>(a, b); } + +template +inline _Tpvec v256_alignr_128(const _Tpvec& a, const _Tpvec& b) +{ return v256_permute2x128<0x21>(a, b); } + +template +inline _Tpvec v256_alignr_64(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(_mm256_alignr_epi8(a.val, b.val, 8)); } +inline v_float64x4 v256_alignr_64(const v_float64x4& a, const v_float64x4& b) +{ return v_float64x4(_mm256_shuffle_pd(b.val, a.val, _MM_SHUFFLE(0, 0, 1, 1))); } +// todo: emulate float32 + +template +inline _Tpvec v256_swap_halves(const _Tpvec& a) +{ return v256_permute2x128<1>(a, a); } + +template +inline _Tpvec v256_reverse_64(const _Tpvec& a) +{ return v256_permute4x64<_MM_SHUFFLE(0, 1, 2, 3)>(a); } + +// ZIP +#define OPENCV_HAL_IMPL_AVX_ZIP(_Tpvec) \ + inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ + { return v256_permute2x128<0x20>(a, b); } \ + inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ + { return v256_permute2x128<0x31>(a, b); } \ + inline void v_recombine(const _Tpvec& a, const _Tpvec& b, \ + _Tpvec& c, _Tpvec& d) \ + { \ + _Tpvec a1b0 = v256_alignr_128(a, b); \ + c = v256_combine_diagonal(a, a1b0); \ + d = v256_combine_diagonal(a1b0, b); \ + } \ + inline void v_zip(const _Tpvec& a, const _Tpvec& b, \ + _Tpvec& ab0, _Tpvec& ab1) \ + { \ + _Tpvec ab0ab2, ab1ab3; \ + v256_zip(a, b, ab0ab2, ab1ab3); \ + v_recombine(ab0ab2, ab1ab3, ab0, ab1); \ + } + +OPENCV_HAL_IMPL_AVX_ZIP(v_uint8x32) +OPENCV_HAL_IMPL_AVX_ZIP(v_int8x32) +OPENCV_HAL_IMPL_AVX_ZIP(v_uint16x16) +OPENCV_HAL_IMPL_AVX_ZIP(v_int16x16) +OPENCV_HAL_IMPL_AVX_ZIP(v_uint32x8) +OPENCV_HAL_IMPL_AVX_ZIP(v_int32x8) +OPENCV_HAL_IMPL_AVX_ZIP(v_uint64x4) +OPENCV_HAL_IMPL_AVX_ZIP(v_int64x4) +OPENCV_HAL_IMPL_AVX_ZIP(v_float32x8) +OPENCV_HAL_IMPL_AVX_ZIP(v_float64x4) + +////////// Arithmetic, bitwise and comparison operations ///////// + +/* Element-wise binary and unary operations */ + +/** Arithmetics **/ +#define OPENCV_HAL_IMPL_AVX_BIN_OP(bin_op, _Tpvec, intrin) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(intrin(a.val, b.val)); } \ + inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ + { a.val = intrin(a.val, b.val); return a; } + +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint8x32, _mm256_adds_epu8) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint8x32, _mm256_subs_epu8) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int8x32, _mm256_adds_epi8) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int8x32, _mm256_subs_epi8) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint16x16, _mm256_adds_epu16) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint16x16, _mm256_subs_epu16) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int16x16, _mm256_adds_epi16) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int16x16, _mm256_subs_epi16) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint32x8, _mm256_add_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint32x8, _mm256_sub_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_uint32x8, _mm256_mullo_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int32x8, _mm256_add_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int32x8, _mm256_sub_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_int32x8, _mm256_mullo_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint64x4, _mm256_add_epi64) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint64x4, _mm256_sub_epi64) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int64x4, _mm256_add_epi64) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int64x4, _mm256_sub_epi64) + +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_float32x8, _mm256_add_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_float32x8, _mm256_sub_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_float32x8, _mm256_mul_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(/, v_float32x8, _mm256_div_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_float64x4, _mm256_add_pd) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_float64x4, _mm256_sub_pd) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_float64x4, _mm256_mul_pd) +OPENCV_HAL_IMPL_AVX_BIN_OP(/, v_float64x4, _mm256_div_pd) + +// saturating multiply 8-bit, 16-bit +inline v_uint8x32 operator * (const v_uint8x32& a, const v_uint8x32& b) +{ + v_uint16x16 c, d; + v_mul_expand(a, b, c, d); + return v_pack(c, d); +} +inline v_int8x32 operator * (const v_int8x32& a, const v_int8x32& b) +{ + v_int16x16 c, d; + v_mul_expand(a, b, c, d); + return v_pack(c, d); +} +inline v_uint16x16 operator * (const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i pl = _mm256_mullo_epi16(a.val, b.val); + __m256i ph = _mm256_mulhi_epu16(a.val, b.val); + __m256i p0 = _mm256_unpacklo_epi16(pl, ph); + __m256i p1 = _mm256_unpackhi_epi16(pl, ph); + return v_uint16x16(_v256_packs_epu32(p0, p1)); +} +inline v_int16x16 operator * (const v_int16x16& a, const v_int16x16& b) +{ + __m256i pl = _mm256_mullo_epi16(a.val, b.val); + __m256i ph = _mm256_mulhi_epi16(a.val, b.val); + __m256i p0 = _mm256_unpacklo_epi16(pl, ph); + __m256i p1 = _mm256_unpackhi_epi16(pl, ph); + return v_int16x16(_mm256_packs_epi32(p0, p1)); +} +inline v_uint8x32& operator *= (v_uint8x32& a, const v_uint8x32& b) +{ a = a * b; return a; } +inline v_int8x32& operator *= (v_int8x32& a, const v_int8x32& b) +{ a = a * b; return a; } +inline v_uint16x16& operator *= (v_uint16x16& a, const v_uint16x16& b) +{ a = a * b; return a; } +inline v_int16x16& operator *= (v_int16x16& a, const v_int16x16& b) +{ a = a * b; return a; } + +/** Non-saturating arithmetics **/ +#define OPENCV_HAL_IMPL_AVX_BIN_FUNC(func, _Tpvec, intrin) \ + inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(intrin(a.val, b.val)); } + +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint8x32, _mm256_add_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int8x32, _mm256_add_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint16x16, _mm256_add_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int16x16, _mm256_add_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint8x32, _mm256_sub_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int8x32, _mm256_sub_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint16x16, _mm256_sub_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int16x16, _mm256_sub_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_mul_wrap, v_uint16x16, _mm256_mullo_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_mul_wrap, v_int16x16, _mm256_mullo_epi16) + +inline v_uint8x32 v_mul_wrap(const v_uint8x32& a, const v_uint8x32& b) +{ + __m256i ad = _mm256_srai_epi16(a.val, 8); + __m256i bd = _mm256_srai_epi16(b.val, 8); + __m256i p0 = _mm256_mullo_epi16(a.val, b.val); // even + __m256i p1 = _mm256_slli_epi16(_mm256_mullo_epi16(ad, bd), 8); // odd + + const __m256i b01 = _mm256_set1_epi32(0xFF00FF00); + return v_uint8x32(_mm256_blendv_epi8(p0, p1, b01)); +} +inline v_int8x32 v_mul_wrap(const v_int8x32& a, const v_int8x32& b) +{ + return v_reinterpret_as_s8(v_mul_wrap(v_reinterpret_as_u8(a), v_reinterpret_as_u8(b))); +} + +// Multiply and expand +inline void v_mul_expand(const v_uint8x32& a, const v_uint8x32& b, + v_uint16x16& c, v_uint16x16& d) +{ + v_uint16x16 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int8x32& a, const v_int8x32& b, + v_int16x16& c, v_int16x16& d) +{ + v_int16x16 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int16x16& a, const v_int16x16& b, + v_int32x8& c, v_int32x8& d) +{ + v_int16x16 vhi = v_int16x16(_mm256_mulhi_epi16(a.val, b.val)); + + v_int16x16 v0, v1; + v_zip(v_mul_wrap(a, b), vhi, v0, v1); + + c = v_reinterpret_as_s32(v0); + d = v_reinterpret_as_s32(v1); +} + +inline void v_mul_expand(const v_uint16x16& a, const v_uint16x16& b, + v_uint32x8& c, v_uint32x8& d) +{ + v_uint16x16 vhi = v_uint16x16(_mm256_mulhi_epu16(a.val, b.val)); + + v_uint16x16 v0, v1; + v_zip(v_mul_wrap(a, b), vhi, v0, v1); + + c = v_reinterpret_as_u32(v0); + d = v_reinterpret_as_u32(v1); +} + +inline void v_mul_expand(const v_uint32x8& a, const v_uint32x8& b, + v_uint64x4& c, v_uint64x4& d) +{ + __m256i v0 = _mm256_mul_epu32(a.val, b.val); + __m256i v1 = _mm256_mul_epu32(_mm256_srli_epi64(a.val, 32), _mm256_srli_epi64(b.val, 32)); + v_zip(v_uint64x4(v0), v_uint64x4(v1), c, d); +} + +inline v_int16x16 v_mul_hi(const v_int16x16& a, const v_int16x16& b) { return v_int16x16(_mm256_mulhi_epi16(a.val, b.val)); } +inline v_uint16x16 v_mul_hi(const v_uint16x16& a, const v_uint16x16& b) { return v_uint16x16(_mm256_mulhi_epu16(a.val, b.val)); } + +/** Bitwise shifts **/ +#define OPENCV_HAL_IMPL_AVX_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, srai) \ + inline _Tpuvec operator << (const _Tpuvec& a, int imm) \ + { return _Tpuvec(_mm256_slli_##suffix(a.val, imm)); } \ + inline _Tpsvec operator << (const _Tpsvec& a, int imm) \ + { return _Tpsvec(_mm256_slli_##suffix(a.val, imm)); } \ + inline _Tpuvec operator >> (const _Tpuvec& a, int imm) \ + { return _Tpuvec(_mm256_srli_##suffix(a.val, imm)); } \ + inline _Tpsvec operator >> (const _Tpsvec& a, int imm) \ + { return _Tpsvec(srai(a.val, imm)); } \ + template \ + inline _Tpuvec v_shl(const _Tpuvec& a) \ + { return _Tpuvec(_mm256_slli_##suffix(a.val, imm)); } \ + template \ + inline _Tpsvec v_shl(const _Tpsvec& a) \ + { return _Tpsvec(_mm256_slli_##suffix(a.val, imm)); } \ + template \ + inline _Tpuvec v_shr(const _Tpuvec& a) \ + { return _Tpuvec(_mm256_srli_##suffix(a.val, imm)); } \ + template \ + inline _Tpsvec v_shr(const _Tpsvec& a) \ + { return _Tpsvec(srai(a.val, imm)); } + +OPENCV_HAL_IMPL_AVX_SHIFT_OP(v_uint16x16, v_int16x16, epi16, _mm256_srai_epi16) +OPENCV_HAL_IMPL_AVX_SHIFT_OP(v_uint32x8, v_int32x8, epi32, _mm256_srai_epi32) + +inline __m256i _mm256_srai_epi64xx(const __m256i a, int imm) +{ + __m256i d = _mm256_set1_epi64x((int64)1 << 63); + __m256i r = _mm256_srli_epi64(_mm256_add_epi64(a, d), imm); + return _mm256_sub_epi64(r, _mm256_srli_epi64(d, imm)); +} +OPENCV_HAL_IMPL_AVX_SHIFT_OP(v_uint64x4, v_int64x4, epi64, _mm256_srai_epi64xx) + + +/** Bitwise logic **/ +#define OPENCV_HAL_IMPL_AVX_LOGIC_OP(_Tpvec, suffix, not_const) \ + OPENCV_HAL_IMPL_AVX_BIN_OP(&, _Tpvec, _mm256_and_##suffix) \ + OPENCV_HAL_IMPL_AVX_BIN_OP(|, _Tpvec, _mm256_or_##suffix) \ + OPENCV_HAL_IMPL_AVX_BIN_OP(^, _Tpvec, _mm256_xor_##suffix) \ + inline _Tpvec operator ~ (const _Tpvec& a) \ + { return _Tpvec(_mm256_xor_##suffix(a.val, not_const)); } + +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint8x32, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int8x32, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint16x16, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int16x16, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint32x8, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int32x8, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint64x4, si256, _mm256_set1_epi64x(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int64x4, si256, _mm256_set1_epi64x(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_float32x8, ps, _mm256_castsi256_ps(_mm256_set1_epi32(-1))) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_float64x4, pd, _mm256_castsi256_pd(_mm256_set1_epi32(-1))) + +/** Select **/ +#define OPENCV_HAL_IMPL_AVX_SELECT(_Tpvec, suffix) \ + inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_blendv_##suffix(b.val, a.val, mask.val)); } + +OPENCV_HAL_IMPL_AVX_SELECT(v_uint8x32, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_int8x32, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_uint16x16, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_int16x16, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_uint32x8, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_int32x8, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_SELECT(v_float64x4, pd) + +/** Comparison **/ +#define OPENCV_HAL_IMPL_AVX_CMP_OP_OV(_Tpvec) \ + inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ + { return ~(a == b); } \ + inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ + { return b > a; } \ + inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ + { return ~(a < b); } \ + inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ + { return b >= a; } + +#define OPENCV_HAL_IMPL_AVX_CMP_OP_INT(_Tpuvec, _Tpsvec, suffix, sbit) \ + inline _Tpuvec operator == (const _Tpuvec& a, const _Tpuvec& b) \ + { return _Tpuvec(_mm256_cmpeq_##suffix(a.val, b.val)); } \ + inline _Tpuvec operator > (const _Tpuvec& a, const _Tpuvec& b) \ + { \ + __m256i smask = _mm256_set1_##suffix(sbit); \ + return _Tpuvec(_mm256_cmpgt_##suffix( \ + _mm256_xor_si256(a.val, smask), \ + _mm256_xor_si256(b.val, smask))); \ + } \ + inline _Tpsvec operator == (const _Tpsvec& a, const _Tpsvec& b) \ + { return _Tpsvec(_mm256_cmpeq_##suffix(a.val, b.val)); } \ + inline _Tpsvec operator > (const _Tpsvec& a, const _Tpsvec& b) \ + { return _Tpsvec(_mm256_cmpgt_##suffix(a.val, b.val)); } \ + OPENCV_HAL_IMPL_AVX_CMP_OP_OV(_Tpuvec) \ + OPENCV_HAL_IMPL_AVX_CMP_OP_OV(_Tpsvec) + +OPENCV_HAL_IMPL_AVX_CMP_OP_INT(v_uint8x32, v_int8x32, epi8, (char)-128) +OPENCV_HAL_IMPL_AVX_CMP_OP_INT(v_uint16x16, v_int16x16, epi16, (short)-32768) +OPENCV_HAL_IMPL_AVX_CMP_OP_INT(v_uint32x8, v_int32x8, epi32, (int)0x80000000) + +#define OPENCV_HAL_IMPL_AVX_CMP_OP_64BIT(_Tpvec) \ + inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_cmpeq_epi64(a.val, b.val)); } \ + inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ + { return ~(a == b); } + +OPENCV_HAL_IMPL_AVX_CMP_OP_64BIT(v_uint64x4) +OPENCV_HAL_IMPL_AVX_CMP_OP_64BIT(v_int64x4) + +#define OPENCV_HAL_IMPL_AVX_CMP_FLT(bin_op, imm8, _Tpvec, suffix) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_cmp_##suffix(a.val, b.val, imm8)); } + +#define OPENCV_HAL_IMPL_AVX_CMP_OP_FLT(_Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(==, _CMP_EQ_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(!=, _CMP_NEQ_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(<, _CMP_LT_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(>, _CMP_GT_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(<=, _CMP_LE_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(>=, _CMP_GE_OQ, _Tpvec, suffix) + +OPENCV_HAL_IMPL_AVX_CMP_OP_FLT(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_CMP_OP_FLT(v_float64x4, pd) + +inline v_float32x8 v_not_nan(const v_float32x8& a) +{ return v_float32x8(_mm256_cmp_ps(a.val, a.val, _CMP_ORD_Q)); } +inline v_float64x4 v_not_nan(const v_float64x4& a) +{ return v_float64x4(_mm256_cmp_pd(a.val, a.val, _CMP_ORD_Q)); } + +/** min/max **/ +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_uint8x32, _mm256_min_epu8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_uint8x32, _mm256_max_epu8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_int8x32, _mm256_min_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_int8x32, _mm256_max_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_uint16x16, _mm256_min_epu16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_uint16x16, _mm256_max_epu16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_int16x16, _mm256_min_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_int16x16, _mm256_max_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_uint32x8, _mm256_min_epu32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_uint32x8, _mm256_max_epu32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_int32x8, _mm256_min_epi32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_int32x8, _mm256_max_epi32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_float32x8, _mm256_min_ps) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_float32x8, _mm256_max_ps) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_float64x4, _mm256_min_pd) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_float64x4, _mm256_max_pd) + +/** Rotate **/ +template +inline v_uint8x32 v_rotate_left(const v_uint8x32& a, const v_uint8x32& b) +{ + enum {IMM_R = (16 - imm) & 0xFF}; + enum {IMM_R2 = (32 - imm) & 0xFF}; + + if (imm == 0) return a; + if (imm == 32) return b; + if (imm > 32) return v_uint8x32(); + + __m256i swap = _mm256_permute2x128_si256(a.val, b.val, 0x03); + if (imm == 16) return v_uint8x32(swap); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(a.val, swap, IMM_R)); + return v_uint8x32(_mm256_alignr_epi8(swap, b.val, IMM_R2)); // imm < 32 +} + +template +inline v_uint8x32 v_rotate_right(const v_uint8x32& a, const v_uint8x32& b) +{ + enum {IMM_L = (imm - 16) & 0xFF}; + + if (imm == 0) return a; + if (imm == 32) return b; + if (imm > 32) return v_uint8x32(); + + __m256i swap = _mm256_permute2x128_si256(a.val, b.val, 0x21); + if (imm == 16) return v_uint8x32(swap); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(swap, a.val, imm)); + return v_uint8x32(_mm256_alignr_epi8(b.val, swap, IMM_L)); +} + +template +inline v_uint8x32 v_rotate_left(const v_uint8x32& a) +{ + enum {IMM_L = (imm - 16) & 0xFF}; + enum {IMM_R = (16 - imm) & 0xFF}; + + if (imm == 0) return a; + if (imm > 32) return v_uint8x32(); + + // ESAC control[3] ? [127:0] = 0 + __m256i swapz = _mm256_permute2x128_si256(a.val, a.val, _MM_SHUFFLE(0, 0, 2, 0)); + if (imm == 16) return v_uint8x32(swapz); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(a.val, swapz, IMM_R)); + return v_uint8x32(_mm256_slli_si256(swapz, IMM_L)); +} + +template +inline v_uint8x32 v_rotate_right(const v_uint8x32& a) +{ + enum {IMM_L = (imm - 16) & 0xFF}; + + if (imm == 0) return a; + if (imm > 32) return v_uint8x32(); + + // ESAC control[3] ? [127:0] = 0 + __m256i swapz = _mm256_permute2x128_si256(a.val, a.val, _MM_SHUFFLE(2, 0, 0, 1)); + if (imm == 16) return v_uint8x32(swapz); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(swapz, a.val, imm)); + return v_uint8x32(_mm256_srli_si256(swapz, IMM_L)); +} + +#define OPENCV_HAL_IMPL_AVX_ROTATE_CAST(intrin, _Tpvec, cast) \ + template \ + inline _Tpvec intrin(const _Tpvec& a, const _Tpvec& b) \ + { \ + enum {IMMxW = imm * sizeof(typename _Tpvec::lane_type)}; \ + v_uint8x32 ret = intrin(v_reinterpret_as_u8(a), \ + v_reinterpret_as_u8(b)); \ + return _Tpvec(cast(ret.val)); \ + } \ + template \ + inline _Tpvec intrin(const _Tpvec& a) \ + { \ + enum {IMMxW = imm * sizeof(typename _Tpvec::lane_type)}; \ + v_uint8x32 ret = intrin(v_reinterpret_as_u8(a)); \ + return _Tpvec(cast(ret.val)); \ + } + +#define OPENCV_HAL_IMPL_AVX_ROTATE(_Tpvec) \ + OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_left, _Tpvec, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_right, _Tpvec, OPENCV_HAL_NOP) + +OPENCV_HAL_IMPL_AVX_ROTATE(v_int8x32) +OPENCV_HAL_IMPL_AVX_ROTATE(v_uint16x16) +OPENCV_HAL_IMPL_AVX_ROTATE(v_int16x16) +OPENCV_HAL_IMPL_AVX_ROTATE(v_uint32x8) +OPENCV_HAL_IMPL_AVX_ROTATE(v_int32x8) +OPENCV_HAL_IMPL_AVX_ROTATE(v_uint64x4) +OPENCV_HAL_IMPL_AVX_ROTATE(v_int64x4) + +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_left, v_float32x8, _mm256_castsi256_ps) +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_right, v_float32x8, _mm256_castsi256_ps) +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_left, v_float64x4, _mm256_castsi256_pd) +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_right, v_float64x4, _mm256_castsi256_pd) + +////////// Reduce and mask ///////// + +/** Reduce **/ +#define OPENCV_HAL_IMPL_AVX_REDUCE_16(_Tpvec, sctype, func, intrin) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { \ + __m128i v0 = _v256_extract_low(a.val); \ + __m128i v1 = _v256_extract_high(a.val); \ + v0 = intrin(v0, v1); \ + v0 = intrin(v0, _mm_srli_si128(v0, 8)); \ + v0 = intrin(v0, _mm_srli_si128(v0, 4)); \ + v0 = intrin(v0, _mm_srli_si128(v0, 2)); \ + return (sctype) _mm_cvtsi128_si32(v0); \ + } + +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_uint16x16, ushort, min, _mm_min_epu16) +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_int16x16, short, min, _mm_min_epi16) +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_uint16x16, ushort, max, _mm_max_epu16) +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_int16x16, short, max, _mm_max_epi16) + +#define OPENCV_HAL_IMPL_AVX_REDUCE_8(_Tpvec, sctype, func, intrin) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { \ + __m128i v0 = _v256_extract_low(a.val); \ + __m128i v1 = _v256_extract_high(a.val); \ + v0 = intrin(v0, v1); \ + v0 = intrin(v0, _mm_srli_si128(v0, 8)); \ + v0 = intrin(v0, _mm_srli_si128(v0, 4)); \ + return (sctype) _mm_cvtsi128_si32(v0); \ + } + +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_uint32x8, unsigned, min, _mm_min_epu32) +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_int32x8, int, min, _mm_min_epi32) +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_uint32x8, unsigned, max, _mm_max_epu32) +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_int32x8, int, max, _mm_max_epi32) + +#define OPENCV_HAL_IMPL_AVX_REDUCE_FLT(func, intrin) \ + inline float v_reduce_##func(const v_float32x8& a) \ + { \ + __m128 v0 = _v256_extract_low(a.val); \ + __m128 v1 = _v256_extract_high(a.val); \ + v0 = intrin(v0, v1); \ + v0 = intrin(v0, _mm_permute_ps(v0, _MM_SHUFFLE(0, 0, 3, 2))); \ + v0 = intrin(v0, _mm_permute_ps(v0, _MM_SHUFFLE(0, 0, 0, 3))); \ + return _mm_cvtss_f32(v0); \ + } + +OPENCV_HAL_IMPL_AVX_REDUCE_FLT(min, _mm_min_ps) +OPENCV_HAL_IMPL_AVX_REDUCE_FLT(max, _mm_max_ps) + +inline ushort v_reduce_sum(const v_uint16x16& a) +{ + __m128i a0 = _v256_extract_low(a.val); + __m128i a1 = _v256_extract_high(a.val); + + __m128i s0 = _mm_adds_epu16(a0, a1); + s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 8)); + s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 4)); + s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 2)); + + return (ushort)_mm_cvtsi128_si32(s0); +} + +inline short v_reduce_sum(const v_int16x16& a) +{ + __m256i s0 = _mm256_hadds_epi16(a.val, a.val); + s0 = _mm256_hadds_epi16(s0, s0); + s0 = _mm256_hadds_epi16(s0, s0); + + __m128i s1 = _v256_extract_high(s0); + s1 = _mm_adds_epi16(_v256_extract_low(s0), s1); + + return (short)_mm_cvtsi128_si32(s1); +} + +inline int v_reduce_sum(const v_int32x8& a) +{ + __m256i s0 = _mm256_hadd_epi32(a.val, a.val); + s0 = _mm256_hadd_epi32(s0, s0); + + __m128i s1 = _v256_extract_high(s0); + s1 = _mm_add_epi32(_v256_extract_low(s0), s1); + + return _mm_cvtsi128_si32(s1); +} + +inline unsigned v_reduce_sum(const v_uint32x8& a) +{ return v_reduce_sum(v_reinterpret_as_s32(a)); } + +inline float v_reduce_sum(const v_float32x8& a) +{ + __m256 s0 = _mm256_hadd_ps(a.val, a.val); + s0 = _mm256_hadd_ps(s0, s0); + + __m128 s1 = _v256_extract_high(s0); + s1 = _mm_add_ps(_v256_extract_low(s0), s1); + + return _mm_cvtss_f32(s1); +} + +inline double v_reduce_sum(const v_float64x4& a) +{ + __m256d s0 = _mm256_hadd_pd(a.val, a.val); + return _mm_cvtsd_f64(_mm_add_pd(_v256_extract_low(s0), _v256_extract_high(s0))); +} + +inline v_float32x8 v_reduce_sum4(const v_float32x8& a, const v_float32x8& b, + const v_float32x8& c, const v_float32x8& d) +{ + __m256 ab = _mm256_hadd_ps(a.val, b.val); + __m256 cd = _mm256_hadd_ps(c.val, d.val); + return v_float32x8(_mm256_hadd_ps(ab, cd)); +} + +inline unsigned v_reduce_sad(const v_uint8x32& a, const v_uint8x32& b) +{ + return (unsigned)_v_cvtsi256_si32(_mm256_sad_epu8(a.val, b.val)); +} +inline unsigned v_reduce_sad(const v_int8x32& a, const v_int8x32& b) +{ + __m256i half = _mm256_set1_epi8(0x7f); + return (unsigned)_v_cvtsi256_si32(_mm256_sad_epu8(_mm256_add_epi8(a.val, half), _mm256_add_epi8(b.val, half))); +} +inline unsigned v_reduce_sad(const v_uint16x16& a, const v_uint16x16& b) +{ + v_uint32x8 l, h; + v_expand(v_add_wrap(a - b, b - a), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_int16x16& a, const v_int16x16& b) +{ + v_uint32x8 l, h; + v_expand(v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_uint32x8& a, const v_uint32x8& b) +{ + return v_reduce_sum(v_max(a, b) - v_min(a, b)); +} +inline unsigned v_reduce_sad(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 m = a < b; + return v_reduce_sum(v_reinterpret_as_u32(((a - b) ^ m) - m)); +} +inline float v_reduce_sad(const v_float32x8& a, const v_float32x8& b) +{ + return v_reduce_sum((a - b) & v_float32x8(_mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff)))); +} + +/** Popcount **/ +#define OPENCV_HAL_IMPL_AVX_POPCOUNT(_Tpvec) \ + inline v_uint32x8 v_popcount(const _Tpvec& a) \ + { \ + const v_uint32x8 m1 = v256_setall_u32(0x55555555); \ + const v_uint32x8 m2 = v256_setall_u32(0x33333333); \ + const v_uint32x8 m4 = v256_setall_u32(0x0f0f0f0f); \ + v_uint32x8 p = v_reinterpret_as_u32(a); \ + p = ((p >> 1) & m1) + (p & m1); \ + p = ((p >> 2) & m2) + (p & m2); \ + p = ((p >> 4) & m4) + (p & m4); \ + p.val = _mm256_sad_epu8(p.val, _mm256_setzero_si256()); \ + return p; \ + } + +OPENCV_HAL_IMPL_AVX_POPCOUNT(v_uint8x32) +OPENCV_HAL_IMPL_AVX_POPCOUNT(v_int8x32) +OPENCV_HAL_IMPL_AVX_POPCOUNT(v_uint16x16) +OPENCV_HAL_IMPL_AVX_POPCOUNT(v_int16x16) +OPENCV_HAL_IMPL_AVX_POPCOUNT(v_uint32x8) +OPENCV_HAL_IMPL_AVX_POPCOUNT(v_int32x8) + +/** Mask **/ +inline int v_signmask(const v_int8x32& a) +{ return _mm256_movemask_epi8(a.val); } +inline int v_signmask(const v_uint8x32& a) +{ return v_signmask(v_reinterpret_as_s8(a)); } + +inline int v_signmask(const v_int16x16& a) +{ + v_int8x32 v = v_int8x32(_mm256_packs_epi16(a.val, a.val)); + return v_signmask(v) & 255; +} +inline int v_signmask(const v_uint16x16& a) +{ return v_signmask(v_reinterpret_as_s16(a)); } + +inline int v_signmask(const v_int32x8& a) +{ + __m256i a16 = _mm256_packs_epi32(a.val, a.val); + v_int8x32 v = v_int8x32(_mm256_packs_epi16(a16, a16)); + return v_signmask(v) & 15; +} +inline int v_signmask(const v_uint32x8& a) +{ return v_signmask(v_reinterpret_as_s32(a)); } + +inline int v_signmask(const v_float32x8& a) +{ return _mm256_movemask_ps(a.val); } +inline int v_signmask(const v_float64x4& a) +{ return _mm256_movemask_pd(a.val); } + +/** Checks **/ +#define OPENCV_HAL_IMPL_AVX_CHECK(_Tpvec, and_op, allmask) \ + inline bool v_check_all(const _Tpvec& a) \ + { \ + int mask = v_signmask(v_reinterpret_as_s8(a)); \ + return and_op(mask, allmask) == allmask; \ + } \ + inline bool v_check_any(const _Tpvec& a) \ + { \ + int mask = v_signmask(v_reinterpret_as_s8(a)); \ + return and_op(mask, allmask) != 0; \ + } + +OPENCV_HAL_IMPL_AVX_CHECK(v_uint8x32, OPENCV_HAL_1ST, -1) +OPENCV_HAL_IMPL_AVX_CHECK(v_int8x32, OPENCV_HAL_1ST, -1) +OPENCV_HAL_IMPL_AVX_CHECK(v_uint16x16, OPENCV_HAL_AND, (int)0xaaaa) +OPENCV_HAL_IMPL_AVX_CHECK(v_int16x16, OPENCV_HAL_AND, (int)0xaaaa) +OPENCV_HAL_IMPL_AVX_CHECK(v_uint32x8, OPENCV_HAL_AND, (int)0x8888) +OPENCV_HAL_IMPL_AVX_CHECK(v_int32x8, OPENCV_HAL_AND, (int)0x8888) + +#define OPENCV_HAL_IMPL_AVX_CHECK_FLT(_Tpvec, allmask) \ + inline bool v_check_all(const _Tpvec& a) \ + { \ + int mask = v_signmask(a); \ + return mask == allmask; \ + } \ + inline bool v_check_any(const _Tpvec& a) \ + { \ + int mask = v_signmask(a); \ + return mask != 0; \ + } + +OPENCV_HAL_IMPL_AVX_CHECK_FLT(v_float32x8, 255) +OPENCV_HAL_IMPL_AVX_CHECK_FLT(v_float64x4, 15) + + +////////// Other math ///////// + +/** Some frequent operations **/ +#define OPENCV_HAL_IMPL_AVX_MULADD(_Tpvec, suffix) \ + inline _Tpvec v_fma(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm256_fmadd_##suffix(a.val, b.val, c.val)); } \ + inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm256_fmadd_##suffix(a.val, b.val, c.val)); } \ + inline _Tpvec v_sqrt(const _Tpvec& x) \ + { return _Tpvec(_mm256_sqrt_##suffix(x.val)); } \ + inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ + { return v_fma(a, a, b * b); } \ + inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ + { return v_sqrt(v_fma(a, a, b*b)); } + +OPENCV_HAL_IMPL_AVX_MULADD(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_MULADD(v_float64x4, pd) + +inline v_int32x8 v_fma(const v_int32x8& a, const v_int32x8& b, const v_int32x8& c) +{ + return a * b + c; +} + +inline v_int32x8 v_muladd(const v_int32x8& a, const v_int32x8& b, const v_int32x8& c) +{ + return v_fma(a, b, c); +} + +inline v_float32x8 v_invsqrt(const v_float32x8& x) +{ + v_float32x8 half = x * v256_setall_f32(0.5); + v_float32x8 t = v_float32x8(_mm256_rsqrt_ps(x.val)); + // todo: _mm256_fnmsub_ps + t *= v256_setall_f32(1.5) - ((t * t) * half); + return t; +} + +inline v_float64x4 v_invsqrt(const v_float64x4& x) +{ + return v256_setall_f64(1.) / v_sqrt(x); +} + +/** Absolute values **/ +#define OPENCV_HAL_IMPL_AVX_ABS(_Tpvec, suffix) \ + inline v_u##_Tpvec v_abs(const v_##_Tpvec& x) \ + { return v_u##_Tpvec(_mm256_abs_##suffix(x.val)); } + +OPENCV_HAL_IMPL_AVX_ABS(int8x32, epi8) +OPENCV_HAL_IMPL_AVX_ABS(int16x16, epi16) +OPENCV_HAL_IMPL_AVX_ABS(int32x8, epi32) + +inline v_float32x8 v_abs(const v_float32x8& x) +{ return x & v_float32x8(_mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff))); } +inline v_float64x4 v_abs(const v_float64x4& x) +{ return x & v_float64x4(_mm256_castsi256_pd(_mm256_srli_epi64(_mm256_set1_epi64x(-1), 1))); } + +/** Absolute difference **/ +inline v_uint8x32 v_absdiff(const v_uint8x32& a, const v_uint8x32& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint16x16 v_absdiff(const v_uint16x16& a, const v_uint16x16& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint32x8 v_absdiff(const v_uint32x8& a, const v_uint32x8& b) +{ return v_max(a, b) - v_min(a, b); } + +inline v_uint8x32 v_absdiff(const v_int8x32& a, const v_int8x32& b) +{ + v_int8x32 d = v_sub_wrap(a, b); + v_int8x32 m = a < b; + return v_reinterpret_as_u8(v_sub_wrap(d ^ m, m)); +} + +inline v_uint16x16 v_absdiff(const v_int16x16& a, const v_int16x16& b) +{ return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); } + +inline v_uint32x8 v_absdiff(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 d = a - b; + v_int32x8 m = a < b; + return v_reinterpret_as_u32((d ^ m) - m); +} + +inline v_float32x8 v_absdiff(const v_float32x8& a, const v_float32x8& b) +{ return v_abs(a - b); } + +inline v_float64x4 v_absdiff(const v_float64x4& a, const v_float64x4& b) +{ return v_abs(a - b); } + +/** Saturating absolute difference **/ +inline v_int8x32 v_absdiffs(const v_int8x32& a, const v_int8x32& b) +{ + v_int8x32 d = a - b; + v_int8x32 m = a < b; + return (d ^ m) - m; +} +inline v_int16x16 v_absdiffs(const v_int16x16& a, const v_int16x16& b) +{ return v_max(a, b) - v_min(a, b); } + +////////// Conversions ///////// + +/** Rounding **/ +inline v_int32x8 v_round(const v_float32x8& a) +{ return v_int32x8(_mm256_cvtps_epi32(a.val)); } + +inline v_int32x8 v_round(const v_float64x4& a) +{ return v_int32x8(_mm256_castsi128_si256(_mm256_cvtpd_epi32(a.val))); } + +inline v_int32x8 v_round(const v_float64x4& a, const v_float64x4& b) +{ + __m128i ai = _mm256_cvtpd_epi32(a.val), bi = _mm256_cvtpd_epi32(b.val); + return v_int32x8(_v256_combine(ai, bi)); +} + +inline v_int32x8 v_trunc(const v_float32x8& a) +{ return v_int32x8(_mm256_cvttps_epi32(a.val)); } + +inline v_int32x8 v_trunc(const v_float64x4& a) +{ return v_int32x8(_mm256_castsi128_si256(_mm256_cvttpd_epi32(a.val))); } + +inline v_int32x8 v_floor(const v_float32x8& a) +{ return v_int32x8(_mm256_cvttps_epi32(_mm256_floor_ps(a.val))); } + +inline v_int32x8 v_floor(const v_float64x4& a) +{ return v_trunc(v_float64x4(_mm256_floor_pd(a.val))); } + +inline v_int32x8 v_ceil(const v_float32x8& a) +{ return v_int32x8(_mm256_cvttps_epi32(_mm256_ceil_ps(a.val))); } + +inline v_int32x8 v_ceil(const v_float64x4& a) +{ return v_trunc(v_float64x4(_mm256_ceil_pd(a.val))); } + +/** To float **/ +inline v_float32x8 v_cvt_f32(const v_int32x8& a) +{ return v_float32x8(_mm256_cvtepi32_ps(a.val)); } + +inline v_float32x8 v_cvt_f32(const v_float64x4& a) +{ return v_float32x8(_mm256_castps128_ps256(_mm256_cvtpd_ps(a.val))); } + +inline v_float32x8 v_cvt_f32(const v_float64x4& a, const v_float64x4& b) +{ + __m128 af = _mm256_cvtpd_ps(a.val), bf = _mm256_cvtpd_ps(b.val); + return v_float32x8(_mm256_insertf128_ps(_mm256_castps128_ps256(af), bf, 1)); +} + +inline v_float64x4 v_cvt_f64(const v_int32x8& a) +{ return v_float64x4(_mm256_cvtepi32_pd(_v256_extract_low(a.val))); } + +inline v_float64x4 v_cvt_f64_high(const v_int32x8& a) +{ return v_float64x4(_mm256_cvtepi32_pd(_v256_extract_high(a.val))); } + +inline v_float64x4 v_cvt_f64(const v_float32x8& a) +{ return v_float64x4(_mm256_cvtps_pd(_v256_extract_low(a.val))); } + +inline v_float64x4 v_cvt_f64_high(const v_float32x8& a) +{ return v_float64x4(_mm256_cvtps_pd(_v256_extract_high(a.val))); } + +////////////// Lookup table access //////////////////// + +inline v_int32x8 v_lut(const int* tab, const v_int32x8& idxvec) +{ + return v_int32x8(_mm256_i32gather_epi32(tab, idxvec.val, 4)); +} + +inline v_uint32x8 v_lut(const unsigned* tab, const v_int32x8& idxvec) +{ + return v_reinterpret_as_u32(v_lut((const int *)tab, idxvec)); +} + +inline v_float32x8 v_lut(const float* tab, const v_int32x8& idxvec) +{ + return v_float32x8(_mm256_i32gather_ps(tab, idxvec.val, 4)); +} + +inline v_float64x4 v_lut(const double* tab, const v_int32x8& idxvec) +{ + return v_float64x4(_mm256_i32gather_pd(tab, _mm256_castsi256_si128(idxvec.val), 8)); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x8& idxvec, v_float32x8& x, v_float32x8& y) +{ + int CV_DECL_ALIGNED(32) idx[8]; + v_store_aligned(idx, idxvec); + __m128 z = _mm_setzero_ps(); + __m128 xy01, xy45, xy23, xy67; + xy01 = _mm_loadl_pi(z, (const __m64*)(tab + idx[0])); + xy01 = _mm_loadh_pi(xy01, (const __m64*)(tab + idx[1])); + xy45 = _mm_loadl_pi(z, (const __m64*)(tab + idx[4])); + xy45 = _mm_loadh_pi(xy45, (const __m64*)(tab + idx[5])); + __m256 xy0145 = _v256_combine(xy01, xy45); + xy23 = _mm_loadl_pi(z, (const __m64*)(tab + idx[2])); + xy23 = _mm_loadh_pi(xy23, (const __m64*)(tab + idx[3])); + xy67 = _mm_loadl_pi(z, (const __m64*)(tab + idx[6])); + xy67 = _mm_loadh_pi(xy67, (const __m64*)(tab + idx[7])); + __m256 xy2367 = _v256_combine(xy23, xy67); + + __m256 xxyy0145 = _mm256_unpacklo_ps(xy0145, xy2367); + __m256 xxyy2367 = _mm256_unpackhi_ps(xy0145, xy2367); + + x = v_float32x8(_mm256_unpacklo_ps(xxyy0145, xxyy2367)); + y = v_float32x8(_mm256_unpackhi_ps(xxyy0145, xxyy2367)); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x8& idxvec, v_float64x4& x, v_float64x4& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_low(idx, idxvec); + __m128d xy0 = _mm_loadu_pd(tab + idx[0]); + __m128d xy2 = _mm_loadu_pd(tab + idx[2]); + __m128d xy1 = _mm_loadu_pd(tab + idx[1]); + __m128d xy3 = _mm_loadu_pd(tab + idx[3]); + __m256d xy02 = _v256_combine(xy0, xy2); + __m256d xy13 = _v256_combine(xy1, xy3); + + x = v_float64x4(_mm256_unpacklo_pd(xy02, xy13)); + y = v_float64x4(_mm256_unpackhi_pd(xy02, xy13)); +} + +////////// Matrix operations ///////// + +inline v_int32x8 v_dotprod(const v_int16x16& a, const v_int16x16& b) +{ return v_int32x8(_mm256_madd_epi16(a.val, b.val)); } + +inline v_int32x8 v_dotprod(const v_int16x16& a, const v_int16x16& b, const v_int32x8& c) +{ return v_dotprod(a, b) + c; } + +#define OPENCV_HAL_AVX_SPLAT2_PS(a, im) \ + v_float32x8(_mm256_permute_ps(a.val, _MM_SHUFFLE(im, im, im, im))) + +inline v_float32x8 v_matmul(const v_float32x8& v, const v_float32x8& m0, + const v_float32x8& m1, const v_float32x8& m2, + const v_float32x8& m3) +{ + v_float32x8 v04 = OPENCV_HAL_AVX_SPLAT2_PS(v, 0); + v_float32x8 v15 = OPENCV_HAL_AVX_SPLAT2_PS(v, 1); + v_float32x8 v26 = OPENCV_HAL_AVX_SPLAT2_PS(v, 2); + v_float32x8 v37 = OPENCV_HAL_AVX_SPLAT2_PS(v, 3); + return v_fma(v04, m0, v_fma(v15, m1, v_fma(v26, m2, v37 * m3))); +} + +inline v_float32x8 v_matmuladd(const v_float32x8& v, const v_float32x8& m0, + const v_float32x8& m1, const v_float32x8& m2, + const v_float32x8& a) +{ + v_float32x8 v04 = OPENCV_HAL_AVX_SPLAT2_PS(v, 0); + v_float32x8 v15 = OPENCV_HAL_AVX_SPLAT2_PS(v, 1); + v_float32x8 v26 = OPENCV_HAL_AVX_SPLAT2_PS(v, 2); + return v_fma(v04, m0, v_fma(v15, m1, v_fma(v26, m2, a))); +} + +#define OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(_Tpvec, suffix, cast_from, cast_to) \ + inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, _Tpvec& b2, _Tpvec& b3) \ + { \ + __m256i t0 = cast_from(_mm256_unpacklo_##suffix(a0.val, a1.val)); \ + __m256i t1 = cast_from(_mm256_unpacklo_##suffix(a2.val, a3.val)); \ + __m256i t2 = cast_from(_mm256_unpackhi_##suffix(a0.val, a1.val)); \ + __m256i t3 = cast_from(_mm256_unpackhi_##suffix(a2.val, a3.val)); \ + b0.val = cast_to(_mm256_unpacklo_epi64(t0, t1)); \ + b1.val = cast_to(_mm256_unpackhi_epi64(t0, t1)); \ + b2.val = cast_to(_mm256_unpacklo_epi64(t2, t3)); \ + b3.val = cast_to(_mm256_unpackhi_epi64(t2, t3)); \ + } + +OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(v_uint32x8, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(v_int32x8, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(v_float32x8, ps, _mm256_castps_si256, _mm256_castsi256_ps) + +//////////////// Value reordering /////////////// + +/* Expand */ +#define OPENCV_HAL_IMPL_AVX_EXPAND(_Tpvec, _Tpwvec, _Tp, intrin) \ + inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ + { \ + b0.val = intrin(_v256_extract_low(a.val)); \ + b1.val = intrin(_v256_extract_high(a.val)); \ + } \ + inline _Tpwvec v_expand_low(const _Tpvec& a) \ + { return _Tpwvec(intrin(_v256_extract_low(a.val))); } \ + inline _Tpwvec v_expand_high(const _Tpvec& a) \ + { return _Tpwvec(intrin(_v256_extract_high(a.val))); } \ + inline _Tpwvec v256_load_expand(const _Tp* ptr) \ + { \ + __m128i a = _mm_loadu_si128((const __m128i*)ptr); \ + return _Tpwvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_AVX_EXPAND(v_uint8x32, v_uint16x16, uchar, _mm256_cvtepu8_epi16) +OPENCV_HAL_IMPL_AVX_EXPAND(v_int8x32, v_int16x16, schar, _mm256_cvtepi8_epi16) +OPENCV_HAL_IMPL_AVX_EXPAND(v_uint16x16, v_uint32x8, ushort, _mm256_cvtepu16_epi32) +OPENCV_HAL_IMPL_AVX_EXPAND(v_int16x16, v_int32x8, short, _mm256_cvtepi16_epi32) +OPENCV_HAL_IMPL_AVX_EXPAND(v_uint32x8, v_uint64x4, unsigned, _mm256_cvtepu32_epi64) +OPENCV_HAL_IMPL_AVX_EXPAND(v_int32x8, v_int64x4, int, _mm256_cvtepi32_epi64) + +#define OPENCV_HAL_IMPL_AVX_EXPAND_Q(_Tpvec, _Tp, intrin) \ + inline _Tpvec v256_load_expand_q(const _Tp* ptr) \ + { \ + __m128i a = _mm_loadl_epi64((const __m128i*)ptr); \ + return _Tpvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_AVX_EXPAND_Q(v_uint32x8, uchar, _mm256_cvtepu8_epi32) +OPENCV_HAL_IMPL_AVX_EXPAND_Q(v_int32x8, schar, _mm256_cvtepi8_epi32) + +/* pack */ +// 16 +inline v_int8x32 v_pack(const v_int16x16& a, const v_int16x16& b) +{ return v_int8x32(_v256_shuffle_odd_64(_mm256_packs_epi16(a.val, b.val))); } + +inline v_uint8x32 v_pack(const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i t = _mm256_set1_epi16(255); + __m256i a1 = _mm256_min_epu16(a.val, t); + __m256i b1 = _mm256_min_epu16(b.val, t); + return v_uint8x32(_v256_shuffle_odd_64(_mm256_packus_epi16(a1, b1))); +} + +inline v_uint8x32 v_pack_u(const v_int16x16& a, const v_int16x16& b) +{ + return v_uint8x32(_v256_shuffle_odd_64(_mm256_packus_epi16(a.val, b.val))); +} + +inline void v_pack_store(schar* ptr, const v_int16x16& a) +{ v_store_low(ptr, v_pack(a, a)); } + +inline void v_pack_store(uchar* ptr, const v_uint16x16& a) +{ + const __m256i m = _mm256_set1_epi16(255); + __m256i am = _mm256_min_epu16(a.val, m); + am = _v256_shuffle_odd_64(_mm256_packus_epi16(am, am)); + v_store_low(ptr, v_uint8x32(am)); +} + +inline void v_pack_u_store(uchar* ptr, const v_int16x16& a) +{ v_store_low(ptr, v_pack_u(a, a)); } + +template inline +v_uint8x32 v_rshr_pack(const v_uint16x16& a, const v_uint16x16& b) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + v_uint16x16 delta = v256_setall_u16((short)(1 << (n-1))); + return v_pack_u(v_reinterpret_as_s16((a + delta) >> n), + v_reinterpret_as_s16((b + delta) >> n)); +} + +template inline +void v_rshr_pack_store(uchar* ptr, const v_uint16x16& a) +{ + v_uint16x16 delta = v256_setall_u16((short)(1 << (n-1))); + v_pack_u_store(ptr, v_reinterpret_as_s16((a + delta) >> n)); +} + +template inline +v_uint8x32 v_rshr_pack_u(const v_int16x16& a, const v_int16x16& b) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + return v_pack_u((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_u_store(uchar* ptr, const v_int16x16& a) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + v_pack_u_store(ptr, (a + delta) >> n); +} + +template inline +v_int8x32 v_rshr_pack(const v_int16x16& a, const v_int16x16& b) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(schar* ptr, const v_int16x16& a) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + v_pack_store(ptr, (a + delta) >> n); +} + +// 32 +inline v_int16x16 v_pack(const v_int32x8& a, const v_int32x8& b) +{ return v_int16x16(_v256_shuffle_odd_64(_mm256_packs_epi32(a.val, b.val))); } + +inline v_uint16x16 v_pack(const v_uint32x8& a, const v_uint32x8& b) +{ return v_uint16x16(_v256_shuffle_odd_64(_v256_packs_epu32(a.val, b.val))); } + +inline v_uint16x16 v_pack_u(const v_int32x8& a, const v_int32x8& b) +{ return v_uint16x16(_v256_shuffle_odd_64(_mm256_packus_epi32(a.val, b.val))); } + +inline void v_pack_store(short* ptr, const v_int32x8& a) +{ v_store_low(ptr, v_pack(a, a)); } + +inline void v_pack_store(ushort* ptr, const v_uint32x8& a) +{ + const __m256i m = _mm256_set1_epi32(65535); + __m256i am = _mm256_min_epu32(a.val, m); + am = _v256_shuffle_odd_64(_mm256_packus_epi32(am, am)); + v_store_low(ptr, v_uint16x16(am)); +} + +inline void v_pack_u_store(ushort* ptr, const v_int32x8& a) +{ v_store_low(ptr, v_pack_u(a, a)); } + + +template inline +v_uint16x16 v_rshr_pack(const v_uint32x8& a, const v_uint32x8& b) +{ + // we assume that n > 0, and so the shifted 32-bit values can be treated as signed numbers. + v_uint32x8 delta = v256_setall_u32(1 << (n-1)); + return v_pack_u(v_reinterpret_as_s32((a + delta) >> n), + v_reinterpret_as_s32((b + delta) >> n)); +} + +template inline +void v_rshr_pack_store(ushort* ptr, const v_uint32x8& a) +{ + v_uint32x8 delta = v256_setall_u32(1 << (n-1)); + v_pack_u_store(ptr, v_reinterpret_as_s32((a + delta) >> n)); +} + +template inline +v_uint16x16 v_rshr_pack_u(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + return v_pack_u((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_u_store(ushort* ptr, const v_int32x8& a) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + v_pack_u_store(ptr, (a + delta) >> n); +} + +template inline +v_int16x16 v_rshr_pack(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(short* ptr, const v_int32x8& a) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +// 64 +// Non-saturating pack +inline v_uint32x8 v_pack(const v_uint64x4& a, const v_uint64x4& b) +{ + __m256i a0 = _mm256_shuffle_epi32(a.val, _MM_SHUFFLE(0, 0, 2, 0)); + __m256i b0 = _mm256_shuffle_epi32(b.val, _MM_SHUFFLE(0, 0, 2, 0)); + __m256i ab = _mm256_unpacklo_epi64(a0, b0); // a0, a1, b0, b1, a2, a3, b2, b3 + return v_uint32x8(_v256_shuffle_odd_64(ab)); +} + +inline v_int32x8 v_pack(const v_int64x4& a, const v_int64x4& b) +{ return v_reinterpret_as_s32(v_pack(v_reinterpret_as_u64(a), v_reinterpret_as_u64(b))); } + +inline void v_pack_store(unsigned* ptr, const v_uint64x4& a) +{ + __m256i a0 = _mm256_shuffle_epi32(a.val, _MM_SHUFFLE(0, 0, 2, 0)); + v_store_low(ptr, v_uint32x8(_v256_shuffle_odd_64(a0))); +} + +inline void v_pack_store(int* ptr, const v_int64x4& b) +{ v_pack_store((unsigned*)ptr, v_reinterpret_as_u64(b)); } + +template inline +v_uint32x8 v_rshr_pack(const v_uint64x4& a, const v_uint64x4& b) +{ + v_uint64x4 delta = v256_setall_u64((uint64)1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(unsigned* ptr, const v_uint64x4& a) +{ + v_uint64x4 delta = v256_setall_u64((uint64)1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +template inline +v_int32x8 v_rshr_pack(const v_int64x4& a, const v_int64x4& b) +{ + v_int64x4 delta = v256_setall_s64((int64)1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(int* ptr, const v_int64x4& a) +{ + v_int64x4 delta = v256_setall_s64((int64)1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +// pack boolean +inline v_uint8x32 v_pack_b(const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i ab = _mm256_packs_epi16(a.val, b.val); + return v_uint8x32(_v256_shuffle_odd_64(ab)); +} + +inline v_uint8x32 v_pack_b(const v_uint32x8& a, const v_uint32x8& b, + const v_uint32x8& c, const v_uint32x8& d) +{ + __m256i ab = _mm256_packs_epi32(a.val, b.val); + __m256i cd = _mm256_packs_epi32(c.val, d.val); + + __m256i abcd = _v256_shuffle_odd_64(_mm256_packs_epi16(ab, cd)); + return v_uint8x32(_mm256_shuffle_epi32(abcd, _MM_SHUFFLE(3, 1, 2, 0))); +} + +inline v_uint8x32 v_pack_b(const v_uint64x4& a, const v_uint64x4& b, const v_uint64x4& c, + const v_uint64x4& d, const v_uint64x4& e, const v_uint64x4& f, + const v_uint64x4& g, const v_uint64x4& h) +{ + __m256i ab = _mm256_packs_epi32(a.val, b.val); + __m256i cd = _mm256_packs_epi32(c.val, d.val); + __m256i ef = _mm256_packs_epi32(e.val, f.val); + __m256i gh = _mm256_packs_epi32(g.val, h.val); + + __m256i abcd = _mm256_packs_epi32(ab, cd); + __m256i efgh = _mm256_packs_epi32(ef, gh); + __m256i pkall = _v256_shuffle_odd_64(_mm256_packs_epi16(abcd, efgh)); + + __m256i rev = _mm256_alignr_epi8(pkall, pkall, 8); + return v_uint8x32(_mm256_unpacklo_epi16(pkall, rev)); +} + +/* Recombine */ +// its up there with load and store operations + +/* Extract */ +#define OPENCV_HAL_IMPL_AVX_EXTRACT(_Tpvec) \ + template \ + inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) \ + { return v_rotate_right(a, b); } + +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint8x32) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int8x32) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint16x16) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int16x16) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint32x8) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int32x8) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint64x4) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int64x4) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_float32x8) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_float64x4) + + +///////////////////// load deinterleave ///////////////////////////// + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x32& a, v_uint8x32& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + + const __m256i sh = _mm256_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15, + 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15); + __m256i p0 = _mm256_shuffle_epi8(ab0, sh); + __m256i p1 = _mm256_shuffle_epi8(ab1, sh); + __m256i pl = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint8x32(a0); + b = v_uint8x32(b0); +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x16& a, v_uint16x16& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + + const __m256i sh = _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15, + 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15); + __m256i p0 = _mm256_shuffle_epi8(ab0, sh); + __m256i p1 = _mm256_shuffle_epi8(ab1, sh); + __m256i pl = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint16x16(a0); + b = v_uint16x16(b0); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x8& a, v_uint32x8& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + + const int sh = 0+2*4+1*16+3*64; + __m256i p0 = _mm256_shuffle_epi32(ab0, sh); + __m256i p1 = _mm256_shuffle_epi32(ab1, sh); + __m256i pl = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint32x8(a0); + b = v_uint32x8(b0); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x4& a, v_uint64x4& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 4)); + + __m256i pl = _mm256_permute2x128_si256(ab0, ab1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(ab0, ab1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint64x4(a0); + b = v_uint64x4(b0); +} + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x32& b, v_uint8x32& g, v_uint8x32& r ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 64)); + + __m256i s02_low = _mm256_permute2x128_si256(bgr0, bgr2, 0 + 2*16); + __m256i s02_high = _mm256_permute2x128_si256(bgr0, bgr2, 1 + 3*16); + + const __m256i m0 = _mm256_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, + 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, + -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1); + + __m256i b0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_low, s02_high, m0), bgr1, m1); + __m256i g0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_high, s02_low, m1), bgr1, m0); + __m256i r0 = _mm256_blendv_epi8(_mm256_blendv_epi8(bgr1, s02_low, m0), s02_high, m1); + + const __m256i + sh_b = _mm256_setr_epi8(0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13, + 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13), + sh_g = _mm256_setr_epi8(1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, + 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14), + sh_r = _mm256_setr_epi8(2, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, + 2, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15); + b0 = _mm256_shuffle_epi8(b0, sh_b); + g0 = _mm256_shuffle_epi8(g0, sh_g); + r0 = _mm256_shuffle_epi8(r0, sh_r); + + b = v_uint8x32(b0); + g = v_uint8x32(g0); + r = v_uint8x32(r0); +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x16& b, v_uint16x16& g, v_uint16x16& r ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + + __m256i s02_low = _mm256_permute2x128_si256(bgr0, bgr2, 0 + 2*16); + __m256i s02_high = _mm256_permute2x128_si256(bgr0, bgr2, 1 + 3*16); + + const __m256i m0 = _mm256_setr_epi8(0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, + 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, + -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0); + __m256i b0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_low, s02_high, m0), bgr1, m1); + __m256i g0 = _mm256_blendv_epi8(_mm256_blendv_epi8(bgr1, s02_low, m0), s02_high, m1); + __m256i r0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_high, s02_low, m1), bgr1, m0); + const __m256i sh_b = _mm256_setr_epi8(0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, + 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m256i sh_g = _mm256_setr_epi8(2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, + 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 0, 1, 6, 7, 12, 13); + const __m256i sh_r = _mm256_setr_epi8(4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, + 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + b0 = _mm256_shuffle_epi8(b0, sh_b); + g0 = _mm256_shuffle_epi8(g0, sh_g); + r0 = _mm256_shuffle_epi8(r0, sh_r); + + b = v_uint16x16(b0); + g = v_uint16x16(g0); + r = v_uint16x16(r0); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x8& b, v_uint32x8& g, v_uint32x8& r ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + + __m256i s02_low = _mm256_permute2x128_si256(bgr0, bgr2, 0 + 2*16); + __m256i s02_high = _mm256_permute2x128_si256(bgr0, bgr2, 1 + 3*16); + + __m256i b0 = _mm256_blend_epi32(_mm256_blend_epi32(s02_low, s02_high, 0x24), bgr1, 0x92); + __m256i g0 = _mm256_blend_epi32(_mm256_blend_epi32(s02_high, s02_low, 0x92), bgr1, 0x24); + __m256i r0 = _mm256_blend_epi32(_mm256_blend_epi32(bgr1, s02_low, 0x24), s02_high, 0x92); + + b0 = _mm256_shuffle_epi32(b0, 0x6c); + g0 = _mm256_shuffle_epi32(g0, 0xb1); + r0 = _mm256_shuffle_epi32(r0, 0xc6); + + b = v_uint32x8(b0); + g = v_uint32x8(g0); + r = v_uint32x8(r0); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x4& b, v_uint64x4& g, v_uint64x4& r ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 4)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + + __m256i s01 = _mm256_blend_epi32(bgr0, bgr1, 0xf0); + __m256i s12 = _mm256_blend_epi32(bgr1, bgr2, 0xf0); + __m256i s20r = _mm256_permute4x64_epi64(_mm256_blend_epi32(bgr2, bgr0, 0xf0), 0x1b); + __m256i b0 = _mm256_unpacklo_epi64(s01, s20r); + __m256i g0 = _mm256_alignr_epi8(s12, s01, 8); + __m256i r0 = _mm256_unpackhi_epi64(s20r, s12); + + b = v_uint64x4(b0); + g = v_uint64x4(g0); + r = v_uint64x4(r0); +} + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x32& b, v_uint8x32& g, v_uint8x32& r, v_uint8x32& a ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 64)); + __m256i bgr3 = _mm256_loadu_si256((const __m256i*)(ptr + 96)); + const __m256i sh = _mm256_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, + 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + + __m256i p0 = _mm256_shuffle_epi8(bgr0, sh); + __m256i p1 = _mm256_shuffle_epi8(bgr1, sh); + __m256i p2 = _mm256_shuffle_epi8(bgr2, sh); + __m256i p3 = _mm256_shuffle_epi8(bgr3, sh); + + __m256i p01l = _mm256_unpacklo_epi32(p0, p1); + __m256i p01h = _mm256_unpackhi_epi32(p0, p1); + __m256i p23l = _mm256_unpacklo_epi32(p2, p3); + __m256i p23h = _mm256_unpackhi_epi32(p2, p3); + + __m256i pll = _mm256_permute2x128_si256(p01l, p23l, 0 + 2*16); + __m256i plh = _mm256_permute2x128_si256(p01l, p23l, 1 + 3*16); + __m256i phl = _mm256_permute2x128_si256(p01h, p23h, 0 + 2*16); + __m256i phh = _mm256_permute2x128_si256(p01h, p23h, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi32(pll, plh); + __m256i g0 = _mm256_unpackhi_epi32(pll, plh); + __m256i r0 = _mm256_unpacklo_epi32(phl, phh); + __m256i a0 = _mm256_unpackhi_epi32(phl, phh); + + b = v_uint8x32(b0); + g = v_uint8x32(g0); + r = v_uint8x32(r0); + a = v_uint8x32(a0); +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x16& b, v_uint16x16& g, v_uint16x16& r, v_uint16x16& a ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + __m256i bgr3 = _mm256_loadu_si256((const __m256i*)(ptr + 48)); + const __m256i sh = _mm256_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, + 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15); + __m256i p0 = _mm256_shuffle_epi8(bgr0, sh); + __m256i p1 = _mm256_shuffle_epi8(bgr1, sh); + __m256i p2 = _mm256_shuffle_epi8(bgr2, sh); + __m256i p3 = _mm256_shuffle_epi8(bgr3, sh); + + __m256i p01l = _mm256_unpacklo_epi32(p0, p1); + __m256i p01h = _mm256_unpackhi_epi32(p0, p1); + __m256i p23l = _mm256_unpacklo_epi32(p2, p3); + __m256i p23h = _mm256_unpackhi_epi32(p2, p3); + + __m256i pll = _mm256_permute2x128_si256(p01l, p23l, 0 + 2*16); + __m256i plh = _mm256_permute2x128_si256(p01l, p23l, 1 + 3*16); + __m256i phl = _mm256_permute2x128_si256(p01h, p23h, 0 + 2*16); + __m256i phh = _mm256_permute2x128_si256(p01h, p23h, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi32(pll, plh); + __m256i g0 = _mm256_unpackhi_epi32(pll, plh); + __m256i r0 = _mm256_unpacklo_epi32(phl, phh); + __m256i a0 = _mm256_unpackhi_epi32(phl, phh); + + b = v_uint16x16(b0); + g = v_uint16x16(g0); + r = v_uint16x16(r0); + a = v_uint16x16(a0); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x8& b, v_uint32x8& g, v_uint32x8& r, v_uint32x8& a ) +{ + __m256i p0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i p1 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + __m256i p2 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + __m256i p3 = _mm256_loadu_si256((const __m256i*)(ptr + 24)); + + __m256i p01l = _mm256_unpacklo_epi32(p0, p1); + __m256i p01h = _mm256_unpackhi_epi32(p0, p1); + __m256i p23l = _mm256_unpacklo_epi32(p2, p3); + __m256i p23h = _mm256_unpackhi_epi32(p2, p3); + + __m256i pll = _mm256_permute2x128_si256(p01l, p23l, 0 + 2*16); + __m256i plh = _mm256_permute2x128_si256(p01l, p23l, 1 + 3*16); + __m256i phl = _mm256_permute2x128_si256(p01h, p23h, 0 + 2*16); + __m256i phh = _mm256_permute2x128_si256(p01h, p23h, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi32(pll, plh); + __m256i g0 = _mm256_unpackhi_epi32(pll, plh); + __m256i r0 = _mm256_unpacklo_epi32(phl, phh); + __m256i a0 = _mm256_unpackhi_epi32(phl, phh); + + b = v_uint32x8(b0); + g = v_uint32x8(g0); + r = v_uint32x8(r0); + a = v_uint32x8(a0); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x4& b, v_uint64x4& g, v_uint64x4& r, v_uint64x4& a ) +{ + __m256i bgra0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgra1 = _mm256_loadu_si256((const __m256i*)(ptr + 4)); + __m256i bgra2 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + __m256i bgra3 = _mm256_loadu_si256((const __m256i*)(ptr + 12)); + + __m256i l02 = _mm256_permute2x128_si256(bgra0, bgra2, 0 + 2*16); + __m256i h02 = _mm256_permute2x128_si256(bgra0, bgra2, 1 + 3*16); + __m256i l13 = _mm256_permute2x128_si256(bgra1, bgra3, 0 + 2*16); + __m256i h13 = _mm256_permute2x128_si256(bgra1, bgra3, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi64(l02, l13); + __m256i g0 = _mm256_unpackhi_epi64(l02, l13); + __m256i r0 = _mm256_unpacklo_epi64(h02, h13); + __m256i a0 = _mm256_unpackhi_epi64(h02, h13); + + b = v_uint64x4(b0); + g = v_uint64x4(g0); + r = v_uint64x4(r0); + a = v_uint64x4(a0); +} + +///////////////////////////// store interleave ///////////////////////////////////// + +inline void v_store_interleave( uchar* ptr, const v_uint8x32& x, const v_uint8x32& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi8(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi8(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 32), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 32), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 32), xy1); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x16& x, const v_uint16x16& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi16(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi16(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 16), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 16), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 16), xy1); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x8& x, const v_uint32x8& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi32(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi32(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 8), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 8), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 8), xy1); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x4& x, const v_uint64x4& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi64(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi64(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 4), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 4), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 4), xy1); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x32& b, const v_uint8x32& g, const v_uint8x32& r, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + const __m256i sh_b = _mm256_setr_epi8( + 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, 5, + 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, 5); + const __m256i sh_g = _mm256_setr_epi8( + 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, + 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10); + const __m256i sh_r = _mm256_setr_epi8( + 10, 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, + 10, 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15); + + __m256i b0 = _mm256_shuffle_epi8(b.val, sh_b); + __m256i g0 = _mm256_shuffle_epi8(g.val, sh_g); + __m256i r0 = _mm256_shuffle_epi8(r.val, sh_r); + + const __m256i m0 = _mm256_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, + 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, + 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0); + + __m256i p0 = _mm256_blendv_epi8(_mm256_blendv_epi8(b0, g0, m0), r0, m1); + __m256i p1 = _mm256_blendv_epi8(_mm256_blendv_epi8(g0, r0, m0), b0, m1); + __m256i p2 = _mm256_blendv_epi8(_mm256_blendv_epi8(r0, b0, m0), g0, m1); + + __m256i bgr0 = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i bgr1 = _mm256_permute2x128_si256(p2, p0, 0 + 3*16); + __m256i bgr2 = _mm256_permute2x128_si256(p1, p2, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 32), bgr1); + _mm256_stream_si256((__m256i*)(ptr + 64), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 32), bgr1); + _mm256_store_si256((__m256i*)(ptr + 64), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgr1); + _mm256_storeu_si256((__m256i*)(ptr + 64), bgr2); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x16& b, const v_uint16x16& g, const v_uint16x16& r, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + const __m256i sh_b = _mm256_setr_epi8( + 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, + 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m256i sh_g = _mm256_setr_epi8( + 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, + 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5); + const __m256i sh_r = _mm256_setr_epi8( + 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, + 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + + __m256i b0 = _mm256_shuffle_epi8(b.val, sh_b); + __m256i g0 = _mm256_shuffle_epi8(g.val, sh_g); + __m256i r0 = _mm256_shuffle_epi8(r.val, sh_r); + + const __m256i m0 = _mm256_setr_epi8(0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, + 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, + -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0); + + __m256i p0 = _mm256_blendv_epi8(_mm256_blendv_epi8(b0, g0, m0), r0, m1); + __m256i p1 = _mm256_blendv_epi8(_mm256_blendv_epi8(g0, r0, m0), b0, m1); + __m256i p2 = _mm256_blendv_epi8(_mm256_blendv_epi8(r0, b0, m0), g0, m1); + + __m256i bgr0 = _mm256_permute2x128_si256(p0, p2, 0 + 2*16); + //__m256i bgr1 = p1; + __m256i bgr2 = _mm256_permute2x128_si256(p0, p2, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 16), p1); + _mm256_stream_si256((__m256i*)(ptr + 32), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 16), p1); + _mm256_store_si256((__m256i*)(ptr + 32), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 16), p1); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgr2); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x8& b, const v_uint32x8& g, const v_uint32x8& r, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i b0 = _mm256_shuffle_epi32(b.val, 0x6c); + __m256i g0 = _mm256_shuffle_epi32(g.val, 0xb1); + __m256i r0 = _mm256_shuffle_epi32(r.val, 0xc6); + + __m256i p0 = _mm256_blend_epi32(_mm256_blend_epi32(b0, g0, 0x92), r0, 0x24); + __m256i p1 = _mm256_blend_epi32(_mm256_blend_epi32(g0, r0, 0x92), b0, 0x24); + __m256i p2 = _mm256_blend_epi32(_mm256_blend_epi32(r0, b0, 0x92), g0, 0x24); + + __m256i bgr0 = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + //__m256i bgr1 = p2; + __m256i bgr2 = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 8), p2); + _mm256_stream_si256((__m256i*)(ptr + 16), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 8), p2); + _mm256_store_si256((__m256i*)(ptr + 16), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 8), p2); + _mm256_storeu_si256((__m256i*)(ptr + 16), bgr2); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x4& b, const v_uint64x4& g, const v_uint64x4& r, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i s01 = _mm256_unpacklo_epi64(b.val, g.val); + __m256i s12 = _mm256_unpackhi_epi64(g.val, r.val); + __m256i s20 = _mm256_blend_epi32(r.val, b.val, 0xcc); + + __m256i bgr0 = _mm256_permute2x128_si256(s01, s20, 0 + 2*16); + __m256i bgr1 = _mm256_blend_epi32(s01, s12, 0x0f); + __m256i bgr2 = _mm256_permute2x128_si256(s20, s12, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 4), bgr1); + _mm256_stream_si256((__m256i*)(ptr + 8), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 4), bgr1); + _mm256_store_si256((__m256i*)(ptr + 8), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 4), bgr1); + _mm256_storeu_si256((__m256i*)(ptr + 8), bgr2); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x32& b, const v_uint8x32& g, + const v_uint8x32& r, const v_uint8x32& a, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi8(b.val, g.val); + __m256i bg1 = _mm256_unpackhi_epi8(b.val, g.val); + __m256i ra0 = _mm256_unpacklo_epi8(r.val, a.val); + __m256i ra1 = _mm256_unpackhi_epi8(r.val, a.val); + + __m256i bgra0_ = _mm256_unpacklo_epi16(bg0, ra0); + __m256i bgra1_ = _mm256_unpackhi_epi16(bg0, ra0); + __m256i bgra2_ = _mm256_unpacklo_epi16(bg1, ra1); + __m256i bgra3_ = _mm256_unpackhi_epi16(bg1, ra1); + + __m256i bgra0 = _mm256_permute2x128_si256(bgra0_, bgra1_, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bgra0_, bgra1_, 1 + 3*16); + __m256i bgra1 = _mm256_permute2x128_si256(bgra2_, bgra3_, 0 + 2*16); + __m256i bgra3 = _mm256_permute2x128_si256(bgra2_, bgra3_, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 32), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 64), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 96), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 32), bgra1); + _mm256_store_si256((__m256i*)(ptr + 64), bgra2); + _mm256_store_si256((__m256i*)(ptr + 96), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 64), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 96), bgra3); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x16& b, const v_uint16x16& g, + const v_uint16x16& r, const v_uint16x16& a, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi16(b.val, g.val); + __m256i bg1 = _mm256_unpackhi_epi16(b.val, g.val); + __m256i ra0 = _mm256_unpacklo_epi16(r.val, a.val); + __m256i ra1 = _mm256_unpackhi_epi16(r.val, a.val); + + __m256i bgra0_ = _mm256_unpacklo_epi32(bg0, ra0); + __m256i bgra1_ = _mm256_unpackhi_epi32(bg0, ra0); + __m256i bgra2_ = _mm256_unpacklo_epi32(bg1, ra1); + __m256i bgra3_ = _mm256_unpackhi_epi32(bg1, ra1); + + __m256i bgra0 = _mm256_permute2x128_si256(bgra0_, bgra1_, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bgra0_, bgra1_, 1 + 3*16); + __m256i bgra1 = _mm256_permute2x128_si256(bgra2_, bgra3_, 0 + 2*16); + __m256i bgra3 = _mm256_permute2x128_si256(bgra2_, bgra3_, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 16), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 32), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 48), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 16), bgra1); + _mm256_store_si256((__m256i*)(ptr + 32), bgra2); + _mm256_store_si256((__m256i*)(ptr + 48), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 16), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 48), bgra3); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x8& b, const v_uint32x8& g, + const v_uint32x8& r, const v_uint32x8& a, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi32(b.val, g.val); + __m256i bg1 = _mm256_unpackhi_epi32(b.val, g.val); + __m256i ra0 = _mm256_unpacklo_epi32(r.val, a.val); + __m256i ra1 = _mm256_unpackhi_epi32(r.val, a.val); + + __m256i bgra0_ = _mm256_unpacklo_epi64(bg0, ra0); + __m256i bgra1_ = _mm256_unpackhi_epi64(bg0, ra0); + __m256i bgra2_ = _mm256_unpacklo_epi64(bg1, ra1); + __m256i bgra3_ = _mm256_unpackhi_epi64(bg1, ra1); + + __m256i bgra0 = _mm256_permute2x128_si256(bgra0_, bgra1_, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bgra0_, bgra1_, 1 + 3*16); + __m256i bgra1 = _mm256_permute2x128_si256(bgra2_, bgra3_, 0 + 2*16); + __m256i bgra3 = _mm256_permute2x128_si256(bgra2_, bgra3_, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 8), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 16), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 24), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 8), bgra1); + _mm256_store_si256((__m256i*)(ptr + 16), bgra2); + _mm256_store_si256((__m256i*)(ptr + 24), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 8), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 16), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 24), bgra3); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x4& b, const v_uint64x4& g, + const v_uint64x4& r, const v_uint64x4& a, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi64(b.val, g.val); + __m256i bg1 = _mm256_unpackhi_epi64(b.val, g.val); + __m256i ra0 = _mm256_unpacklo_epi64(r.val, a.val); + __m256i ra1 = _mm256_unpackhi_epi64(r.val, a.val); + + __m256i bgra0 = _mm256_permute2x128_si256(bg0, ra0, 0 + 2*16); + __m256i bgra1 = _mm256_permute2x128_si256(bg1, ra1, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bg0, ra0, 1 + 3*16); + __m256i bgra3 = _mm256_permute2x128_si256(bg1, ra1, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 4), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 8), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 12), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 4), bgra1); + _mm256_store_si256((__m256i*)(ptr + 8), bgra2); + _mm256_store_si256((__m256i*)(ptr + 12), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 4), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 8), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 12), bgra3); + } +} + +#define OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(_Tpvec0, _Tp0, suffix0, _Tpvec1, _Tp1, suffix1) \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0 ) \ +{ \ + _Tpvec1 a1, b1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0 ) \ +{ \ + _Tpvec1 a1, b1, c1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0, _Tpvec0& d0 ) \ +{ \ + _Tpvec1 a1, b1, c1, d1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1, d1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ + d0 = v_reinterpret_as_##suffix0(d1); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, const _Tpvec0& c0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, const _Tpvec0& d0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + _Tpvec1 d1 = v_reinterpret_as_##suffix1(d0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, d1, mode); \ +} + +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int8x32, schar, s8, v_uint8x32, uchar, u8) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int16x16, short, s16, v_uint16x16, ushort, u16) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int32x8, int, s32, v_uint32x8, unsigned, u32) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_float32x8, float, f32, v_uint32x8, unsigned, u32) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int64x4, int64, s64, v_uint64x4, uint64, u64) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_float64x4, double, f64, v_uint64x4, uint64, u64) + +// FP16 +inline v_float32x8 v256_load_expand(const float16_t* ptr) +{ + return v_float32x8(_mm256_cvtph_ps(_mm_loadu_si128((const __m128i*)ptr))); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x8& a) +{ + __m128i ah = _mm256_cvtps_ph(a.val, 0); + _mm_storeu_si128((__m128i*)ptr, ah); +} + +inline void v256_cleanup() { _mm256_zeroall(); } + +//! @name Check SIMD256 support +//! @{ +//! @brief Check CPU capability of SIMD operation +static inline bool hasSIMD256() +{ + return (CV_CPU_HAS_SUPPORT_AVX2) ? true : false; +} +//! @} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} // cv:: + +#endif // OPENCV_HAL_INTRIN_AVX_HPP diff --git a/include/opencv2/core/hal/intrin_cpp.hpp b/include/opencv2/core/hal/intrin_cpp.hpp new file mode 100644 index 0000000..65a01f3 --- /dev/null +++ b/include/opencv2/core/hal/intrin_cpp.hpp @@ -0,0 +1,2310 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_HAL_INTRIN_CPP_HPP +#define OPENCV_HAL_INTRIN_CPP_HPP + +#include +#include +#include +#include "opencv2/core/saturate.hpp" + +namespace cv +{ + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +#endif + +/** @addtogroup core_hal_intrin + +"Universal intrinsics" is a types and functions set intended to simplify vectorization of code on +different platforms. Currently there are two supported SIMD extensions: __SSE/SSE2__ on x86 +architectures and __NEON__ on ARM architectures, both allow working with 128 bit registers +containing packed values of different types. In case when there is no SIMD extension available +during compilation, fallback C++ implementation of intrinsics will be chosen and code will work as +expected although it could be slower. + +### Types + +There are several types representing 128-bit register as a vector of packed values, each type is +implemented as a structure based on a one SIMD register. + +- cv::v_uint8x16 and cv::v_int8x16: sixteen 8-bit integer values (unsigned/signed) - char +- cv::v_uint16x8 and cv::v_int16x8: eight 16-bit integer values (unsigned/signed) - short +- cv::v_uint32x4 and cv::v_int32x4: four 32-bit integer values (unsgined/signed) - int +- cv::v_uint64x2 and cv::v_int64x2: two 64-bit integer values (unsigned/signed) - int64 +- cv::v_float32x4: four 32-bit floating point values (signed) - float +- cv::v_float64x2: two 64-bit floating point valies (signed) - double + +@note +cv::v_float64x2 is not implemented in NEON variant, if you want to use this type, don't forget to +check the CV_SIMD128_64F preprocessor definition: +@code +#if CV_SIMD128_64F +//... +#endif +@endcode + +### Load and store operations + +These operations allow to set contents of the register explicitly or by loading it from some memory +block and to save contents of the register to memory block. + +- Constructors: +@ref v_reg::v_reg(const _Tp *ptr) "from memory", +@ref v_reg::v_reg(_Tp s0, _Tp s1) "from two values", ... +- Other create methods: +@ref v_setall_s8, @ref v_setall_u8, ..., +@ref v_setzero_u8, @ref v_setzero_s8, ... +- Memory operations: +@ref v_load, @ref v_load_aligned, @ref v_load_low, @ref v_load_halves, +@ref v_store, @ref v_store_aligned, +@ref v_store_high, @ref v_store_low + +### Value reordering + +These operations allow to reorder or recombine elements in one or multiple vectors. + +- Interleave, deinterleave (2, 3 and 4 channels): @ref v_load_deinterleave, @ref v_store_interleave +- Expand: @ref v_load_expand, @ref v_load_expand_q, @ref v_expand, @ref v_expand_low, @ref v_expand_high +- Pack: @ref v_pack, @ref v_pack_u, @ref v_pack_b, @ref v_rshr_pack, @ref v_rshr_pack_u, +@ref v_pack_store, @ref v_pack_u_store, @ref v_rshr_pack_store, @ref v_rshr_pack_u_store +- Recombine: @ref v_zip, @ref v_recombine, @ref v_combine_low, @ref v_combine_high +- Extract: @ref v_extract + + +### Arithmetic, bitwise and comparison operations + +Element-wise binary and unary operations. + +- Arithmetics: +@ref operator +(const v_reg &a, const v_reg &b) "+", +@ref operator -(const v_reg &a, const v_reg &b) "-", +@ref operator *(const v_reg &a, const v_reg &b) "*", +@ref operator /(const v_reg &a, const v_reg &b) "/", +@ref v_mul_expand + +- Non-saturating arithmetics: @ref v_add_wrap, @ref v_sub_wrap + +- Bitwise shifts: +@ref operator <<(const v_reg &a, int s) "<<", +@ref operator >>(const v_reg &a, int s) ">>", +@ref v_shl, @ref v_shr + +- Bitwise logic: +@ref operator&(const v_reg &a, const v_reg &b) "&", +@ref operator |(const v_reg &a, const v_reg &b) "|", +@ref operator ^(const v_reg &a, const v_reg &b) "^", +@ref operator ~(const v_reg &a) "~" + +- Comparison: +@ref operator >(const v_reg &a, const v_reg &b) ">", +@ref operator >=(const v_reg &a, const v_reg &b) ">=", +@ref operator <(const v_reg &a, const v_reg &b) "<", +@ref operator <=(const v_reg &a, const v_reg &b) "<=", +@ref operator==(const v_reg &a, const v_reg &b) "==", +@ref operator !=(const v_reg &a, const v_reg &b) "!=" + +- min/max: @ref v_min, @ref v_max + +### Reduce and mask + +Most of these operations return only one value. + +- Reduce: @ref v_reduce_min, @ref v_reduce_max, @ref v_reduce_sum, @ref v_popcount +- Mask: @ref v_signmask, @ref v_check_all, @ref v_check_any, @ref v_select + +### Other math + +- Some frequent operations: @ref v_sqrt, @ref v_invsqrt, @ref v_magnitude, @ref v_sqr_magnitude +- Absolute values: @ref v_abs, @ref v_absdiff, @ref v_absdiffs + +### Conversions + +Different type conversions and casts: + +- Rounding: @ref v_round, @ref v_floor, @ref v_ceil, @ref v_trunc, +- To float: @ref v_cvt_f32, @ref v_cvt_f64 +- Reinterpret: @ref v_reinterpret_as_u8, @ref v_reinterpret_as_s8, ... + +### Matrix operations + +In these operations vectors represent matrix rows/columns: @ref v_dotprod, @ref v_matmul, @ref v_transpose4x4 + +### Usability + +Most operations are implemented only for some subset of the available types, following matrices +shows the applicability of different operations to the types. + +Regular integers: + +| Operations\\Types | uint 8x16 | int 8x16 | uint 16x8 | int 16x8 | uint 32x4 | int 32x4 | +|-------------------|:-:|:-:|:-:|:-:|:-:|:-:| +|load, store | x | x | x | x | x | x | +|interleave | x | x | x | x | x | x | +|expand | x | x | x | x | x | x | +|expand_low | x | x | x | x | x | x | +|expand_high | x | x | x | x | x | x | +|expand_q | x | x | | | | | +|add, sub | x | x | x | x | x | x | +|add_wrap, sub_wrap | x | x | x | x | | | +|mul_wrap | x | x | x | x | | | +|mul | x | x | x | x | x | x | +|mul_expand | x | x | x | x | x | | +|compare | x | x | x | x | x | x | +|shift | | | x | x | x | x | +|dotprod | | | | x | | | +|logical | x | x | x | x | x | x | +|min, max | x | x | x | x | x | x | +|absdiff | x | x | x | x | x | x | +|absdiffs | | x | | x | | | +|reduce | | | | | x | x | +|mask | x | x | x | x | x | x | +|pack | x | x | x | x | x | x | +|pack_u | x | | x | | | | +|pack_b | x | | | | | | +|unpack | x | x | x | x | x | x | +|extract | x | x | x | x | x | x | +|rotate (lanes) | x | x | x | x | x | x | +|cvt_flt32 | | | | | | x | +|cvt_flt64 | | | | | | x | +|transpose4x4 | | | | | x | x | + +Big integers: + +| Operations\\Types | uint 64x2 | int 64x2 | +|-------------------|:-:|:-:| +|load, store | x | x | +|add, sub | x | x | +|shift | x | x | +|logical | x | x | +|extract | x | x | +|rotate (lanes) | x | x | + +Floating point: + +| Operations\\Types | float 32x4 | float 64x2 | +|-------------------|:-:|:-:| +|load, store | x | x | +|interleave | x | | +|add, sub | x | x | +|mul | x | x | +|div | x | x | +|compare | x | x | +|min, max | x | x | +|absdiff | x | x | +|reduce | x | | +|mask | x | x | +|unpack | x | x | +|cvt_flt32 | | x | +|cvt_flt64 | x | | +|sqrt, abs | x | x | +|float math | x | x | +|transpose4x4 | x | | +|extract | x | x | +|rotate (lanes) | x | x | + + @{ */ + +template struct v_reg +{ +//! @cond IGNORED + typedef _Tp lane_type; + enum { nlanes = n }; +// !@endcond + + /** @brief Constructor + + Initializes register with data from memory + @param ptr pointer to memory block with data for register */ + explicit v_reg(const _Tp* ptr) { for( int i = 0; i < n; i++ ) s[i] = ptr[i]; } + + /** @brief Constructor + + Initializes register with two 64-bit values */ + v_reg(_Tp s0, _Tp s1) { s[0] = s0; s[1] = s1; } + + /** @brief Constructor + + Initializes register with four 32-bit values */ + v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3) { s[0] = s0; s[1] = s1; s[2] = s2; s[3] = s3; } + + /** @brief Constructor + + Initializes register with eight 16-bit values */ + v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3, + _Tp s4, _Tp s5, _Tp s6, _Tp s7) + { + s[0] = s0; s[1] = s1; s[2] = s2; s[3] = s3; + s[4] = s4; s[5] = s5; s[6] = s6; s[7] = s7; + } + + /** @brief Constructor + + Initializes register with sixteen 8-bit values */ + v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3, + _Tp s4, _Tp s5, _Tp s6, _Tp s7, + _Tp s8, _Tp s9, _Tp s10, _Tp s11, + _Tp s12, _Tp s13, _Tp s14, _Tp s15) + { + s[0] = s0; s[1] = s1; s[2] = s2; s[3] = s3; + s[4] = s4; s[5] = s5; s[6] = s6; s[7] = s7; + s[8] = s8; s[9] = s9; s[10] = s10; s[11] = s11; + s[12] = s12; s[13] = s13; s[14] = s14; s[15] = s15; + } + + /** @brief Default constructor + + Does not initialize anything*/ + v_reg() {} + + /** @brief Copy constructor */ + v_reg(const v_reg<_Tp, n> & r) + { + for( int i = 0; i < n; i++ ) + s[i] = r.s[i]; + } + /** @brief Access first value + + Returns value of the first lane according to register type, for example: + @code{.cpp} + v_int32x4 r(1, 2, 3, 4); + int v = r.get0(); // returns 1 + v_uint64x2 r(1, 2); + uint64_t v = r.get0(); // returns 1 + @endcode + */ + _Tp get0() const { return s[0]; } + +//! @cond IGNORED + _Tp get(const int i) const { return s[i]; } + v_reg<_Tp, n> high() const + { + v_reg<_Tp, n> c; + int i; + for( i = 0; i < n/2; i++ ) + { + c.s[i] = s[i+(n/2)]; + c.s[i+(n/2)] = 0; + } + return c; + } + + static v_reg<_Tp, n> zero() + { + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = (_Tp)0; + return c; + } + + static v_reg<_Tp, n> all(_Tp s) + { + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = s; + return c; + } + + template v_reg<_Tp2, n2> reinterpret_as() const + { + size_t bytes = std::min(sizeof(_Tp2)*n2, sizeof(_Tp)*n); + v_reg<_Tp2, n2> c; + std::memcpy(&c.s[0], &s[0], bytes); + return c; + } + + _Tp s[n]; +//! @endcond +}; + +/** @brief Sixteen 8-bit unsigned integer values */ +typedef v_reg v_uint8x16; +/** @brief Sixteen 8-bit signed integer values */ +typedef v_reg v_int8x16; +/** @brief Eight 16-bit unsigned integer values */ +typedef v_reg v_uint16x8; +/** @brief Eight 16-bit signed integer values */ +typedef v_reg v_int16x8; +/** @brief Four 32-bit unsigned integer values */ +typedef v_reg v_uint32x4; +/** @brief Four 32-bit signed integer values */ +typedef v_reg v_int32x4; +/** @brief Four 32-bit floating point values (single precision) */ +typedef v_reg v_float32x4; +/** @brief Two 64-bit floating point values (double precision) */ +typedef v_reg v_float64x2; +/** @brief Two 64-bit unsigned integer values */ +typedef v_reg v_uint64x2; +/** @brief Two 64-bit signed integer values */ +typedef v_reg v_int64x2; + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_BIN_OP(bin_op) \ +template inline v_reg<_Tp, n> \ + operator bin_op (const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = saturate_cast<_Tp>(a.s[i] bin_op b.s[i]); \ + return c; \ +} \ +template inline v_reg<_Tp, n>& \ + operator bin_op##= (v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + for( int i = 0; i < n; i++ ) \ + a.s[i] = saturate_cast<_Tp>(a.s[i] bin_op b.s[i]); \ + return a; \ +} + +/** @brief Add values + +For all types. */ +OPENCV_HAL_IMPL_BIN_OP(+) + +/** @brief Subtract values + +For all types. */ +OPENCV_HAL_IMPL_BIN_OP(-) + +/** @brief Multiply values + +For 16- and 32-bit integer types and floating types. */ +OPENCV_HAL_IMPL_BIN_OP(*) + +/** @brief Divide values + +For floating types only. */ +OPENCV_HAL_IMPL_BIN_OP(/) + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_BIT_OP(bit_op) \ +template inline v_reg<_Tp, n> operator bit_op \ + (const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + typedef typename V_TypeTraits<_Tp>::int_type itype; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int((itype)(V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) bit_op \ + V_TypeTraits<_Tp>::reinterpret_int(b.s[i]))); \ + return c; \ +} \ +template inline v_reg<_Tp, n>& operator \ + bit_op##= (v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + typedef typename V_TypeTraits<_Tp>::int_type itype; \ + for( int i = 0; i < n; i++ ) \ + a.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int((itype)(V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) bit_op \ + V_TypeTraits<_Tp>::reinterpret_int(b.s[i]))); \ + return a; \ +} + +/** @brief Bitwise AND + +Only for integer types. */ +OPENCV_HAL_IMPL_BIT_OP(&) + +/** @brief Bitwise OR + +Only for integer types. */ +OPENCV_HAL_IMPL_BIT_OP(|) + +/** @brief Bitwise XOR + +Only for integer types.*/ +OPENCV_HAL_IMPL_BIT_OP(^) + +/** @brief Bitwise NOT + +Only for integer types.*/ +template inline v_reg<_Tp, n> operator ~ (const v_reg<_Tp, n>& a) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int(~V_TypeTraits<_Tp>::reinterpret_int(a.s[i])); + } + return c; +} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_MATH_FUNC(func, cfunc, _Tp2) \ +template inline v_reg<_Tp2, n> func(const v_reg<_Tp, n>& a) \ +{ \ + v_reg<_Tp2, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = cfunc(a.s[i]); \ + return c; \ +} + +/** @brief Square root of elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_sqrt, std::sqrt, _Tp) + +//! @cond IGNORED +OPENCV_HAL_IMPL_MATH_FUNC(v_sin, std::sin, _Tp) +OPENCV_HAL_IMPL_MATH_FUNC(v_cos, std::cos, _Tp) +OPENCV_HAL_IMPL_MATH_FUNC(v_exp, std::exp, _Tp) +OPENCV_HAL_IMPL_MATH_FUNC(v_log, std::log, _Tp) +//! @endcond + +/** @brief Absolute value of elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_abs, (typename V_TypeTraits<_Tp>::abs_type)std::abs, + typename V_TypeTraits<_Tp>::abs_type) + +/** @brief Round elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_round, cvRound, int) + +/** @brief Floor elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_floor, cvFloor, int) + +/** @brief Ceil elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_ceil, cvCeil, int) + +/** @brief Truncate elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_trunc, int, int) + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_MINMAX_FUNC(func, cfunc) \ +template inline v_reg<_Tp, n> func(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = cfunc(a.s[i], b.s[i]); \ + return c; \ +} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_REDUCE_MINMAX_FUNC(func, cfunc) \ +template inline _Tp func(const v_reg<_Tp, n>& a) \ +{ \ + _Tp c = a.s[0]; \ + for( int i = 1; i < n; i++ ) \ + c = cfunc(c, a.s[i]); \ + return c; \ +} + +/** @brief Choose min values for each pair + +Scheme: +@code +{A1 A2 ...} +{B1 B2 ...} +-------------- +{min(A1,B1) min(A2,B2) ...} +@endcode +For all types except 64-bit integer. */ +OPENCV_HAL_IMPL_MINMAX_FUNC(v_min, std::min) + +/** @brief Choose max values for each pair + +Scheme: +@code +{A1 A2 ...} +{B1 B2 ...} +-------------- +{max(A1,B1) max(A2,B2) ...} +@endcode +For all types except 64-bit integer. */ +OPENCV_HAL_IMPL_MINMAX_FUNC(v_max, std::max) + +/** @brief Find one min value + +Scheme: +@code +{A1 A2 A3 ...} => min(A1,A2,A3,...) +@endcode +For 32-bit integer and 32-bit floating point types. */ +OPENCV_HAL_IMPL_REDUCE_MINMAX_FUNC(v_reduce_min, std::min) + +/** @brief Find one max value + +Scheme: +@code +{A1 A2 A3 ...} => max(A1,A2,A3,...) +@endcode +For 32-bit integer and 32-bit floating point types. */ +OPENCV_HAL_IMPL_REDUCE_MINMAX_FUNC(v_reduce_max, std::max) + +static const unsigned char popCountTable[] = +{ + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; +/** @brief Count the 1 bits in the vector and return 4 values + +Scheme: +@code +{A1 A2 A3 ...} => popcount(A1) +@endcode +Any types but result will be in v_uint32x4*/ +template inline v_uint32x4 v_popcount(const v_reg<_Tp, n>& a) +{ + v_uint8x16 b; + b = v_reinterpret_as_u8(a); + for( int i = 0; i < v_uint8x16::nlanes; i++ ) + { + b.s[i] = popCountTable[b.s[i]]; + } + v_uint32x4 c; + for( int i = 0; i < v_uint32x4::nlanes; i++ ) + { + c.s[i] = b.s[i*4] + b.s[i*4+1] + b.s[i*4+2] + b.s[i*4+3]; + } + return c; +} + + +//! @cond IGNORED +template +inline void v_minmax( const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + v_reg<_Tp, n>& minval, v_reg<_Tp, n>& maxval ) +{ + for( int i = 0; i < n; i++ ) + { + minval.s[i] = std::min(a.s[i], b.s[i]); + maxval.s[i] = std::max(a.s[i], b.s[i]); + } +} +//! @endcond + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_CMP_OP(cmp_op) \ +template \ +inline v_reg<_Tp, n> operator cmp_op(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + typedef typename V_TypeTraits<_Tp>::int_type itype; \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int((itype)-(int)(a.s[i] cmp_op b.s[i])); \ + return c; \ +} + +/** @brief Less-than comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(<) + +/** @brief Greater-than comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(>) + +/** @brief Less-than or equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(<=) + +/** @brief Greater-than or equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(>=) + +/** @brief Equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(==) + +/** @brief Not equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(!=) + +template +inline v_reg v_not_nan(const v_reg& a) +{ + typedef typename V_TypeTraits::int_type itype; + v_reg c; + for (int i = 0; i < n; i++) + c.s[i] = V_TypeTraits::reinterpret_from_int((itype)-(int)(a.s[i] == a.s[i])); + return c; +} +template +inline v_reg v_not_nan(const v_reg& a) +{ + typedef typename V_TypeTraits::int_type itype; + v_reg c; + for (int i = 0; i < n; i++) + c.s[i] = V_TypeTraits::reinterpret_from_int((itype)-(int)(a.s[i] == a.s[i])); + return c; +} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_ARITHM_OP(func, bin_op, cast_op, _Tp2) \ +template \ +inline v_reg<_Tp2, n> func(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + typedef _Tp2 rtype; \ + v_reg c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = cast_op(a.s[i] bin_op b.s[i]); \ + return c; \ +} + +/** @brief Add values without saturation + +For 8- and 16-bit integer values. */ +OPENCV_HAL_IMPL_ARITHM_OP(v_add_wrap, +, (_Tp), _Tp) + +/** @brief Subtract values without saturation + +For 8- and 16-bit integer values. */ +OPENCV_HAL_IMPL_ARITHM_OP(v_sub_wrap, -, (_Tp), _Tp) + +/** @brief Multiply values without saturation + +For 8- and 16-bit integer values. */ +OPENCV_HAL_IMPL_ARITHM_OP(v_mul_wrap, *, (_Tp), _Tp) + +//! @cond IGNORED +template inline T _absdiff(T a, T b) +{ + return a > b ? a - b : b - a; +} +//! @endcond + +/** @brief Absolute difference + +Returns \f$ |a - b| \f$ converted to corresponding unsigned type. +Example: +@code{.cpp} +v_int32x4 a, b; // {1, 2, 3, 4} and {4, 3, 2, 1} +v_uint32x4 c = v_absdiff(a, b); // result is {3, 1, 1, 3} +@endcode +For 8-, 16-, 32-bit integer source types. */ +template +inline v_reg::abs_type, n> v_absdiff(const v_reg<_Tp, n>& a, const v_reg<_Tp, n> & b) +{ + typedef typename V_TypeTraits<_Tp>::abs_type rtype; + v_reg c; + const rtype mask = (rtype)(std::numeric_limits<_Tp>::is_signed ? (1 << (sizeof(rtype)*8 - 1)) : 0); + for( int i = 0; i < n; i++ ) + { + rtype ua = a.s[i] ^ mask; + rtype ub = b.s[i] ^ mask; + c.s[i] = _absdiff(ua, ub); + } + return c; +} + +/** @overload + +For 32-bit floating point values */ +inline v_float32x4 v_absdiff(const v_float32x4& a, const v_float32x4& b) +{ + v_float32x4 c; + for( int i = 0; i < c.nlanes; i++ ) + c.s[i] = _absdiff(a.s[i], b.s[i]); + return c; +} + +/** @overload + +For 64-bit floating point values */ +inline v_float64x2 v_absdiff(const v_float64x2& a, const v_float64x2& b) +{ + v_float64x2 c; + for( int i = 0; i < c.nlanes; i++ ) + c.s[i] = _absdiff(a.s[i], b.s[i]); + return c; +} + +/** @brief Saturating absolute difference + +Returns \f$ saturate(|a - b|) \f$ . +For 8-, 16-bit signed integer source types. */ +template +inline v_reg<_Tp, n> v_absdiffs(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++) + c.s[i] = saturate_cast<_Tp>(std::abs(a.s[i] - b.s[i])); + return c; +} + +/** @brief Inversed square root + +Returns \f$ 1/sqrt(a) \f$ +For floating point types only. */ +template +inline v_reg<_Tp, n> v_invsqrt(const v_reg<_Tp, n>& a) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = 1.f/std::sqrt(a.s[i]); + return c; +} + +/** @brief Magnitude + +Returns \f$ sqrt(a^2 + b^2) \f$ +For floating point types only. */ +template +inline v_reg<_Tp, n> v_magnitude(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = std::sqrt(a.s[i]*a.s[i] + b.s[i]*b.s[i]); + return c; +} + +/** @brief Square of the magnitude + +Returns \f$ a^2 + b^2 \f$ +For floating point types only. */ +template +inline v_reg<_Tp, n> v_sqr_magnitude(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = a.s[i]*a.s[i] + b.s[i]*b.s[i]; + return c; +} + +/** @brief Multiply and add + + Returns \f$ a*b + c \f$ + For floating point types and signed 32bit int only. */ +template +inline v_reg<_Tp, n> v_fma(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg<_Tp, n>& c) +{ + v_reg<_Tp, n> d; + for( int i = 0; i < n; i++ ) + d.s[i] = a.s[i]*b.s[i] + c.s[i]; + return d; +} + +/** @brief A synonym for v_fma */ +template +inline v_reg<_Tp, n> v_muladd(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg<_Tp, n>& c) +{ + return v_fma(a, b, c); +} + +/** @brief Dot product of elements + +Multiply values in two registers and sum adjacent result pairs. +Scheme: +@code + {A1 A2 ...} // 16-bit +x {B1 B2 ...} // 16-bit +------------- +{A1B1+A2B2 ...} // 32-bit +@endcode +Implemented only for 16-bit signed source type (v_int16x8). +*/ +template inline v_reg::w_type, n/2> + v_dotprod(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg c; + for( int i = 0; i < (n/2); i++ ) + c.s[i] = (w_type)a.s[i*2]*b.s[i*2] + (w_type)a.s[i*2+1]*b.s[i*2+1]; + return c; +} + +/** @brief Dot product of elements + +Same as cv::v_dotprod, but add a third element to the sum of adjacent pairs. +Scheme: +@code + {A1 A2 ...} // 16-bit +x {B1 B2 ...} // 16-bit +------------- + {A1B1+A2B2+C1 ...} // 32-bit + +@endcode +Implemented only for 16-bit signed source type (v_int16x8). +*/ +template inline v_reg::w_type, n/2> + v_dotprod(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, const v_reg::w_type, n / 2>& c) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg s; + for( int i = 0; i < (n/2); i++ ) + s.s[i] = (w_type)a.s[i*2]*b.s[i*2] + (w_type)a.s[i*2+1]*b.s[i*2+1] + c.s[i]; + return s; +} + +/** @brief Multiply and expand + +Multiply values two registers and store results in two registers with wider pack type. +Scheme: +@code + {A B C D} // 32-bit +x {E F G H} // 32-bit +--------------- +{AE BF} // 64-bit + {CG DH} // 64-bit +@endcode +Example: +@code{.cpp} +v_uint32x4 a, b; // {1,2,3,4} and {2,2,2,2} +v_uint64x2 c, d; // results +v_mul_expand(a, b, c, d); // c, d = {2,4}, {6, 8} +@endcode +Implemented only for 16- and unsigned 32-bit source types (v_int16x8, v_uint16x8, v_uint32x4). +*/ +template inline void v_mul_expand(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + v_reg::w_type, n/2>& c, + v_reg::w_type, n/2>& d) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = (w_type)a.s[i]*b.s[i]; + d.s[i] = (w_type)a.s[i+(n/2)]*b.s[i+(n/2)]; + } +} + +/** @brief Multiply and extract high part + +Multiply values two registers and store high part of the results. +Implemented only for 16-bit source types (v_int16x8, v_uint16x8). Returns \f$ a*b >> 16 \f$ +*/ +template inline v_reg<_Tp, n> v_mul_hi(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg<_Tp, n> c; + for (int i = 0; i < n; i++) + c.s[i] = (_Tp)(((w_type)a.s[i] * b.s[i]) >> sizeof(_Tp)*8); + return c; +} + +//! @cond IGNORED +template inline void v_hsum(const v_reg<_Tp, n>& a, + v_reg::w_type, n/2>& c) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = (w_type)a.s[i*2] + a.s[i*2+1]; + } +} +//! @endcond + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_SHIFT_OP(shift_op) \ +template inline v_reg<_Tp, n> operator shift_op(const v_reg<_Tp, n>& a, int imm) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = (_Tp)(a.s[i] shift_op imm); \ + return c; \ +} + +/** @brief Bitwise shift left + +For 16-, 32- and 64-bit integer values. */ +OPENCV_HAL_IMPL_SHIFT_OP(<< ) + +/** @brief Bitwise shift right + +For 16-, 32- and 64-bit integer values. */ +OPENCV_HAL_IMPL_SHIFT_OP(>> ) + +/** @brief Element shift left among vector + +For all type */ +#define OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(suffix,opA,opB) \ +template inline v_reg<_Tp, n> v_rotate_##suffix(const v_reg<_Tp, n>& a) \ +{ \ + v_reg<_Tp, n> b; \ + for (int i = 0; i < n; i++) \ + { \ + int sIndex = i opA imm; \ + if (0 <= sIndex && sIndex < n) \ + { \ + b.s[i] = a.s[sIndex]; \ + } \ + else \ + { \ + b.s[i] = 0; \ + } \ + } \ + return b; \ +} \ +template inline v_reg<_Tp, n> v_rotate_##suffix(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + for (int i = 0; i < n; i++) \ + { \ + int aIndex = i opA imm; \ + int bIndex = i opA imm opB n; \ + if (0 <= bIndex && bIndex < n) \ + { \ + c.s[i] = b.s[bIndex]; \ + } \ + else if (0 <= aIndex && aIndex < n) \ + { \ + c.s[i] = a.s[aIndex]; \ + } \ + else \ + { \ + c.s[i] = 0; \ + } \ + } \ + return c; \ +} + +OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(left, -, +) +OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(right, +, -) + +/** @brief Sum packed values + +Scheme: +@code +{A1 A2 A3 ...} => sum{A1,A2,A3,...} +@endcode +For 32-bit integer and 32-bit floating point types.*/ +template inline typename V_TypeTraits<_Tp>::sum_type v_reduce_sum(const v_reg<_Tp, n>& a) +{ + typename V_TypeTraits<_Tp>::sum_type c = a.s[0]; + for( int i = 1; i < n; i++ ) + c += a.s[i]; + return c; +} + +/** @brief Sums all elements of each input vector, returns the vector of sums + + Scheme: + @code + result[0] = a[0] + a[1] + a[2] + a[3] + result[1] = b[0] + b[1] + b[2] + b[3] + result[2] = c[0] + c[1] + c[2] + c[3] + result[3] = d[0] + d[1] + d[2] + d[3] + @endcode +*/ +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + v_float32x4 r; + r.s[0] = a.s[0] + a.s[1] + a.s[2] + a.s[3]; + r.s[1] = b.s[0] + b.s[1] + b.s[2] + b.s[3]; + r.s[2] = c.s[0] + c.s[1] + c.s[2] + c.s[3]; + r.s[3] = d.s[0] + d.s[1] + d.s[2] + d.s[3]; + return r; +} + +/** @brief Sum absolute differences of values + +Scheme: +@code +{A1 A2 A3 ...} {B1 B2 B3 ...} => sum{ABS(A1-B1),abs(A2-B2),abs(A3-B3),...} +@endcode +For all types except 64-bit types.*/ +template inline typename V_TypeTraits< typename V_TypeTraits<_Tp>::abs_type >::sum_type v_reduce_sad(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typename V_TypeTraits< typename V_TypeTraits<_Tp>::abs_type >::sum_type c = _absdiff(a.s[0], b.s[0]); + for (int i = 1; i < n; i++) + c += _absdiff(a.s[i], b.s[i]); + return c; +} + +/** @brief Get negative values mask + +Returned value is a bit mask with bits set to 1 on places corresponding to negative packed values indexes. +Example: +@code{.cpp} +v_int32x4 r; // set to {-1, -1, 1, 1} +int mask = v_signmask(r); // mask = 3 <== 00000000 00000000 00000000 00000011 +@endcode +For all types except 64-bit. */ +template inline int v_signmask(const v_reg<_Tp, n>& a) +{ + int mask = 0; + for( int i = 0; i < n; i++ ) + mask |= (V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) < 0) << i; + return mask; +} + +/** @brief Check if all packed values are less than zero + +Unsigned values will be casted to signed: `uchar 254 => char -2`. +For all types except 64-bit. */ +template inline bool v_check_all(const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < n; i++ ) + if( V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) >= 0 ) + return false; + return true; +} + +/** @brief Check if any of packed values is less than zero + +Unsigned values will be casted to signed: `uchar 254 => char -2`. +For all types except 64-bit. */ +template inline bool v_check_any(const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < n; i++ ) + if( V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) < 0 ) + return true; + return false; +} + +/** @brief Per-element select (blend operation) + +Return value will be built by combining values _a_ and _b_ using the following scheme: + result[i] = mask[i] ? a[i] : b[i]; + +@note: _mask_ element values are restricted to these values: +- 0: select element from _b_ +- 0xff/0xffff/etc: select element from _a_ +(fully compatible with bitwise-based operator) +*/ +template inline v_reg<_Tp, n> v_select(const v_reg<_Tp, n>& mask, + const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef V_TypeTraits<_Tp> Traits; + typedef typename Traits::int_type int_type; + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + { + int_type m = Traits::reinterpret_int(mask.s[i]); + CV_DbgAssert(m == 0 || m == (~(int_type)0)); // restrict mask values: 0 or 0xff/0xffff/etc + c.s[i] = m ? a.s[i] : b.s[i]; + } + return c; +} + +/** @brief Expand values to the wider pack type + +Copy contents of register to two registers with 2x wider pack type. +Scheme: +@code + int32x4 int64x2 int64x2 +{A B C D} ==> {A B} , {C D} +@endcode */ +template inline void v_expand(const v_reg<_Tp, n>& a, + v_reg::w_type, n/2>& b0, + v_reg::w_type, n/2>& b1) +{ + for( int i = 0; i < (n/2); i++ ) + { + b0.s[i] = a.s[i]; + b1.s[i] = a.s[i+(n/2)]; + } +} + +/** @brief Expand lower values to the wider pack type + +Same as cv::v_expand, but return lower half of the vector. + +Scheme: +@code + int32x4 int64x2 +{A B C D} ==> {A B} +@endcode */ +template +inline v_reg::w_type, n/2> +v_expand_low(const v_reg<_Tp, n>& a) +{ + v_reg::w_type, n/2> b; + for( int i = 0; i < (n/2); i++ ) + b.s[i] = a.s[i]; + return b; +} + +/** @brief Expand higher values to the wider pack type + +Same as cv::v_expand_low, but expand higher half of the vector instead. + +Scheme: +@code + int32x4 int64x2 +{A B C D} ==> {C D} +@endcode */ +template +inline v_reg::w_type, n/2> +v_expand_high(const v_reg<_Tp, n>& a) +{ + v_reg::w_type, n/2> b; + for( int i = 0; i < (n/2); i++ ) + b.s[i] = a.s[i+(n/2)]; + return b; +} + +//! @cond IGNORED +template inline v_reg::int_type, n> + v_reinterpret_as_int(const v_reg<_Tp, n>& a) +{ + v_reg::int_type, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = V_TypeTraits<_Tp>::reinterpret_int(a.s[i]); + return c; +} + +template inline v_reg::uint_type, n> + v_reinterpret_as_uint(const v_reg<_Tp, n>& a) +{ + v_reg::uint_type, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = V_TypeTraits<_Tp>::reinterpret_uint(a.s[i]); + return c; +} +//! @endcond + +/** @brief Interleave two vectors + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +--------------- + {A1 B1 A2 B2} and {A3 B3 A4 B4} +@endcode +For all types except 64-bit. +*/ +template inline void v_zip( const v_reg<_Tp, n>& a0, const v_reg<_Tp, n>& a1, + v_reg<_Tp, n>& b0, v_reg<_Tp, n>& b1 ) +{ + int i; + for( i = 0; i < n/2; i++ ) + { + b0.s[i*2] = a0.s[i]; + b0.s[i*2+1] = a1.s[i]; + } + for( ; i < n; i++ ) + { + b1.s[i*2-n] = a0.s[i]; + b1.s[i*2-n+1] = a1.s[i]; + } +} + +/** @brief Load register contents from memory + +@param ptr pointer to memory block with data +@return register object + +@note Returned type will be detected from passed pointer type, for example uchar ==> cv::v_uint8x16, int ==> cv::v_int32x4, etc. + */ +template +inline v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128> v_load(const _Tp* ptr) +{ + return v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128>(ptr); +} + +/** @brief Load register contents from memory (aligned) + +similar to cv::v_load, but source memory block should be aligned (to 16-byte boundary) + */ +template +inline v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128> v_load_aligned(const _Tp* ptr) +{ + return v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128>(ptr); +} + +/** @brief Load 64-bits of data to lower part (high part is undefined). + +@param ptr memory block containing data for first half (0..n/2) + +@code{.cpp} +int lo[2] = { 1, 2 }; +v_int32x4 r = v_load_low(lo); +@endcode + */ +template +inline v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128> v_load_low(const _Tp* ptr) +{ + v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128> c; + for( int i = 0; i < c.nlanes/2; i++ ) + { + c.s[i] = ptr[i]; + } + return c; +} + +/** @brief Load register contents from two memory blocks + +@param loptr memory block containing data for first half (0..n/2) +@param hiptr memory block containing data for second half (n/2..n) + +@code{.cpp} +int lo[2] = { 1, 2 }, hi[2] = { 3, 4 }; +v_int32x4 r = v_load_halves(lo, hi); +@endcode + */ +template +inline v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128> v_load_halves(const _Tp* loptr, const _Tp* hiptr) +{ + v_reg<_Tp, V_TypeTraits<_Tp>::nlanes128> c; + for( int i = 0; i < c.nlanes/2; i++ ) + { + c.s[i] = loptr[i]; + c.s[i+c.nlanes/2] = hiptr[i]; + } + return c; +} + +/** @brief Load register contents from memory with double expand + +Same as cv::v_load, but result pack type will be 2x wider than memory type. + +@code{.cpp} +short buf[4] = {1, 2, 3, 4}; // type is int16 +v_int32x4 r = v_load_expand(buf); // r = {1, 2, 3, 4} - type is int32 +@endcode +For 8-, 16-, 32-bit integer source types. */ +template +inline v_reg::w_type, V_TypeTraits<_Tp>::nlanes128 / 2> +v_load_expand(const _Tp* ptr) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg::nlanes128> c; + for( int i = 0; i < c.nlanes; i++ ) + { + c.s[i] = ptr[i]; + } + return c; +} + +/** @brief Load register contents from memory with quad expand + +Same as cv::v_load_expand, but result type is 4 times wider than source. +@code{.cpp} +char buf[4] = {1, 2, 3, 4}; // type is int8 +v_int32x4 r = v_load_q(buf); // r = {1, 2, 3, 4} - type is int32 +@endcode +For 8-bit integer source types. */ +template +inline v_reg::q_type, V_TypeTraits<_Tp>::nlanes128 / 4> +v_load_expand_q(const _Tp* ptr) +{ + typedef typename V_TypeTraits<_Tp>::q_type q_type; + v_reg::nlanes128> c; + for( int i = 0; i < c.nlanes; i++ ) + { + c.s[i] = ptr[i]; + } + return c; +} + +/** @brief Load and deinterleave (2 channels) + +Load data from memory deinterleave and store to 2 registers. +Scheme: +@code +{A1 B1 A2 B2 ...} ==> {A1 A2 ...}, {B1 B2 ...} +@endcode +For all types except 64-bit. */ +template inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a, + v_reg<_Tp, n>& b) +{ + int i, i2; + for( i = i2 = 0; i < n; i++, i2 += 2 ) + { + a.s[i] = ptr[i2]; + b.s[i] = ptr[i2+1]; + } +} + +/** @brief Load and deinterleave (3 channels) + +Load data from memory deinterleave and store to 3 registers. +Scheme: +@code +{A1 B1 C1 A2 B2 C2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...} +@endcode +For all types except 64-bit. */ +template inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a, + v_reg<_Tp, n>& b, v_reg<_Tp, n>& c) +{ + int i, i3; + for( i = i3 = 0; i < n; i++, i3 += 3 ) + { + a.s[i] = ptr[i3]; + b.s[i] = ptr[i3+1]; + c.s[i] = ptr[i3+2]; + } +} + +/** @brief Load and deinterleave (4 channels) + +Load data from memory deinterleave and store to 4 registers. +Scheme: +@code +{A1 B1 C1 D1 A2 B2 C2 D2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}, {D1 D2 ...} +@endcode +For all types except 64-bit. */ +template +inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a, + v_reg<_Tp, n>& b, v_reg<_Tp, n>& c, + v_reg<_Tp, n>& d) +{ + int i, i4; + for( i = i4 = 0; i < n; i++, i4 += 4 ) + { + a.s[i] = ptr[i4]; + b.s[i] = ptr[i4+1]; + c.s[i] = ptr[i4+2]; + d.s[i] = ptr[i4+3]; + } +} + +/** @brief Interleave and store (2 channels) + +Interleave and store data from 2 registers to memory. +Scheme: +@code +{A1 A2 ...}, {B1 B2 ...} ==> {A1 B1 A2 B2 ...} +@endcode +For all types except 64-bit. */ +template +inline void v_store_interleave( _Tp* ptr, const v_reg<_Tp, n>& a, + const v_reg<_Tp, n>& b, + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) +{ + int i, i2; + for( i = i2 = 0; i < n; i++, i2 += 2 ) + { + ptr[i2] = a.s[i]; + ptr[i2+1] = b.s[i]; + } +} + +/** @brief Interleave and store (3 channels) + +Interleave and store data from 3 registers to memory. +Scheme: +@code +{A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...} ==> {A1 B1 C1 A2 B2 C2 ...} +@endcode +For all types except 64-bit. */ +template +inline void v_store_interleave( _Tp* ptr, const v_reg<_Tp, n>& a, + const v_reg<_Tp, n>& b, const v_reg<_Tp, n>& c, + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) +{ + int i, i3; + for( i = i3 = 0; i < n; i++, i3 += 3 ) + { + ptr[i3] = a.s[i]; + ptr[i3+1] = b.s[i]; + ptr[i3+2] = c.s[i]; + } +} + +/** @brief Interleave and store (4 channels) + +Interleave and store data from 4 registers to memory. +Scheme: +@code +{A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}, {D1 D2 ...} ==> {A1 B1 C1 D1 A2 B2 C2 D2 ...} +@endcode +For all types except 64-bit. */ +template inline void v_store_interleave( _Tp* ptr, const v_reg<_Tp, n>& a, + const v_reg<_Tp, n>& b, const v_reg<_Tp, n>& c, + const v_reg<_Tp, n>& d, + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) +{ + int i, i4; + for( i = i4 = 0; i < n; i++, i4 += 4 ) + { + ptr[i4] = a.s[i]; + ptr[i4+1] = b.s[i]; + ptr[i4+2] = c.s[i]; + ptr[i4+3] = d.s[i]; + } +} + +/** @brief Store data to memory + +Store register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {A B C D} +@endcode +Pointer can be unaligned. */ +template +inline void v_store(_Tp* ptr, const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < n; i++ ) + ptr[i] = a.s[i]; +} + +/** @brief Store data to memory (lower half) + +Store lower half of register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {A B} +@endcode */ +template +inline void v_store_low(_Tp* ptr, const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < (n/2); i++ ) + ptr[i] = a.s[i]; +} + +/** @brief Store data to memory (higher half) + +Store higher half of register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {C D} +@endcode */ +template +inline void v_store_high(_Tp* ptr, const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < (n/2); i++ ) + ptr[i] = a.s[i+(n/2)]; +} + +/** @brief Store data to memory (aligned) + +Store register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {A B C D} +@endcode +Pointer __should__ be aligned by 16-byte boundary. */ +template +inline void v_store_aligned(_Tp* ptr, const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < n; i++ ) + ptr[i] = a.s[i]; +} + +template +inline void v_store_aligned_nocache(_Tp* ptr, const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < n; i++ ) + ptr[i] = a.s[i]; +} + +template +inline void v_store_aligned(_Tp* ptr, const v_reg<_Tp, n>& a, hal::StoreMode /*mode*/) +{ + for( int i = 0; i < n; i++ ) + ptr[i] = a.s[i]; +} + +/** @brief Combine vector from first elements of two vectors + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +--------------- + {A1 A2 B1 B2} +@endcode +For all types except 64-bit. */ +template +inline v_reg<_Tp, n> v_combine_low(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = a.s[i]; + c.s[i+(n/2)] = b.s[i]; + } + return c; +} + +/** @brief Combine vector from last elements of two vectors + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +--------------- + {A3 A4 B3 B4} +@endcode +For all types except 64-bit. */ +template +inline v_reg<_Tp, n> v_combine_high(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = a.s[i+(n/2)]; + c.s[i+(n/2)] = b.s[i+(n/2)]; + } + return c; +} + +/** @brief Combine two vectors from lower and higher parts of two other vectors + +@code{.cpp} +low = cv::v_combine_low(a, b); +high = cv::v_combine_high(a, b); +@endcode */ +template +inline void v_recombine(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + v_reg<_Tp, n>& low, v_reg<_Tp, n>& high) +{ + for( int i = 0; i < (n/2); i++ ) + { + low.s[i] = a.s[i]; + low.s[i+(n/2)] = b.s[i]; + high.s[i] = a.s[i+(n/2)]; + high.s[i+(n/2)] = b.s[i+(n/2)]; + } +} + +/** @brief Vector extract + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +======================== +shift = 1 {A2 A3 A4 B1} +shift = 2 {A3 A4 B1 B2} +shift = 3 {A4 B1 B2 B3} +@endcode +Restriction: 0 <= shift < nlanes + +Usage: +@code +v_int32x4 a, b, c; +c = v_extract<2>(a, b); +@endcode +For all types. */ +template +inline v_reg<_Tp, n> v_extract(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> r; + const int shift = n - s; + int i = 0; + for (; i < shift; ++i) + r.s[i] = a.s[i+s]; + for (; i < n; ++i) + r.s[i] = b.s[i-shift]; + return r; +} + +/** @brief Round + +Rounds each value. Input type is float vector ==> output type is int vector.*/ +template inline v_reg v_round(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = cvRound(a.s[i]); + return c; +} + +/** @overload */ +template inline v_reg v_round(const v_reg& a, const v_reg& b) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvRound(a.s[i]); + c.s[i+n] = cvRound(b.s[i]); + } + return c; +} + +/** @brief Floor + +Floor each value. Input type is float vector ==> output type is int vector.*/ +template inline v_reg v_floor(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = cvFloor(a.s[i]); + return c; +} + +/** @brief Ceil + +Ceil each value. Input type is float vector ==> output type is int vector.*/ +template inline v_reg v_ceil(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = cvCeil(a.s[i]); + return c; +} + +/** @brief Trunc + +Truncate each value. Input type is float vector ==> output type is int vector.*/ +template inline v_reg v_trunc(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = (int)(a.s[i]); + return c; +} + +/** @overload */ +template inline v_reg v_round(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvRound(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @overload */ +template inline v_reg v_floor(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvFloor(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @overload */ +template inline v_reg v_ceil(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvCeil(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @overload */ +template inline v_reg v_trunc(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvCeil(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @brief Convert to float + +Supported input type is cv::v_int32x4. */ +template inline v_reg v_cvt_f32(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = (float)a.s[i]; + return c; +} + +template inline v_reg v_cvt_f32(const v_reg& a, const v_reg& b) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = (float)a.s[i]; + c.s[i+n] = (float)b.s[i]; + } + return c; +} + +/** @brief Convert to double + +Supported input type is cv::v_int32x4. */ +template inline v_reg v_cvt_f64(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = (double)a.s[i]; + return c; +} + +/** @brief Convert to double + +Supported input type is cv::v_float32x4. */ +template inline v_reg v_cvt_f64(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = (double)a.s[i]; + return c; +} + +template inline v_reg v_lut(const int* tab, const v_reg& idx) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = tab[idx.s[i]]; + return c; +} + +template inline v_reg v_lut(const float* tab, const v_reg& idx) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = tab[idx.s[i]]; + return c; +} + +template inline v_reg v_lut(const double* tab, const v_reg& idx) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = tab[idx.s[i]]; + return c; +} + +template inline void v_lut_deinterleave(const float* tab, const v_reg& idx, + v_reg& x, v_reg& y) +{ + for( int i = 0; i < n; i++ ) + { + int j = idx.s[i]; + x.s[i] = tab[j]; + y.s[i] = tab[j+1]; + } +} + +template inline void v_lut_deinterleave(const double* tab, const v_reg& idx, + v_reg& x, v_reg& y) +{ + for( int i = 0; i < n; i++ ) + { + int j = idx.s[i]; + x.s[i] = tab[j]; + y.s[i] = tab[j+1]; + } +} + +/** @brief Transpose 4x4 matrix + +Scheme: +@code +a0 {A1 A2 A3 A4} +a1 {B1 B2 B3 B4} +a2 {C1 C2 C3 C4} +a3 {D1 D2 D3 D4} +=============== +b0 {A1 B1 C1 D1} +b1 {A2 B2 C2 D2} +b2 {A3 B3 C3 D3} +b3 {A4 B4 C4 D4} +@endcode +*/ +template +inline void v_transpose4x4( v_reg<_Tp, 4>& a0, const v_reg<_Tp, 4>& a1, + const v_reg<_Tp, 4>& a2, const v_reg<_Tp, 4>& a3, + v_reg<_Tp, 4>& b0, v_reg<_Tp, 4>& b1, + v_reg<_Tp, 4>& b2, v_reg<_Tp, 4>& b3 ) +{ + b0 = v_reg<_Tp, 4>(a0.s[0], a1.s[0], a2.s[0], a3.s[0]); + b1 = v_reg<_Tp, 4>(a0.s[1], a1.s[1], a2.s[1], a3.s[1]); + b2 = v_reg<_Tp, 4>(a0.s[2], a1.s[2], a2.s[2], a3.s[2]); + b3 = v_reg<_Tp, 4>(a0.s[3], a1.s[3], a2.s[3], a3.s[3]); +} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_INIT_ZERO(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_setzero_##suffix() { return _Tpvec::zero(); } + +//! @name Init with zero +//! @{ +//! @brief Create new vector with zero elements +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int16x8, short, s16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int32x4, int, s32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float32x4, float, f32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float64x2, double, f64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int64x2, int64, s64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_INIT_VAL(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_setall_##suffix(_Tp val) { return _Tpvec::all(val); } + +//! @name Init with value +//! @{ +//! @brief Create new vector with elements set to a specific value +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int16x8, short, s16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int32x4, int, s32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float32x4, float, f32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float64x2, double, f64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int64x2, int64, s64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_REINTERPRET(_Tpvec, _Tp, suffix) \ +template inline _Tpvec \ + v_reinterpret_as_##suffix(const v_reg<_Tp0, n0>& a) \ +{ return a.template reinterpret_as<_Tp, _Tpvec::nlanes>(); } + +//! @name Reinterpret +//! @{ +//! @brief Convert vector to different type without modifying underlying data. +OPENCV_HAL_IMPL_C_REINTERPRET(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_C_REINTERPRET(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_C_REINTERPRET(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_C_REINTERPRET(v_int16x8, short, s16) +OPENCV_HAL_IMPL_C_REINTERPRET(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_C_REINTERPRET(v_int32x4, int, s32) +OPENCV_HAL_IMPL_C_REINTERPRET(v_float32x4, float, f32) +OPENCV_HAL_IMPL_C_REINTERPRET(v_float64x2, double, f64) +OPENCV_HAL_IMPL_C_REINTERPRET(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_C_REINTERPRET(v_int64x2, int64, s64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_SHIFTL(_Tpvec, _Tp) \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ return a << n; } + +//! @name Left shift +//! @{ +//! @brief Shift left +OPENCV_HAL_IMPL_C_SHIFTL(v_uint16x8, ushort) +OPENCV_HAL_IMPL_C_SHIFTL(v_int16x8, short) +OPENCV_HAL_IMPL_C_SHIFTL(v_uint32x4, unsigned) +OPENCV_HAL_IMPL_C_SHIFTL(v_int32x4, int) +OPENCV_HAL_IMPL_C_SHIFTL(v_uint64x2, uint64) +OPENCV_HAL_IMPL_C_SHIFTL(v_int64x2, int64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_SHIFTR(_Tpvec, _Tp) \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ return a >> n; } + +//! @name Right shift +//! @{ +//! @brief Shift right +OPENCV_HAL_IMPL_C_SHIFTR(v_uint16x8, ushort) +OPENCV_HAL_IMPL_C_SHIFTR(v_int16x8, short) +OPENCV_HAL_IMPL_C_SHIFTR(v_uint32x4, unsigned) +OPENCV_HAL_IMPL_C_SHIFTR(v_int32x4, int) +OPENCV_HAL_IMPL_C_SHIFTR(v_uint64x2, uint64) +OPENCV_HAL_IMPL_C_SHIFTR(v_int64x2, int64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_RSHIFTR(_Tpvec, _Tp) \ +template inline _Tpvec v_rshr(const _Tpvec& a) \ +{ \ + _Tpvec c; \ + for( int i = 0; i < _Tpvec::nlanes; i++ ) \ + c.s[i] = (_Tp)((a.s[i] + ((_Tp)1 << (n - 1))) >> n); \ + return c; \ +} + +//! @name Rounding shift +//! @{ +//! @brief Rounding shift right +OPENCV_HAL_IMPL_C_RSHIFTR(v_uint16x8, ushort) +OPENCV_HAL_IMPL_C_RSHIFTR(v_int16x8, short) +OPENCV_HAL_IMPL_C_RSHIFTR(v_uint32x4, unsigned) +OPENCV_HAL_IMPL_C_RSHIFTR(v_int32x4, int) +OPENCV_HAL_IMPL_C_RSHIFTR(v_uint64x2, uint64) +OPENCV_HAL_IMPL_C_RSHIFTR(v_int64x2, int64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_PACK(_Tpvec, _Tpnvec, _Tpn, pack_suffix, cast) \ +inline _Tpnvec v_##pack_suffix(const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpnvec c; \ + for( int i = 0; i < _Tpvec::nlanes; i++ ) \ + { \ + c.s[i] = cast<_Tpn>(a.s[i]); \ + c.s[i+_Tpvec::nlanes] = cast<_Tpn>(b.s[i]); \ + } \ + return c; \ +} + +//! @name Pack +//! @{ +//! @brief Pack values from two vectors to one +//! +//! Return vector type have twice more elements than input vector types. Variant with _u_ suffix also +//! converts to corresponding unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_PACK(v_uint16x8, v_uint8x16, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(v_int16x8, v_int8x16, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(v_uint32x4, v_uint16x8, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(v_int32x4, v_int16x8, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(v_uint64x2, v_uint32x4, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK(v_int64x2, v_int32x4, int, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK(v_int16x8, v_uint8x16, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(v_int32x4, v_uint16x8, ushort, pack_u, saturate_cast) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_RSHR_PACK(_Tpvec, _Tp, _Tpnvec, _Tpn, pack_suffix, cast) \ +template inline _Tpnvec v_rshr_##pack_suffix(const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpnvec c; \ + for( int i = 0; i < _Tpvec::nlanes; i++ ) \ + { \ + c.s[i] = cast<_Tpn>((a.s[i] + ((_Tp)1 << (n - 1))) >> n); \ + c.s[i+_Tpvec::nlanes] = cast<_Tpn>((b.s[i] + ((_Tp)1 << (n - 1))) >> n); \ + } \ + return c; \ +} + +//! @name Pack with rounding shift +//! @{ +//! @brief Pack values from two vectors to one with rounding shift +//! +//! Values from the input vectors will be shifted right by _n_ bits with rounding, converted to narrower +//! type and returned in the result vector. Variant with _u_ suffix converts to unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_RSHR_PACK(v_uint16x8, ushort, v_uint8x16, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(v_int16x8, short, v_int8x16, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(v_uint32x4, unsigned, v_uint16x8, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(v_int32x4, int, v_int16x8, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(v_uint64x2, uint64, v_uint32x4, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(v_int64x2, int64, v_int32x4, int, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(v_int16x8, short, v_uint8x16, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(v_int32x4, int, v_uint16x8, ushort, pack_u, saturate_cast) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_PACK_STORE(_Tpvec, _Tp, _Tpnvec, _Tpn, pack_suffix, cast) \ +inline void v_##pack_suffix##_store(_Tpn* ptr, const _Tpvec& a) \ +{ \ + for( int i = 0; i < _Tpvec::nlanes; i++ ) \ + ptr[i] = cast<_Tpn>(a.s[i]); \ +} + +//! @name Pack and store +//! @{ +//! @brief Store values from the input vector into memory with pack +//! +//! Values will be stored into memory with conversion to narrower type. +//! Variant with _u_ suffix converts to corresponding unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_PACK_STORE(v_uint16x8, ushort, v_uint8x16, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(v_int16x8, short, v_int8x16, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(v_uint32x4, unsigned, v_uint16x8, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(v_int32x4, int, v_int16x8, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(v_uint64x2, uint64, v_uint32x4, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(v_int64x2, int64, v_int32x4, int, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(v_int16x8, short, v_uint8x16, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(v_int32x4, int, v_uint16x8, ushort, pack_u, saturate_cast) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(_Tpvec, _Tp, _Tpnvec, _Tpn, pack_suffix, cast) \ +template inline void v_rshr_##pack_suffix##_store(_Tpn* ptr, const _Tpvec& a) \ +{ \ + for( int i = 0; i < _Tpvec::nlanes; i++ ) \ + ptr[i] = cast<_Tpn>((a.s[i] + ((_Tp)1 << (n - 1))) >> n); \ +} + +//! @name Pack and store with rounding shift +//! @{ +//! @brief Store values from the input vector into memory with pack +//! +//! Values will be shifted _n_ bits right with rounding, converted to narrower type and stored into +//! memory. Variant with _u_ suffix converts to unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_uint16x8, ushort, v_uint8x16, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_int16x8, short, v_int8x16, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_uint32x4, unsigned, v_uint16x8, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_int32x4, int, v_int16x8, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_uint64x2, uint64, v_uint32x4, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_int64x2, int64, v_int32x4, int, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_int16x8, short, v_uint8x16, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(v_int32x4, int, v_uint16x8, ushort, pack_u, saturate_cast) +//! @} + +//! @cond IGNORED +template +inline void _pack_b(_Tpm* mptr, const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + for (int i = 0; i < n; ++i) + { + mptr[i] = (_Tpm)a.s[i]; + mptr[i + n] = (_Tpm)b.s[i]; + } +} +//! @endcond + +//! @name Pack boolean values +//! @{ +//! @brief Pack boolean values from multiple vectors to one unsigned 8-bit integer vector +//! +//! @note Must provide valid boolean values to guarantee same result for all architectures. + +/** @brief +//! For 16-bit boolean values + +Scheme: +@code +a {0xFFFF 0 0 0xFFFF 0 0xFFFF 0xFFFF 0} +b {0xFFFF 0 0xFFFF 0 0 0xFFFF 0 0xFFFF} +=============== +{ + 0xFF 0 0 0xFF 0 0xFF 0xFF 0 + 0xFF 0 0xFF 0 0 0xFF 0 0xFF +} +@endcode */ + +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + v_uint8x16 mask; + _pack_b(mask.s, a, b); + return mask; +} + +/** @overload +For 32-bit boolean values + +Scheme: +@code +a {0xFFFF.. 0 0 0xFFFF..} +b {0 0xFFFF.. 0xFFFF.. 0} +c {0xFFFF.. 0 0xFFFF.. 0} +d {0 0xFFFF.. 0 0xFFFF..} +=============== +{ + 0xFF 0 0 0xFF 0 0xFF 0xFF 0 + 0xFF 0 0xFF 0 0 0xFF 0 0xFF +} +@endcode */ + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + v_uint8x16 mask; + _pack_b(mask.s, a, b); + _pack_b(mask.s + 8, c, d); + return mask; +} + +/** @overload +For 64-bit boolean values + +Scheme: +@code +a {0xFFFF.. 0} +b {0 0xFFFF..} +c {0xFFFF.. 0} +d {0 0xFFFF..} + +e {0xFFFF.. 0} +f {0xFFFF.. 0} +g {0 0xFFFF..} +h {0 0xFFFF..} +=============== +{ + 0xFF 0 0 0xFF 0xFF 0 0 0xFF + 0xFF 0 0xFF 0 0 0xFF 0 0xFF +} +@endcode */ +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + v_uint8x16 mask; + _pack_b(mask.s, a, b); + _pack_b(mask.s + 4, c, d); + _pack_b(mask.s + 8, e, f); + _pack_b(mask.s + 12, g, h); + return mask; +} +//! @} + +/** @brief Matrix multiplication + +Scheme: +@code +{A0 A1 A2 A3} |V0| +{B0 B1 B2 B3} |V1| +{C0 C1 C2 C3} |V2| +{D0 D1 D2 D3} x |V3| +==================== +{R0 R1 R2 R3}, where: +R0 = A0V0 + A1V1 + A2V2 + A3V3, +R1 = B0V0 + B1V1 + B2V2 + B3V3 +... +@endcode +*/ +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + return v_float32x4(v.s[0]*m0.s[0] + v.s[1]*m1.s[0] + v.s[2]*m2.s[0] + v.s[3]*m3.s[0], + v.s[0]*m0.s[1] + v.s[1]*m1.s[1] + v.s[2]*m2.s[1] + v.s[3]*m3.s[1], + v.s[0]*m0.s[2] + v.s[1]*m1.s[2] + v.s[2]*m2.s[2] + v.s[3]*m3.s[2], + v.s[0]*m0.s[3] + v.s[1]*m1.s[3] + v.s[2]*m2.s[3] + v.s[3]*m3.s[3]); +} + +/** @brief Matrix multiplication and add + +Scheme: +@code +{A0 A1 A2 } |V0| |D0| +{B0 B1 B2 } |V1| |D1| +{C0 C1 C2 } x |V2| + |D2| +==================== +{R0 R1 R2 R3}, where: +R0 = A0V0 + A1V1 + A2V2 + D0, +R1 = B0V0 + B1V1 + B2V2 + D1 +... +@endcode +*/ +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + return v_float32x4(v.s[0]*m0.s[0] + v.s[1]*m1.s[0] + v.s[2]*m2.s[0] + m3.s[0], + v.s[0]*m0.s[1] + v.s[1]*m1.s[1] + v.s[2]*m2.s[1] + m3.s[1], + v.s[0]*m0.s[2] + v.s[1]*m1.s[2] + v.s[2]*m2.s[2] + m3.s[2], + v.s[0]*m0.s[3] + v.s[1]*m1.s[3] + v.s[2]*m2.s[3] + m3.s[3]); +} + +////// FP16 suport /////// + +inline v_reg::nlanes128> +v_load_expand(const float16_t* ptr) +{ + v_reg::nlanes128> v; + for( int i = 0; i < v.nlanes; i++ ) + { + v.s[i] = ptr[i]; + } + return v; +} + +inline void +v_pack_store(float16_t* ptr, v_reg::nlanes128>& v) +{ + for( int i = 0; i < v.nlanes; i++ ) + { + ptr[i] = float16_t(v.s[i]); + } +} + +inline void v_cleanup() {} + +//! @} + +//! @name Check SIMD support +//! @{ +//! @brief Check CPU capability of SIMD operation +static inline bool hasSIMD128() +{ + return false; +} + +//! @} + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +#endif +} + +#endif diff --git a/include/opencv2/core/hal/intrin_forward.hpp b/include/opencv2/core/hal/intrin_forward.hpp new file mode 100644 index 0000000..4618552 --- /dev/null +++ b/include/opencv2/core/hal/intrin_forward.hpp @@ -0,0 +1,158 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef CV__SIMD_FORWARD +#error "Need to pre-define forward width" +#endif + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +/** Types **/ +#if CV__SIMD_FORWARD == 512 +// [todo] 512 +#error "AVX512 Not implemented yet" +#elif CV__SIMD_FORWARD == 256 +// 256 +#define __CV_VX(fun) v256_##fun +#define __CV_V_UINT8 v_uint8x32 +#define __CV_V_INT8 v_int8x32 +#define __CV_V_UINT16 v_uint16x16 +#define __CV_V_INT16 v_int16x16 +#define __CV_V_UINT32 v_uint32x8 +#define __CV_V_INT32 v_int32x8 +#define __CV_V_UINT64 v_uint64x4 +#define __CV_V_INT64 v_int64x4 +#define __CV_V_FLOAT32 v_float32x8 +#define __CV_V_FLOAT64 v_float64x4 +struct v_uint8x32; +struct v_int8x32; +struct v_uint16x16; +struct v_int16x16; +struct v_uint32x8; +struct v_int32x8; +struct v_uint64x4; +struct v_int64x4; +struct v_float32x8; +struct v_float64x4; +#else +// 128 +#define __CV_VX(fun) v_##fun +#define __CV_V_UINT8 v_uint8x16 +#define __CV_V_INT8 v_int8x16 +#define __CV_V_UINT16 v_uint16x8 +#define __CV_V_INT16 v_int16x8 +#define __CV_V_UINT32 v_uint32x4 +#define __CV_V_INT32 v_int32x4 +#define __CV_V_UINT64 v_uint64x2 +#define __CV_V_INT64 v_int64x2 +#define __CV_V_FLOAT32 v_float32x4 +#define __CV_V_FLOAT64 v_float64x2 +struct v_uint8x16; +struct v_int8x16; +struct v_uint16x8; +struct v_int16x8; +struct v_uint32x4; +struct v_int32x4; +struct v_uint64x2; +struct v_int64x2; +struct v_float32x4; +struct v_float64x2; +#endif + +/** Value reordering **/ + +// Expansion +void v_expand(const __CV_V_UINT8&, __CV_V_UINT16&, __CV_V_UINT16&); +void v_expand(const __CV_V_INT8&, __CV_V_INT16&, __CV_V_INT16&); +void v_expand(const __CV_V_UINT16&, __CV_V_UINT32&, __CV_V_UINT32&); +void v_expand(const __CV_V_INT16&, __CV_V_INT32&, __CV_V_INT32&); +void v_expand(const __CV_V_UINT32&, __CV_V_UINT64&, __CV_V_UINT64&); +void v_expand(const __CV_V_INT32&, __CV_V_INT64&, __CV_V_INT64&); +// Low Expansion +__CV_V_UINT16 v_expand_low(const __CV_V_UINT8&); +__CV_V_INT16 v_expand_low(const __CV_V_INT8&); +__CV_V_UINT32 v_expand_low(const __CV_V_UINT16&); +__CV_V_INT32 v_expand_low(const __CV_V_INT16&); +__CV_V_UINT64 v_expand_low(const __CV_V_UINT32&); +__CV_V_INT64 v_expand_low(const __CV_V_INT32&); +// High Expansion +__CV_V_UINT16 v_expand_high(const __CV_V_UINT8&); +__CV_V_INT16 v_expand_high(const __CV_V_INT8&); +__CV_V_UINT32 v_expand_high(const __CV_V_UINT16&); +__CV_V_INT32 v_expand_high(const __CV_V_INT16&); +__CV_V_UINT64 v_expand_high(const __CV_V_UINT32&); +__CV_V_INT64 v_expand_high(const __CV_V_INT32&); +// Load & Low Expansion +__CV_V_UINT16 __CV_VX(load_expand)(const uchar*); +__CV_V_INT16 __CV_VX(load_expand)(const schar*); +__CV_V_UINT32 __CV_VX(load_expand)(const ushort*); +__CV_V_INT32 __CV_VX(load_expand)(const short*); +__CV_V_UINT64 __CV_VX(load_expand)(const uint*); +__CV_V_INT64 __CV_VX(load_expand)(const int*); +// Load lower 8-bit and expand into 32-bit +__CV_V_UINT32 __CV_VX(load_expand_q)(const uchar*); +__CV_V_INT32 __CV_VX(load_expand_q)(const schar*); + +// Saturating Pack +__CV_V_UINT8 v_pack(const __CV_V_UINT16&, const __CV_V_UINT16&); +__CV_V_INT8 v_pack(const __CV_V_INT16&, const __CV_V_INT16&); +__CV_V_UINT16 v_pack(const __CV_V_UINT32&, const __CV_V_UINT32&); +__CV_V_INT16 v_pack(const __CV_V_INT32&, const __CV_V_INT32&); +// Non-saturating Pack +__CV_V_UINT32 v_pack(const __CV_V_UINT64&, const __CV_V_UINT64&); +__CV_V_INT32 v_pack(const __CV_V_INT64&, const __CV_V_INT64&); +// Pack signed integers with unsigned saturation +__CV_V_UINT8 v_pack_u(const __CV_V_INT16&, const __CV_V_INT16&); +__CV_V_UINT16 v_pack_u(const __CV_V_INT32&, const __CV_V_INT32&); + +/** Arithmetic, bitwise and comparison operations **/ + +// Non-saturating multiply +#if CV_VSX +template +Tvec v_mul_wrap(const Tvec& a, const Tvec& b); +#else +__CV_V_UINT8 v_mul_wrap(const __CV_V_UINT8&, const __CV_V_UINT8&); +__CV_V_INT8 v_mul_wrap(const __CV_V_INT8&, const __CV_V_INT8&); +__CV_V_UINT16 v_mul_wrap(const __CV_V_UINT16&, const __CV_V_UINT16&); +__CV_V_INT16 v_mul_wrap(const __CV_V_INT16&, const __CV_V_INT16&); +#endif + +// Multiply and expand +#if CV_VSX +template +void v_mul_expand(const Tvec& a, const Tvec& b, Twvec& c, Twvec& d); +#else +void v_mul_expand(const __CV_V_UINT8&, const __CV_V_UINT8&, __CV_V_UINT16&, __CV_V_UINT16&); +void v_mul_expand(const __CV_V_INT8&, const __CV_V_INT8&, __CV_V_INT16&, __CV_V_INT16&); +void v_mul_expand(const __CV_V_UINT16&, const __CV_V_UINT16&, __CV_V_UINT32&, __CV_V_UINT32&); +void v_mul_expand(const __CV_V_INT16&, const __CV_V_INT16&, __CV_V_INT32&, __CV_V_INT32&); +void v_mul_expand(const __CV_V_UINT32&, const __CV_V_UINT32&, __CV_V_UINT64&, __CV_V_UINT64&); +void v_mul_expand(const __CV_V_INT32&, const __CV_V_INT32&, __CV_V_INT64&, __CV_V_INT64&); +#endif + +/** Cleanup **/ +#undef CV__SIMD_FORWARD +#undef __CV_VX +#undef __CV_V_UINT8 +#undef __CV_V_INT8 +#undef __CV_V_UINT16 +#undef __CV_V_INT16 +#undef __CV_V_UINT32 +#undef __CV_V_INT32 +#undef __CV_V_UINT64 +#undef __CV_V_INT64 +#undef __CV_V_FLOAT32 +#undef __CV_V_FLOAT64 + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} // cv:: \ No newline at end of file diff --git a/include/opencv2/core/hal/intrin_neon.hpp b/include/opencv2/core/hal/intrin_neon.hpp new file mode 100644 index 0000000..608dc97 --- /dev/null +++ b/include/opencv2/core/hal/intrin_neon.hpp @@ -0,0 +1,1697 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_HAL_INTRIN_NEON_HPP +#define OPENCV_HAL_INTRIN_NEON_HPP + +#include +#include "opencv2/core/utility.hpp" + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#define CV_SIMD128 1 +#if defined(__aarch64__) +#define CV_SIMD128_64F 1 +#else +#define CV_SIMD128_64F 0 +#endif + +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_NEON_REINTERPRET(_Tpv, suffix) \ +template static inline \ +_Tpv vreinterpretq_##suffix##_f64(T a) { return (_Tpv) a; } \ +template static inline \ +float64x2_t vreinterpretq_f64_##suffix(T a) { return (float64x2_t) a; } +OPENCV_HAL_IMPL_NEON_REINTERPRET(uint8x16_t, u8) +OPENCV_HAL_IMPL_NEON_REINTERPRET(int8x16_t, s8) +OPENCV_HAL_IMPL_NEON_REINTERPRET(uint16x8_t, u16) +OPENCV_HAL_IMPL_NEON_REINTERPRET(int16x8_t, s16) +OPENCV_HAL_IMPL_NEON_REINTERPRET(uint32x4_t, u32) +OPENCV_HAL_IMPL_NEON_REINTERPRET(int32x4_t, s32) +OPENCV_HAL_IMPL_NEON_REINTERPRET(uint64x2_t, u64) +OPENCV_HAL_IMPL_NEON_REINTERPRET(int64x2_t, s64) +OPENCV_HAL_IMPL_NEON_REINTERPRET(float32x4_t, f32) +#endif + +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + + v_uint8x16() {} + explicit v_uint8x16(uint8x16_t v) : val(v) {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + uchar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = vld1q_u8(v); + } + uchar get0() const + { + return vgetq_lane_u8(val, 0); + } + + uint8x16_t val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + + v_int8x16() {} + explicit v_int8x16(int8x16_t v) : val(v) {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + schar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = vld1q_s8(v); + } + schar get0() const + { + return vgetq_lane_s8(val, 0); + } + + int8x16_t val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + + v_uint16x8() {} + explicit v_uint16x8(uint16x8_t v) : val(v) {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + ushort v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = vld1q_u16(v); + } + ushort get0() const + { + return vgetq_lane_u16(val, 0); + } + + uint16x8_t val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + + v_int16x8() {} + explicit v_int16x8(int16x8_t v) : val(v) {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + short v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = vld1q_s16(v); + } + short get0() const + { + return vgetq_lane_s16(val, 0); + } + + int16x8_t val; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + enum { nlanes = 4 }; + + v_uint32x4() {} + explicit v_uint32x4(uint32x4_t v) : val(v) {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + unsigned v[] = {v0, v1, v2, v3}; + val = vld1q_u32(v); + } + unsigned get0() const + { + return vgetq_lane_u32(val, 0); + } + + uint32x4_t val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + + v_int32x4() {} + explicit v_int32x4(int32x4_t v) : val(v) {} + v_int32x4(int v0, int v1, int v2, int v3) + { + int v[] = {v0, v1, v2, v3}; + val = vld1q_s32(v); + } + int get0() const + { + return vgetq_lane_s32(val, 0); + } + int32x4_t val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + + v_float32x4() {} + explicit v_float32x4(float32x4_t v) : val(v) {} + v_float32x4(float v0, float v1, float v2, float v3) + { + float v[] = {v0, v1, v2, v3}; + val = vld1q_f32(v); + } + float get0() const + { + return vgetq_lane_f32(val, 0); + } + float32x4_t val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + + v_uint64x2() {} + explicit v_uint64x2(uint64x2_t v) : val(v) {} + v_uint64x2(uint64 v0, uint64 v1) + { + uint64 v[] = {v0, v1}; + val = vld1q_u64(v); + } + uint64 get0() const + { + return vgetq_lane_u64(val, 0); + } + uint64x2_t val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + + v_int64x2() {} + explicit v_int64x2(int64x2_t v) : val(v) {} + v_int64x2(int64 v0, int64 v1) + { + int64 v[] = {v0, v1}; + val = vld1q_s64(v); + } + int64 get0() const + { + return vgetq_lane_s64(val, 0); + } + int64x2_t val; +}; + +#if CV_SIMD128_64F +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + + v_float64x2() {} + explicit v_float64x2(float64x2_t v) : val(v) {} + v_float64x2(double v0, double v1) + { + double v[] = {v0, v1}; + val = vld1q_f64(v); + } + double get0() const + { + return vgetq_lane_f64(val, 0); + } + float64x2_t val; +}; +#endif + +#if CV_FP16 +// Workaround for old compilers +static inline int16x4_t vreinterpret_s16_f16(float16x4_t a) { return (int16x4_t)a; } +static inline float16x4_t vreinterpret_f16_s16(int16x4_t a) { return (float16x4_t)a; } + +static inline float16x4_t cv_vld1_f16(const void* ptr) +{ +#ifndef vld1_f16 // APPLE compiler defines vld1_f16 as macro + return vreinterpret_f16_s16(vld1_s16((const short*)ptr)); +#else + return vld1_f16((const __fp16*)ptr); +#endif +} +static inline void cv_vst1_f16(void* ptr, float16x4_t a) +{ +#ifndef vst1_f16 // APPLE compiler defines vst1_f16 as macro + vst1_s16((short*)ptr, vreinterpret_s16_f16(a)); +#else + vst1_f16((__fp16*)ptr, a); +#endif +} + +#ifndef vdup_n_f16 + #define vdup_n_f16(v) (float16x4_t){v, v, v, v} +#endif + +#endif // CV_FP16 + +#if CV_FP16 +inline v_float32x4 v128_load_fp16_f32(const short* ptr) +{ + float16x4_t a = cv_vld1_f16((const __fp16*)ptr); + return v_float32x4(vcvt_f32_f16(a)); +} + +inline void v_store_fp16(short* ptr, const v_float32x4& a) +{ + float16x4_t fp16 = vcvt_f16_f32(a.val); + cv_vst1_f16((short*)ptr, fp16); +} +#endif + +#define OPENCV_HAL_IMPL_NEON_INIT(_Tpv, _Tp, suffix) \ +inline v_##_Tpv v_setzero_##suffix() { return v_##_Tpv(vdupq_n_##suffix((_Tp)0)); } \ +inline v_##_Tpv v_setall_##suffix(_Tp v) { return v_##_Tpv(vdupq_n_##suffix(v)); } \ +inline _Tpv##_t vreinterpretq_##suffix##_##suffix(_Tpv##_t v) { return v; } \ +inline v_uint8x16 v_reinterpret_as_u8(const v_##_Tpv& v) { return v_uint8x16(vreinterpretq_u8_##suffix(v.val)); } \ +inline v_int8x16 v_reinterpret_as_s8(const v_##_Tpv& v) { return v_int8x16(vreinterpretq_s8_##suffix(v.val)); } \ +inline v_uint16x8 v_reinterpret_as_u16(const v_##_Tpv& v) { return v_uint16x8(vreinterpretq_u16_##suffix(v.val)); } \ +inline v_int16x8 v_reinterpret_as_s16(const v_##_Tpv& v) { return v_int16x8(vreinterpretq_s16_##suffix(v.val)); } \ +inline v_uint32x4 v_reinterpret_as_u32(const v_##_Tpv& v) { return v_uint32x4(vreinterpretq_u32_##suffix(v.val)); } \ +inline v_int32x4 v_reinterpret_as_s32(const v_##_Tpv& v) { return v_int32x4(vreinterpretq_s32_##suffix(v.val)); } \ +inline v_uint64x2 v_reinterpret_as_u64(const v_##_Tpv& v) { return v_uint64x2(vreinterpretq_u64_##suffix(v.val)); } \ +inline v_int64x2 v_reinterpret_as_s64(const v_##_Tpv& v) { return v_int64x2(vreinterpretq_s64_##suffix(v.val)); } \ +inline v_float32x4 v_reinterpret_as_f32(const v_##_Tpv& v) { return v_float32x4(vreinterpretq_f32_##suffix(v.val)); } + +OPENCV_HAL_IMPL_NEON_INIT(uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_INIT(int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_INIT(uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_INIT(int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_INIT(uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_NEON_INIT(int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_INIT(uint64x2, uint64, u64) +OPENCV_HAL_IMPL_NEON_INIT(int64x2, int64, s64) +OPENCV_HAL_IMPL_NEON_INIT(float32x4, float, f32) +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_NEON_INIT_64(_Tpv, suffix) \ +inline v_float64x2 v_reinterpret_as_f64(const v_##_Tpv& v) { return v_float64x2(vreinterpretq_f64_##suffix(v.val)); } +OPENCV_HAL_IMPL_NEON_INIT(float64x2, double, f64) +OPENCV_HAL_IMPL_NEON_INIT_64(uint8x16, u8) +OPENCV_HAL_IMPL_NEON_INIT_64(int8x16, s8) +OPENCV_HAL_IMPL_NEON_INIT_64(uint16x8, u16) +OPENCV_HAL_IMPL_NEON_INIT_64(int16x8, s16) +OPENCV_HAL_IMPL_NEON_INIT_64(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_INIT_64(int32x4, s32) +OPENCV_HAL_IMPL_NEON_INIT_64(uint64x2, u64) +OPENCV_HAL_IMPL_NEON_INIT_64(int64x2, s64) +OPENCV_HAL_IMPL_NEON_INIT_64(float32x4, f32) +OPENCV_HAL_IMPL_NEON_INIT_64(float64x2, f64) +#endif + +#define OPENCV_HAL_IMPL_NEON_PACK(_Tpvec, _Tp, hreg, suffix, _Tpwvec, pack, mov, rshr) \ +inline _Tpvec v_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + hreg a1 = mov(a.val), b1 = mov(b.val); \ + return _Tpvec(vcombine_##suffix(a1, b1)); \ +} \ +inline void v_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + hreg a1 = mov(a.val); \ + vst1_##suffix(ptr, a1); \ +} \ +template inline \ +_Tpvec v_rshr_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + hreg a1 = rshr(a.val, n); \ + hreg b1 = rshr(b.val, n); \ + return _Tpvec(vcombine_##suffix(a1, b1)); \ +} \ +template inline \ +void v_rshr_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + hreg a1 = rshr(a.val, n); \ + vst1_##suffix(ptr, a1); \ +} + +OPENCV_HAL_IMPL_NEON_PACK(v_uint8x16, uchar, uint8x8_t, u8, v_uint16x8, pack, vqmovn_u16, vqrshrn_n_u16) +OPENCV_HAL_IMPL_NEON_PACK(v_int8x16, schar, int8x8_t, s8, v_int16x8, pack, vqmovn_s16, vqrshrn_n_s16) +OPENCV_HAL_IMPL_NEON_PACK(v_uint16x8, ushort, uint16x4_t, u16, v_uint32x4, pack, vqmovn_u32, vqrshrn_n_u32) +OPENCV_HAL_IMPL_NEON_PACK(v_int16x8, short, int16x4_t, s16, v_int32x4, pack, vqmovn_s32, vqrshrn_n_s32) +OPENCV_HAL_IMPL_NEON_PACK(v_uint32x4, unsigned, uint32x2_t, u32, v_uint64x2, pack, vmovn_u64, vrshrn_n_u64) +OPENCV_HAL_IMPL_NEON_PACK(v_int32x4, int, int32x2_t, s32, v_int64x2, pack, vmovn_s64, vrshrn_n_s64) + +OPENCV_HAL_IMPL_NEON_PACK(v_uint8x16, uchar, uint8x8_t, u8, v_int16x8, pack_u, vqmovun_s16, vqrshrun_n_s16) +OPENCV_HAL_IMPL_NEON_PACK(v_uint16x8, ushort, uint16x4_t, u16, v_int32x4, pack_u, vqmovun_s32, vqrshrun_n_s32) + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + uint8x16_t ab = vcombine_u8(vmovn_u16(a.val), vmovn_u16(b.val)); + return v_uint8x16(ab); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + uint16x8_t nab = vcombine_u16(vmovn_u32(a.val), vmovn_u32(b.val)); + uint16x8_t ncd = vcombine_u16(vmovn_u32(c.val), vmovn_u32(d.val)); + return v_uint8x16(vcombine_u8(vmovn_u16(nab), vmovn_u16(ncd))); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + uint32x4_t ab = vcombine_u32(vmovn_u64(a.val), vmovn_u64(b.val)); + uint32x4_t cd = vcombine_u32(vmovn_u64(c.val), vmovn_u64(d.val)); + uint32x4_t ef = vcombine_u32(vmovn_u64(e.val), vmovn_u64(f.val)); + uint32x4_t gh = vcombine_u32(vmovn_u64(g.val), vmovn_u64(h.val)); + + uint16x8_t abcd = vcombine_u16(vmovn_u32(ab), vmovn_u32(cd)); + uint16x8_t efgh = vcombine_u16(vmovn_u32(ef), vmovn_u32(gh)); + return v_uint8x16(vcombine_u8(vmovn_u16(abcd), vmovn_u16(efgh))); +} + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + float32x2_t vl = vget_low_f32(v.val), vh = vget_high_f32(v.val); + float32x4_t res = vmulq_lane_f32(m0.val, vl, 0); + res = vmlaq_lane_f32(res, m1.val, vl, 1); + res = vmlaq_lane_f32(res, m2.val, vh, 0); + res = vmlaq_lane_f32(res, m3.val, vh, 1); + return v_float32x4(res); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + float32x2_t vl = vget_low_f32(v.val), vh = vget_high_f32(v.val); + float32x4_t res = vmulq_lane_f32(m0.val, vl, 0); + res = vmlaq_lane_f32(res, m1.val, vl, 1); + res = vmlaq_lane_f32(res, m2.val, vh, 0); + res = vaddq_f32(res, a.val); + return v_float32x4(res); +} + +#define OPENCV_HAL_IMPL_NEON_BIN_OP(bin_op, _Tpvec, intrin) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a.val = intrin(a.val, b.val); \ + return a; \ +} + +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint8x16, vqaddq_u8) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint8x16, vqsubq_u8) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int8x16, vqaddq_s8) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int8x16, vqsubq_s8) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint16x8, vqaddq_u16) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint16x8, vqsubq_u16) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int16x8, vqaddq_s16) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int16x8, vqsubq_s16) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int32x4, vaddq_s32) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int32x4, vsubq_s32) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_int32x4, vmulq_s32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint32x4, vaddq_u32) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint32x4, vsubq_u32) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_uint32x4, vmulq_u32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_float32x4, vaddq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_float32x4, vsubq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_float32x4, vmulq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int64x2, vaddq_s64) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int64x2, vsubq_s64) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint64x2, vaddq_u64) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint64x2, vsubq_u64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_BIN_OP(/, v_float32x4, vdivq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_float64x2, vaddq_f64) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_float64x2, vsubq_f64) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_float64x2, vmulq_f64) +OPENCV_HAL_IMPL_NEON_BIN_OP(/, v_float64x2, vdivq_f64) +#else +inline v_float32x4 operator / (const v_float32x4& a, const v_float32x4& b) +{ + float32x4_t reciprocal = vrecpeq_f32(b.val); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + return v_float32x4(vmulq_f32(a.val, reciprocal)); +} +inline v_float32x4& operator /= (v_float32x4& a, const v_float32x4& b) +{ + float32x4_t reciprocal = vrecpeq_f32(b.val); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + a.val = vmulq_f32(a.val, reciprocal); + return a; +} +#endif + +// saturating multiply 8-bit, 16-bit +#define OPENCV_HAL_IMPL_NEON_MUL_SAT(_Tpvec, _Tpwvec) \ + inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ + { \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ + } \ + inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ + { a = a * b; return a; } + +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_int16x8, v_int32x4) +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_uint16x8, v_uint32x4) + +// Multiply and expand +inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b, + v_int16x8& c, v_int16x8& d) +{ + c.val = vmull_s8(vget_low_s8(a.val), vget_low_s8(b.val)); + d.val = vmull_s8(vget_high_s8(a.val), vget_high_s8(b.val)); +} + +inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b, + v_uint16x8& c, v_uint16x8& d) +{ + c.val = vmull_u8(vget_low_u8(a.val), vget_low_u8(b.val)); + d.val = vmull_u8(vget_high_u8(a.val), vget_high_u8(b.val)); +} + +inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, + v_int32x4& c, v_int32x4& d) +{ + c.val = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val)); + d.val = vmull_s16(vget_high_s16(a.val), vget_high_s16(b.val)); +} + +inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, + v_uint32x4& c, v_uint32x4& d) +{ + c.val = vmull_u16(vget_low_u16(a.val), vget_low_u16(b.val)); + d.val = vmull_u16(vget_high_u16(a.val), vget_high_u16(b.val)); +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, + v_uint64x2& c, v_uint64x2& d) +{ + c.val = vmull_u32(vget_low_u32(a.val), vget_low_u32(b.val)); + d.val = vmull_u32(vget_high_u32(a.val), vget_high_u32(b.val)); +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + return v_int16x8(vcombine_s16( + vshrn_n_s32(vmull_s16( vget_low_s16(a.val), vget_low_s16(b.val)), 16), + vshrn_n_s32(vmull_s16(vget_high_s16(a.val), vget_high_s16(b.val)), 16) + )); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + return v_uint16x8(vcombine_u16( + vshrn_n_u32(vmull_u16( vget_low_u16(a.val), vget_low_u16(b.val)), 16), + vshrn_n_u32(vmull_u16(vget_high_u16(a.val), vget_high_u16(b.val)), 16) + )); +} + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ + int32x4_t c = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val)); + int32x4_t d = vmull_s16(vget_high_s16(a.val), vget_high_s16(b.val)); + int32x4x2_t cd = vuzpq_s32(c, d); + return v_int32x4(vaddq_s32(cd.val[0], cd.val[1])); +} + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ + v_int32x4 s = v_dotprod(a, b); + return v_int32x4(vaddq_s32(s.val , c.val)); +} + +#define OPENCV_HAL_IMPL_NEON_LOGIC_OP(_Tpvec, suffix) \ + OPENCV_HAL_IMPL_NEON_BIN_OP(&, _Tpvec, vandq_##suffix) \ + OPENCV_HAL_IMPL_NEON_BIN_OP(|, _Tpvec, vorrq_##suffix) \ + OPENCV_HAL_IMPL_NEON_BIN_OP(^, _Tpvec, veorq_##suffix) \ + inline _Tpvec operator ~ (const _Tpvec& a) \ + { \ + return _Tpvec(vreinterpretq_##suffix##_u8(vmvnq_u8(vreinterpretq_u8_##suffix(a.val)))); \ + } + +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint8x16, u8) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int8x16, s8) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint16x8, u16) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int16x8, s16) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint32x4, u32) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int32x4, s32) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint64x2, u64) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int64x2, s64) + +#define OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(bin_op, intrin) \ +inline v_float32x4 operator bin_op (const v_float32x4& a, const v_float32x4& b) \ +{ \ + return v_float32x4(vreinterpretq_f32_s32(intrin(vreinterpretq_s32_f32(a.val), vreinterpretq_s32_f32(b.val)))); \ +} \ +inline v_float32x4& operator bin_op##= (v_float32x4& a, const v_float32x4& b) \ +{ \ + a.val = vreinterpretq_f32_s32(intrin(vreinterpretq_s32_f32(a.val), vreinterpretq_s32_f32(b.val))); \ + return a; \ +} + +OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(&, vandq_s32) +OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(|, vorrq_s32) +OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(^, veorq_s32) + +inline v_float32x4 operator ~ (const v_float32x4& a) +{ + return v_float32x4(vreinterpretq_f32_s32(vmvnq_s32(vreinterpretq_s32_f32(a.val)))); +} + +#if CV_SIMD128_64F +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ + return v_float32x4(vsqrtq_f32(x.val)); +} + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + v_float32x4 one = v_setall_f32(1.0f); + return one / v_sqrt(x); +} +#else +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ + float32x4_t x1 = vmaxq_f32(x.val, vdupq_n_f32(FLT_MIN)); + float32x4_t e = vrsqrteq_f32(x1); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x1, e), e), e); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x1, e), e), e); + return v_float32x4(vmulq_f32(x.val, e)); +} + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + float32x4_t e = vrsqrteq_f32(x.val); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x.val, e), e), e); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x.val, e), e), e); + return v_float32x4(e); +} +#endif + +#define OPENCV_HAL_IMPL_NEON_ABS(_Tpuvec, _Tpsvec, usuffix, ssuffix) \ +inline _Tpuvec v_abs(const _Tpsvec& a) { return v_reinterpret_as_##usuffix(_Tpsvec(vabsq_##ssuffix(a.val))); } + +OPENCV_HAL_IMPL_NEON_ABS(v_uint8x16, v_int8x16, u8, s8) +OPENCV_HAL_IMPL_NEON_ABS(v_uint16x8, v_int16x8, u16, s16) +OPENCV_HAL_IMPL_NEON_ABS(v_uint32x4, v_int32x4, u32, s32) + +inline v_float32x4 v_abs(v_float32x4 x) +{ return v_float32x4(vabsq_f32(x.val)); } + +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(bin_op, intrin) \ +inline v_float64x2 operator bin_op (const v_float64x2& a, const v_float64x2& b) \ +{ \ + return v_float64x2(vreinterpretq_f64_s64(intrin(vreinterpretq_s64_f64(a.val), vreinterpretq_s64_f64(b.val)))); \ +} \ +inline v_float64x2& operator bin_op##= (v_float64x2& a, const v_float64x2& b) \ +{ \ + a.val = vreinterpretq_f64_s64(intrin(vreinterpretq_s64_f64(a.val), vreinterpretq_s64_f64(b.val))); \ + return a; \ +} + +OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(&, vandq_s64) +OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(|, vorrq_s64) +OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(^, veorq_s64) + +inline v_float64x2 operator ~ (const v_float64x2& a) +{ + return v_float64x2(vreinterpretq_f64_s32(vmvnq_s32(vreinterpretq_s32_f64(a.val)))); +} + +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ + return v_float64x2(vsqrtq_f64(x.val)); +} + +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ + v_float64x2 one = v_setall_f64(1.0f); + return one / v_sqrt(x); +} + +inline v_float64x2 v_abs(v_float64x2 x) +{ return v_float64x2(vabsq_f64(x.val)); } +#endif + +// TODO: exp, log, sin, cos + +#define OPENCV_HAL_IMPL_NEON_BIN_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_min, vminq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_max, vmaxq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_min, vminq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_max, vmaxq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_min, vminq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_max, vmaxq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_min, vminq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_max, vmaxq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint32x4, v_min, vminq_u32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint32x4, v_max, vmaxq_u32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int32x4, v_min, vminq_s32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int32x4, v_max, vmaxq_s32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_min, vminq_f32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_max, vmaxq_f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_min, vminq_f64) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_max, vmaxq_f64) +#endif + +#if CV_SIMD128_64F +inline int64x2_t vmvnq_s64(int64x2_t a) +{ + int64x2_t vx = vreinterpretq_s64_u32(vdupq_n_u32(0xFFFFFFFF)); + return veorq_s64(a, vx); +} +inline uint64x2_t vmvnq_u64(uint64x2_t a) +{ + uint64x2_t vx = vreinterpretq_u64_u32(vdupq_n_u32(0xFFFFFFFF)); + return veorq_u64(a, vx); +} +#endif +#define OPENCV_HAL_IMPL_NEON_INT_CMP_OP(_Tpvec, cast, suffix, not_suffix) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vceqq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vmvnq_##not_suffix(vceqq_##suffix(a.val, b.val)))); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcltq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcgtq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcleq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcgeq_##suffix(a.val, b.val))); } + +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint8x16, OPENCV_HAL_NOP, u8, u8) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int8x16, vreinterpretq_s8_u8, s8, u8) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint16x8, OPENCV_HAL_NOP, u16, u16) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int16x8, vreinterpretq_s16_u16, s16, u16) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint32x4, OPENCV_HAL_NOP, u32, u32) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int32x4, vreinterpretq_s32_u32, s32, u32) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_float32x4, vreinterpretq_f32_u32, f32, u32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint64x2, OPENCV_HAL_NOP, u64, u64) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int64x2, vreinterpretq_s64_u64, s64, u64) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_float64x2, vreinterpretq_f64_u64, f64, u64) +#endif + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return v_float32x4(vreinterpretq_f32_u32(vceqq_f32(a.val, a.val))); } +#if CV_SIMD128_64F +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return v_float64x2(vreinterpretq_f64_u64(vceqq_f64(a.val, a.val))); } +#endif + +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_add_wrap, vaddq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_add_wrap, vaddq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_add_wrap, vaddq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_add_wrap, vaddq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_sub_wrap, vsubq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_sub_wrap, vsubq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_sub_wrap, vsubq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_sub_wrap, vsubq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_mul_wrap, vmulq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_mul_wrap, vmulq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_mul_wrap, vmulq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_mul_wrap, vmulq_s16) + +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_absdiff, vabdq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_absdiff, vabdq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint32x4, v_absdiff, vabdq_u32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_absdiff, vabdq_f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_absdiff, vabdq_f64) +#endif + +/** Saturating absolute difference **/ +inline v_int8x16 v_absdiffs(const v_int8x16& a, const v_int8x16& b) +{ return v_int8x16(vqabsq_s8(vqsubq_s8(a.val, b.val))); } +inline v_int16x8 v_absdiffs(const v_int16x8& a, const v_int16x8& b) +{ return v_int16x8(vqabsq_s16(vqsubq_s16(a.val, b.val))); } + +#define OPENCV_HAL_IMPL_NEON_BIN_FUNC2(_Tpvec, _Tpvec2, cast, func, intrin) \ +inline _Tpvec2 func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec2(cast(intrin(a.val, b.val))); \ +} + +OPENCV_HAL_IMPL_NEON_BIN_FUNC2(v_int8x16, v_uint8x16, vreinterpretq_u8_s8, v_absdiff, vabdq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC2(v_int16x8, v_uint16x8, vreinterpretq_u16_s16, v_absdiff, vabdq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC2(v_int32x4, v_uint32x4, vreinterpretq_u32_s32, v_absdiff, vabdq_s32) + +inline v_float32x4 v_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + v_float32x4 x(vmlaq_f32(vmulq_f32(a.val, a.val), b.val, b.val)); + return v_sqrt(x); +} + +inline v_float32x4 v_sqr_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + return v_float32x4(vmlaq_f32(vmulq_f32(a.val, a.val), b.val, b.val)); +} + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ +#if CV_SIMD128_64F + // ARMv8, which adds support for 64-bit floating-point (so CV_SIMD128_64F is defined), + // also adds FMA support both for single- and double-precision floating-point vectors + return v_float32x4(vfmaq_f32(c.val, a.val, b.val)); +#else + return v_float32x4(vmlaq_f32(c.val, a.val, b.val)); +#endif +} + +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_int32x4(vmlaq_s32(c.val, a.val, b.val)); +} + +inline v_float32x4 v_muladd(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +#if CV_SIMD128_64F +inline v_float64x2 v_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + v_float64x2 x(vaddq_f64(vmulq_f64(a.val, a.val), vmulq_f64(b.val, b.val))); + return v_sqrt(x); +} + +inline v_float64x2 v_sqr_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + return v_float64x2(vaddq_f64(vmulq_f64(a.val, a.val), vmulq_f64(b.val, b.val))); +} + +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_float64x2(vfmaq_f64(c.val, a.val, b.val)); +} + +inline v_float64x2 v_muladd(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_fma(a, b, c); +} +#endif + +// trade efficiency for convenience +#define OPENCV_HAL_IMPL_NEON_SHIFT_OP(_Tpvec, suffix, _Tps, ssuffix) \ +inline _Tpvec operator << (const _Tpvec& a, int n) \ +{ return _Tpvec(vshlq_##suffix(a.val, vdupq_n_##ssuffix((_Tps)n))); } \ +inline _Tpvec operator >> (const _Tpvec& a, int n) \ +{ return _Tpvec(vshlq_##suffix(a.val, vdupq_n_##ssuffix((_Tps)-n))); } \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ return _Tpvec(vshlq_n_##suffix(a.val, n)); } \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ return _Tpvec(vshrq_n_##suffix(a.val, n)); } \ +template inline _Tpvec v_rshr(const _Tpvec& a) \ +{ return _Tpvec(vrshrq_n_##suffix(a.val, n)); } + +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint8x16, u8, schar, s8) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int8x16, s8, schar, s8) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint16x8, u16, short, s16) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int16x8, s16, short, s16) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint32x4, u32, int, s32) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int32x4, s32, int, s32) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint64x2, u64, int64, s64) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int64x2, s64, int64, s64) + +#define OPENCV_HAL_IMPL_NEON_ROTATE_OP(_Tpvec, suffix) \ +template inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ return _Tpvec(vextq_##suffix(a.val, vdupq_n_##suffix(0), n)); } \ +template inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ return _Tpvec(vextq_##suffix(vdupq_n_##suffix(0), a.val, _Tpvec::nlanes - n)); } \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a) \ +{ return a; } \ +template inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vextq_##suffix(a.val, b.val, n)); } \ +template inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vextq_##suffix(b.val, a.val, _Tpvec::nlanes - n)); } \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a, const _Tpvec& b) \ +{ CV_UNUSED(b); return a; } + +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint8x16, u8) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int8x16, s8) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint16x8, u16) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int16x8, s16) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint32x4, u32) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int32x4, s32) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_float32x4, f32) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint64x2, u64) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int64x2, s64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_float64x2, f64) +#endif + +#define OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(vld1q_##suffix(ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(vld1q_##suffix(ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(vcombine_##suffix(vld1_##suffix(ptr), vdup_n_##suffix((_Tp)0))); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ return _Tpvec(vcombine_##suffix(vld1_##suffix(ptr0), vld1_##suffix(ptr1))); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode /*mode*/) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ vst1_##suffix(ptr, vget_low_##suffix(a.val)); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ vst1_##suffix(ptr, vget_high_##suffix(a.val)); } + +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int64x2, int64, s64) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float32x4, float, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float64x2, double, f64) +#endif + +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + _Tpnvec##_t a0 = vp##vectorfunc##_##suffix(vget_low_##suffix(a.val), vget_high_##suffix(a.val)); \ + a0 = vp##vectorfunc##_##suffix(a0, a0); \ + return (scalartype)vget_lane_##suffix(vp##vectorfunc##_##suffix(a0, a0),0); \ +} + +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, unsigned short, sum, add, u16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, unsigned short, max, max, u16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, unsigned short, min, min, u16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, sum, add, s16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, max, max, s16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, min, min, s16) + +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + _Tpnvec##_t a0 = vp##vectorfunc##_##suffix(vget_low_##suffix(a.val), vget_high_##suffix(a.val)); \ + return (scalartype)vget_lane_##suffix(vp##vectorfunc##_##suffix(a0, vget_high_##suffix(a.val)),0); \ +} + +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, sum, add, u32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, max, max, u32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, min, min, u32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, sum, add, s32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, max, max, s32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, min, min, s32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, sum, add, f32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, max, max, f32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, min, min, f32) + +#if CV_SIMD128_64F +inline double v_reduce_sum(const v_float64x2& a) +{ + return vgetq_lane_f64(a.val, 0) + vgetq_lane_f64(a.val, 1); +} +#endif + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + float32x4x2_t ab = vtrnq_f32(a.val, b.val); + float32x4x2_t cd = vtrnq_f32(c.val, d.val); + + float32x4_t u0 = vaddq_f32(ab.val[0], ab.val[1]); // a0+a1 b0+b1 a2+a3 b2+b3 + float32x4_t u1 = vaddq_f32(cd.val[0], cd.val[1]); // c0+c1 d0+d1 c2+c3 d2+d3 + + float32x4_t v0 = vcombine_f32(vget_low_f32(u0), vget_low_f32(u1)); + float32x4_t v1 = vcombine_f32(vget_high_f32(u0), vget_high_f32(u1)); + + return v_float32x4(vaddq_f32(v0, v1)); +} + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ + uint32x4_t t0 = vpaddlq_u16(vpaddlq_u8(vabdq_u8(a.val, b.val))); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ + uint32x4_t t0 = vpaddlq_u16(vpaddlq_u8(vreinterpretq_u8_s8(vabdq_s8(a.val, b.val)))); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ + uint32x4_t t0 = vpaddlq_u16(vabdq_u16(a.val, b.val)); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ + uint32x4_t t0 = vpaddlq_u16(vreinterpretq_u16_s16(vabdq_s16(a.val, b.val))); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ + uint32x4_t t0 = vabdq_u32(a.val, b.val); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ + uint32x4_t t0 = vreinterpretq_u32_s32(vabdq_s32(a.val, b.val)); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + float32x4_t t0 = vabdq_f32(a.val, b.val); + float32x2_t t1 = vpadd_f32(vget_low_f32(t0), vget_high_f32(t0)); + return vget_lane_f32(vpadd_f32(t1, t1), 0); +} + +#define OPENCV_HAL_IMPL_NEON_POPCOUNT(_Tpvec, cast) \ +inline v_uint32x4 v_popcount(const _Tpvec& a) \ +{ \ + uint8x16_t t = vcntq_u8(cast(a.val)); \ + uint16x8_t t0 = vpaddlq_u8(t); /* 16 -> 8 */ \ + uint32x4_t t1 = vpaddlq_u16(t0); /* 8 -> 4 */ \ + return v_uint32x4(t1); \ +} + +OPENCV_HAL_IMPL_NEON_POPCOUNT(v_uint8x16, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_NEON_POPCOUNT(v_uint16x8, vreinterpretq_u8_u16) +OPENCV_HAL_IMPL_NEON_POPCOUNT(v_uint32x4, vreinterpretq_u8_u32) +OPENCV_HAL_IMPL_NEON_POPCOUNT(v_int8x16, vreinterpretq_u8_s8) +OPENCV_HAL_IMPL_NEON_POPCOUNT(v_int16x8, vreinterpretq_u8_s16) +OPENCV_HAL_IMPL_NEON_POPCOUNT(v_int32x4, vreinterpretq_u8_s32) + +inline int v_signmask(const v_uint8x16& a) +{ + int8x8_t m0 = vcreate_s8(CV_BIG_UINT(0x0706050403020100)); + uint8x16_t v0 = vshlq_u8(vshrq_n_u8(a.val, 7), vcombine_s8(m0, m0)); + uint64x2_t v1 = vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(v0))); + return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 8); +} +inline int v_signmask(const v_int8x16& a) +{ return v_signmask(v_reinterpret_as_u8(a)); } + +inline int v_signmask(const v_uint16x8& a) +{ + int16x4_t m0 = vcreate_s16(CV_BIG_UINT(0x0003000200010000)); + uint16x8_t v0 = vshlq_u16(vshrq_n_u16(a.val, 15), vcombine_s16(m0, m0)); + uint64x2_t v1 = vpaddlq_u32(vpaddlq_u16(v0)); + return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 4); +} +inline int v_signmask(const v_int16x8& a) +{ return v_signmask(v_reinterpret_as_u16(a)); } + +inline int v_signmask(const v_uint32x4& a) +{ + int32x2_t m0 = vcreate_s32(CV_BIG_UINT(0x0000000100000000)); + uint32x4_t v0 = vshlq_u32(vshrq_n_u32(a.val, 31), vcombine_s32(m0, m0)); + uint64x2_t v1 = vpaddlq_u32(v0); + return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 2); +} +inline int v_signmask(const v_int32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } +inline int v_signmask(const v_float32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } +#if CV_SIMD128_64F +inline int v_signmask(const v_uint64x2& a) +{ + int64x1_t m0 = vdup_n_s64(0); + uint64x2_t v0 = vshlq_u64(vshrq_n_u64(a.val, 63), vcombine_s64(m0, m0)); + return (int)vgetq_lane_u64(v0, 0) + ((int)vgetq_lane_u64(v0, 1) << 1); +} +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +#endif + +#define OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(_Tpvec, suffix, shift) \ +inline bool v_check_all(const v_##_Tpvec& a) \ +{ \ + _Tpvec##_t v0 = vshrq_n_##suffix(vmvnq_##suffix(a.val), shift); \ + uint64x2_t v1 = vreinterpretq_u64_##suffix(v0); \ + return (vgetq_lane_u64(v1, 0) | vgetq_lane_u64(v1, 1)) == 0; \ +} \ +inline bool v_check_any(const v_##_Tpvec& a) \ +{ \ + _Tpvec##_t v0 = vshrq_n_##suffix(a.val, shift); \ + uint64x2_t v1 = vreinterpretq_u64_##suffix(v0); \ + return (vgetq_lane_u64(v1, 0) | vgetq_lane_u64(v1, 1)) != 0; \ +} + +OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint8x16, u8, 7) +OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint16x8, u16, 15) +OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint32x4, u32, 31) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint64x2, u64, 63) +#endif + +inline bool v_check_all(const v_int8x16& a) +{ return v_check_all(v_reinterpret_as_u8(a)); } +inline bool v_check_all(const v_int16x8& a) +{ return v_check_all(v_reinterpret_as_u16(a)); } +inline bool v_check_all(const v_int32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } + +inline bool v_check_any(const v_int8x16& a) +{ return v_check_any(v_reinterpret_as_u8(a)); } +inline bool v_check_any(const v_int16x8& a) +{ return v_check_any(v_reinterpret_as_u16(a)); } +inline bool v_check_any(const v_int32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } + +#if CV_SIMD128_64F +inline bool v_check_all(const v_int64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_int64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } +#endif + +#define OPENCV_HAL_IMPL_NEON_SELECT(_Tpvec, suffix, usuffix) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vbslq_##suffix(vreinterpretq_##usuffix##_##suffix(mask.val), a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_NEON_SELECT(v_uint8x16, u8, u8) +OPENCV_HAL_IMPL_NEON_SELECT(v_int8x16, s8, u8) +OPENCV_HAL_IMPL_NEON_SELECT(v_uint16x8, u16, u16) +OPENCV_HAL_IMPL_NEON_SELECT(v_int16x8, s16, u16) +OPENCV_HAL_IMPL_NEON_SELECT(v_uint32x4, u32, u32) +OPENCV_HAL_IMPL_NEON_SELECT(v_int32x4, s32, u32) +OPENCV_HAL_IMPL_NEON_SELECT(v_float32x4, f32, u32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_SELECT(v_float64x2, f64, u64) +#endif + +#define OPENCV_HAL_IMPL_NEON_EXPAND(_Tpvec, _Tpwvec, _Tp, suffix) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + b0.val = vmovl_##suffix(vget_low_##suffix(a.val)); \ + b1.val = vmovl_##suffix(vget_high_##suffix(a.val)); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ \ + return _Tpwvec(vmovl_##suffix(vget_low_##suffix(a.val))); \ +} \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ \ + return _Tpwvec(vmovl_##suffix(vget_high_##suffix(a.val))); \ +} \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ \ + return _Tpwvec(vmovl_##suffix(vld1_##suffix(ptr))); \ +} + +OPENCV_HAL_IMPL_NEON_EXPAND(v_uint8x16, v_uint16x8, uchar, u8) +OPENCV_HAL_IMPL_NEON_EXPAND(v_int8x16, v_int16x8, schar, s8) +OPENCV_HAL_IMPL_NEON_EXPAND(v_uint16x8, v_uint32x4, ushort, u16) +OPENCV_HAL_IMPL_NEON_EXPAND(v_int16x8, v_int32x4, short, s16) +OPENCV_HAL_IMPL_NEON_EXPAND(v_uint32x4, v_uint64x2, uint, u32) +OPENCV_HAL_IMPL_NEON_EXPAND(v_int32x4, v_int64x2, int, s32) + +inline v_uint32x4 v_load_expand_q(const uchar* ptr) +{ + uint8x8_t v0 = vcreate_u8(*(unsigned*)ptr); + uint16x4_t v1 = vget_low_u16(vmovl_u8(v0)); + return v_uint32x4(vmovl_u16(v1)); +} + +inline v_int32x4 v_load_expand_q(const schar* ptr) +{ + int8x8_t v0 = vcreate_s8(*(unsigned*)ptr); + int16x4_t v1 = vget_low_s16(vmovl_s8(v0)); + return v_int32x4(vmovl_s16(v1)); +} + +#if defined(__aarch64__) +#define OPENCV_HAL_IMPL_NEON_UNPACKS(_Tpvec, suffix) \ +inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \ +{ \ + b0.val = vzip1q_##suffix(a0.val, a1.val); \ + b1.val = vzip2q_##suffix(a0.val, a1.val); \ +} \ +inline v_##_Tpvec v_combine_low(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val))); \ +} \ +inline v_##_Tpvec v_combine_high(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val))); \ +} \ +inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + c.val = vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val)); \ + d.val = vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val)); \ +} +#else +#define OPENCV_HAL_IMPL_NEON_UNPACKS(_Tpvec, suffix) \ +inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \ +{ \ + _Tpvec##x2_t p = vzipq_##suffix(a0.val, a1.val); \ + b0.val = p.val[0]; \ + b1.val = p.val[1]; \ +} \ +inline v_##_Tpvec v_combine_low(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val))); \ +} \ +inline v_##_Tpvec v_combine_high(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val))); \ +} \ +inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + c.val = vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val)); \ + d.val = vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val)); \ +} +#endif + +OPENCV_HAL_IMPL_NEON_UNPACKS(uint8x16, u8) +OPENCV_HAL_IMPL_NEON_UNPACKS(int8x16, s8) +OPENCV_HAL_IMPL_NEON_UNPACKS(uint16x8, u16) +OPENCV_HAL_IMPL_NEON_UNPACKS(int16x8, s16) +OPENCV_HAL_IMPL_NEON_UNPACKS(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_UNPACKS(int32x4, s32) +OPENCV_HAL_IMPL_NEON_UNPACKS(float32x4, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_UNPACKS(float64x2, f64) +#endif + +#define OPENCV_HAL_IMPL_NEON_EXTRACT(_Tpvec, suffix) \ +template \ +inline v_##_Tpvec v_extract(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vextq_##suffix(a.val, b.val, s)); \ +} + +OPENCV_HAL_IMPL_NEON_EXTRACT(uint8x16, u8) +OPENCV_HAL_IMPL_NEON_EXTRACT(int8x16, s8) +OPENCV_HAL_IMPL_NEON_EXTRACT(uint16x8, u16) +OPENCV_HAL_IMPL_NEON_EXTRACT(int16x8, s16) +OPENCV_HAL_IMPL_NEON_EXTRACT(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_EXTRACT(int32x4, s32) +OPENCV_HAL_IMPL_NEON_EXTRACT(uint64x2, u64) +OPENCV_HAL_IMPL_NEON_EXTRACT(int64x2, s64) +OPENCV_HAL_IMPL_NEON_EXTRACT(float32x4, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_EXTRACT(float64x2, f64) +#endif + +#if CV_SIMD128_64F +inline v_int32x4 v_round(const v_float32x4& a) +{ + float32x4_t a_ = a.val; + int32x4_t result; + __asm__ ("fcvtns %0.4s, %1.4s" + : "=w"(result) + : "w"(a_) + : /* No clobbers */); + return v_int32x4(result); +} +#else +inline v_int32x4 v_round(const v_float32x4& a) +{ + static const int32x4_t v_sign = vdupq_n_s32(1 << 31), + v_05 = vreinterpretq_s32_f32(vdupq_n_f32(0.5f)); + + int32x4_t v_addition = vorrq_s32(v_05, vandq_s32(v_sign, vreinterpretq_s32_f32(a.val))); + return v_int32x4(vcvtq_s32_f32(vaddq_f32(a.val, vreinterpretq_f32_s32(v_addition)))); +} +#endif +inline v_int32x4 v_floor(const v_float32x4& a) +{ + int32x4_t a1 = vcvtq_s32_f32(a.val); + uint32x4_t mask = vcgtq_f32(vcvtq_f32_s32(a1), a.val); + return v_int32x4(vaddq_s32(a1, vreinterpretq_s32_u32(mask))); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + int32x4_t a1 = vcvtq_s32_f32(a.val); + uint32x4_t mask = vcgtq_f32(a.val, vcvtq_f32_s32(a1)); + return v_int32x4(vsubq_s32(a1, vreinterpretq_s32_u32(mask))); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ return v_int32x4(vcvtq_s32_f32(a.val)); } + +#if CV_SIMD128_64F +inline v_int32x4 v_round(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), zero)); +} + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), vmovn_s64(vcvtaq_s64_f64(b.val)))); +} + +inline v_int32x4 v_floor(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + int64x2_t a1 = vcvtq_s64_f64(a.val); + uint64x2_t mask = vcgtq_f64(vcvtq_f64_s64(a1), a.val); + a1 = vaddq_s64(a1, vreinterpretq_s64_u64(mask)); + return v_int32x4(vcombine_s32(vmovn_s64(a1), zero)); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + int64x2_t a1 = vcvtq_s64_f64(a.val); + uint64x2_t mask = vcgtq_f64(a.val, vcvtq_f64_s64(a1)); + a1 = vsubq_s64(a1, vreinterpretq_s64_u64(mask)); + return v_int32x4(vcombine_s32(vmovn_s64(a1), zero)); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), zero)); +} +#endif + +#define OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(_Tpvec, suffix) \ +inline void v_transpose4x4(const v_##_Tpvec& a0, const v_##_Tpvec& a1, \ + const v_##_Tpvec& a2, const v_##_Tpvec& a3, \ + v_##_Tpvec& b0, v_##_Tpvec& b1, \ + v_##_Tpvec& b2, v_##_Tpvec& b3) \ +{ \ + /* m00 m01 m02 m03 */ \ + /* m10 m11 m12 m13 */ \ + /* m20 m21 m22 m23 */ \ + /* m30 m31 m32 m33 */ \ + _Tpvec##x2_t t0 = vtrnq_##suffix(a0.val, a1.val); \ + _Tpvec##x2_t t1 = vtrnq_##suffix(a2.val, a3.val); \ + /* m00 m10 m02 m12 */ \ + /* m01 m11 m03 m13 */ \ + /* m20 m30 m22 m32 */ \ + /* m21 m31 m23 m33 */ \ + b0.val = vcombine_##suffix(vget_low_##suffix(t0.val[0]), vget_low_##suffix(t1.val[0])); \ + b1.val = vcombine_##suffix(vget_low_##suffix(t0.val[1]), vget_low_##suffix(t1.val[1])); \ + b2.val = vcombine_##suffix(vget_high_##suffix(t0.val[0]), vget_high_##suffix(t1.val[0])); \ + b3.val = vcombine_##suffix(vget_high_##suffix(t0.val[1]), vget_high_##suffix(t1.val[1])); \ +} + +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(int32x4, s32) +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(float32x4, f32) + +#define OPENCV_HAL_IMPL_NEON_INTERLEAVED(_Tpvec, _Tp, suffix) \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b) \ +{ \ + _Tpvec##x2_t v = vld2q_##suffix(ptr); \ + a.val = v.val[0]; \ + b.val = v.val[1]; \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, v_##_Tpvec& c) \ +{ \ + _Tpvec##x3_t v = vld3q_##suffix(ptr); \ + a.val = v.val[0]; \ + b.val = v.val[1]; \ + c.val = v.val[2]; \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, \ + v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + _Tpvec##x4_t v = vld4q_##suffix(ptr); \ + a.val = v.val[0]; \ + b.val = v.val[1]; \ + c.val = v.val[2]; \ + d.val = v.val[3]; \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + _Tpvec##x2_t v; \ + v.val[0] = a.val; \ + v.val[1] = b.val; \ + vst2q_##suffix(ptr, v); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + _Tpvec##x3_t v; \ + v.val[0] = a.val; \ + v.val[1] = b.val; \ + v.val[2] = c.val; \ + vst3q_##suffix(ptr, v); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, const v_##_Tpvec& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec##x4_t v; \ + v.val[0] = a.val; \ + v.val[1] = b.val; \ + v.val[2] = c.val; \ + v.val[3] = d.val; \ + vst4q_##suffix(ptr, v); \ +} + +#define OPENCV_HAL_IMPL_NEON_INTERLEAVED_INT64(tp, suffix) \ +inline void v_load_deinterleave( const tp* ptr, v_##tp##x2& a, v_##tp##x2& b ) \ +{ \ + tp##x1_t a0 = vld1_##suffix(ptr); \ + tp##x1_t b0 = vld1_##suffix(ptr + 1); \ + tp##x1_t a1 = vld1_##suffix(ptr + 2); \ + tp##x1_t b1 = vld1_##suffix(ptr + 3); \ + a = v_##tp##x2(vcombine_##suffix(a0, a1)); \ + b = v_##tp##x2(vcombine_##suffix(b0, b1)); \ +} \ + \ +inline void v_load_deinterleave( const tp* ptr, v_##tp##x2& a, \ + v_##tp##x2& b, v_##tp##x2& c ) \ +{ \ + tp##x1_t a0 = vld1_##suffix(ptr); \ + tp##x1_t b0 = vld1_##suffix(ptr + 1); \ + tp##x1_t c0 = vld1_##suffix(ptr + 2); \ + tp##x1_t a1 = vld1_##suffix(ptr + 3); \ + tp##x1_t b1 = vld1_##suffix(ptr + 4); \ + tp##x1_t c1 = vld1_##suffix(ptr + 5); \ + a = v_##tp##x2(vcombine_##suffix(a0, a1)); \ + b = v_##tp##x2(vcombine_##suffix(b0, b1)); \ + c = v_##tp##x2(vcombine_##suffix(c0, c1)); \ +} \ + \ +inline void v_load_deinterleave( const tp* ptr, v_##tp##x2& a, v_##tp##x2& b, \ + v_##tp##x2& c, v_##tp##x2& d ) \ +{ \ + tp##x1_t a0 = vld1_##suffix(ptr); \ + tp##x1_t b0 = vld1_##suffix(ptr + 1); \ + tp##x1_t c0 = vld1_##suffix(ptr + 2); \ + tp##x1_t d0 = vld1_##suffix(ptr + 3); \ + tp##x1_t a1 = vld1_##suffix(ptr + 4); \ + tp##x1_t b1 = vld1_##suffix(ptr + 5); \ + tp##x1_t c1 = vld1_##suffix(ptr + 6); \ + tp##x1_t d1 = vld1_##suffix(ptr + 7); \ + a = v_##tp##x2(vcombine_##suffix(a0, a1)); \ + b = v_##tp##x2(vcombine_##suffix(b0, b1)); \ + c = v_##tp##x2(vcombine_##suffix(c0, c1)); \ + d = v_##tp##x2(vcombine_##suffix(d0, d1)); \ +} \ + \ +inline void v_store_interleave( tp* ptr, const v_##tp##x2& a, const v_##tp##x2& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + vst1_##suffix(ptr, vget_low_##suffix(a.val)); \ + vst1_##suffix(ptr + 1, vget_low_##suffix(b.val)); \ + vst1_##suffix(ptr + 2, vget_high_##suffix(a.val)); \ + vst1_##suffix(ptr + 3, vget_high_##suffix(b.val)); \ +} \ + \ +inline void v_store_interleave( tp* ptr, const v_##tp##x2& a, \ + const v_##tp##x2& b, const v_##tp##x2& c, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + vst1_##suffix(ptr, vget_low_##suffix(a.val)); \ + vst1_##suffix(ptr + 1, vget_low_##suffix(b.val)); \ + vst1_##suffix(ptr + 2, vget_low_##suffix(c.val)); \ + vst1_##suffix(ptr + 3, vget_high_##suffix(a.val)); \ + vst1_##suffix(ptr + 4, vget_high_##suffix(b.val)); \ + vst1_##suffix(ptr + 5, vget_high_##suffix(c.val)); \ +} \ + \ +inline void v_store_interleave( tp* ptr, const v_##tp##x2& a, const v_##tp##x2& b, \ + const v_##tp##x2& c, const v_##tp##x2& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + vst1_##suffix(ptr, vget_low_##suffix(a.val)); \ + vst1_##suffix(ptr + 1, vget_low_##suffix(b.val)); \ + vst1_##suffix(ptr + 2, vget_low_##suffix(c.val)); \ + vst1_##suffix(ptr + 3, vget_low_##suffix(d.val)); \ + vst1_##suffix(ptr + 4, vget_high_##suffix(a.val)); \ + vst1_##suffix(ptr + 5, vget_high_##suffix(b.val)); \ + vst1_##suffix(ptr + 6, vget_high_##suffix(c.val)); \ + vst1_##suffix(ptr + 7, vget_high_##suffix(d.val)); \ +} + +OPENCV_HAL_IMPL_NEON_INTERLEAVED(uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(float32x4, float, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_INTERLEAVED(float64x2, double, f64) +#endif + +OPENCV_HAL_IMPL_NEON_INTERLEAVED_INT64(int64, s64) +OPENCV_HAL_IMPL_NEON_INTERLEAVED_INT64(uint64, u64) + +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(vcvtq_f32_s32(a.val)); +} + +#if CV_SIMD128_64F +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + float32x2_t zero = vdup_n_f32(0.0f); + return v_float32x4(vcombine_f32(vcvt_f32_f64(a.val), zero)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + return v_float32x4(vcombine_f32(vcvt_f32_f64(a.val), vcvt_f32_f64(b.val))); +} + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vcvt_f32_s32(vget_low_s32(a.val)))); +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vcvt_f32_s32(vget_high_s32(a.val)))); +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vget_low_f32(a.val))); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vget_high_f32(a.val))); +} +#endif + +////////////// Lookup table access //////////////////// + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) elems[4] = + { + tab[vgetq_lane_s32(idxvec.val, 0)], + tab[vgetq_lane_s32(idxvec.val, 1)], + tab[vgetq_lane_s32(idxvec.val, 2)], + tab[vgetq_lane_s32(idxvec.val, 3)] + }; + return v_int32x4(vld1q_s32(elems)); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + float CV_DECL_ALIGNED(32) elems[4] = + { + tab[vgetq_lane_s32(idxvec.val, 0)], + tab[vgetq_lane_s32(idxvec.val, 1)], + tab[vgetq_lane_s32(idxvec.val, 2)], + tab[vgetq_lane_s32(idxvec.val, 3)] + }; + return v_float32x4(vld1q_f32(elems)); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + /*int CV_DECL_ALIGNED(32) idx[4]; + v_store(idx, idxvec); + + float32x4_t xy02 = vcombine_f32(vld1_f32(tab + idx[0]), vld1_f32(tab + idx[2])); + float32x4_t xy13 = vcombine_f32(vld1_f32(tab + idx[1]), vld1_f32(tab + idx[3])); + + float32x4x2_t xxyy = vuzpq_f32(xy02, xy13); + x = v_float32x4(xxyy.val[0]); + y = v_float32x4(xxyy.val[1]);*/ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + x = v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); + y = v_float32x4(tab[idx[0]+1], tab[idx[1]+1], tab[idx[2]+1], tab[idx[3]+1]); +} + +#if CV_SIMD128_64F +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + double CV_DECL_ALIGNED(32) elems[2] = + { + tab[vgetq_lane_s32(idxvec.val, 0)], + tab[vgetq_lane_s32(idxvec.val, 1)], + }; + return v_float64x2(vld1q_f64(elems)); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + x = v_float64x2(tab[idx[0]], tab[idx[1]]); + y = v_float64x2(tab[idx[0]+1], tab[idx[1]+1]); +} +#endif + +////// FP16 suport /////// +#if CV_FP16 +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + float16x4_t v = + #ifndef vld1_f16 // APPLE compiler defines vld1_f16 as macro + (float16x4_t)vld1_s16((const short*)ptr); + #else + vld1_f16((const __fp16*)ptr); + #endif + return v_float32x4(vcvt_f32_f16(v)); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + float16x4_t hv = vcvt_f16_f32(v.val); + + #ifndef vst1_f16 // APPLE compiler defines vst1_f16 as macro + vst1_s16((short*)ptr, (int16x4_t)hv); + #else + vst1_f16((__fp16*)ptr, hv); + #endif +} +#else +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + const int N = 4; + float buf[N]; + for( int i = 0; i < N; i++ ) buf[i] = (float)ptr[i]; + return v_load(buf); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + const int N = 4; + float buf[N]; + v_store(buf, v); + for( int i = 0; i < N; i++ ) ptr[i] = float16_t(buf[i]); +} +#endif + +inline void v_cleanup() {} + +//! @name Check SIMD support +//! @{ +//! @brief Check CPU capability of SIMD operation +static inline bool hasSIMD128() +{ + return (CV_CPU_HAS_SUPPORT_NEON) ? true : false; +} + +//! @} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif diff --git a/include/opencv2/core/hal/intrin_sse.hpp b/include/opencv2/core/hal/intrin_sse.hpp new file mode 100644 index 0000000..f7a67da --- /dev/null +++ b/include/opencv2/core/hal/intrin_sse.hpp @@ -0,0 +1,2816 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_HAL_SSE_HPP +#define OPENCV_HAL_SSE_HPP + +#include +#include "opencv2/core/utility.hpp" + +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 +#define CV_SIMD128_FP16 0 // no native operations with FP16 type. + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +///////// Types //////////// + +struct v_uint8x16 +{ + typedef uchar lane_type; + typedef __m128i vector_type; + enum { nlanes = 16 }; + + v_uint8x16() : val(_mm_setzero_si128()) {} + explicit v_uint8x16(__m128i v) : val(v) {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + val = _mm_setr_epi8((char)v0, (char)v1, (char)v2, (char)v3, + (char)v4, (char)v5, (char)v6, (char)v7, + (char)v8, (char)v9, (char)v10, (char)v11, + (char)v12, (char)v13, (char)v14, (char)v15); + } + uchar get0() const + { + return (uchar)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + typedef __m128i vector_type; + enum { nlanes = 16 }; + + v_int8x16() : val(_mm_setzero_si128()) {} + explicit v_int8x16(__m128i v) : val(v) {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + val = _mm_setr_epi8((char)v0, (char)v1, (char)v2, (char)v3, + (char)v4, (char)v5, (char)v6, (char)v7, + (char)v8, (char)v9, (char)v10, (char)v11, + (char)v12, (char)v13, (char)v14, (char)v15); + } + schar get0() const + { + return (schar)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + typedef __m128i vector_type; + enum { nlanes = 8 }; + + v_uint16x8() : val(_mm_setzero_si128()) {} + explicit v_uint16x8(__m128i v) : val(v) {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + val = _mm_setr_epi16((short)v0, (short)v1, (short)v2, (short)v3, + (short)v4, (short)v5, (short)v6, (short)v7); + } + ushort get0() const + { + return (ushort)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + typedef __m128i vector_type; + enum { nlanes = 8 }; + + v_int16x8() : val(_mm_setzero_si128()) {} + explicit v_int16x8(__m128i v) : val(v) {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + val = _mm_setr_epi16((short)v0, (short)v1, (short)v2, (short)v3, + (short)v4, (short)v5, (short)v6, (short)v7); + } + short get0() const + { + return (short)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + typedef __m128i vector_type; + enum { nlanes = 4 }; + + v_uint32x4() : val(_mm_setzero_si128()) {} + explicit v_uint32x4(__m128i v) : val(v) {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + val = _mm_setr_epi32((int)v0, (int)v1, (int)v2, (int)v3); + } + unsigned get0() const + { + return (unsigned)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + typedef __m128i vector_type; + enum { nlanes = 4 }; + + v_int32x4() : val(_mm_setzero_si128()) {} + explicit v_int32x4(__m128i v) : val(v) {} + v_int32x4(int v0, int v1, int v2, int v3) + { + val = _mm_setr_epi32(v0, v1, v2, v3); + } + int get0() const + { + return _mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + typedef __m128 vector_type; + enum { nlanes = 4 }; + + v_float32x4() : val(_mm_setzero_ps()) {} + explicit v_float32x4(__m128 v) : val(v) {} + v_float32x4(float v0, float v1, float v2, float v3) + { + val = _mm_setr_ps(v0, v1, v2, v3); + } + float get0() const + { + return _mm_cvtss_f32(val); + } + + __m128 val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + typedef __m128i vector_type; + enum { nlanes = 2 }; + + v_uint64x2() : val(_mm_setzero_si128()) {} + explicit v_uint64x2(__m128i v) : val(v) {} + v_uint64x2(uint64 v0, uint64 v1) + { + val = _mm_setr_epi32((int)v0, (int)(v0 >> 32), (int)v1, (int)(v1 >> 32)); + } + uint64 get0() const + { + int a = _mm_cvtsi128_si32(val); + int b = _mm_cvtsi128_si32(_mm_srli_epi64(val, 32)); + return (unsigned)a | ((uint64)(unsigned)b << 32); + } + + __m128i val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + typedef __m128i vector_type; + enum { nlanes = 2 }; + + v_int64x2() : val(_mm_setzero_si128()) {} + explicit v_int64x2(__m128i v) : val(v) {} + v_int64x2(int64 v0, int64 v1) + { + val = _mm_setr_epi32((int)v0, (int)(v0 >> 32), (int)v1, (int)(v1 >> 32)); + } + int64 get0() const + { + int a = _mm_cvtsi128_si32(val); + int b = _mm_cvtsi128_si32(_mm_srli_epi64(val, 32)); + return (int64)((unsigned)a | ((uint64)(unsigned)b << 32)); + } + + __m128i val; +}; + +struct v_float64x2 +{ + typedef double lane_type; + typedef __m128d vector_type; + enum { nlanes = 2 }; + + v_float64x2() : val(_mm_setzero_pd()) {} + explicit v_float64x2(__m128d v) : val(v) {} + v_float64x2(double v0, double v1) + { + val = _mm_setr_pd(v0, v1); + } + double get0() const + { + return _mm_cvtsd_f64(val); + } + + __m128d val; +}; + +namespace hal_sse_internal +{ + template + to_sse_type v_sse_reinterpret_as(const from_sse_type& val); + +#define OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(to_sse_type, from_sse_type, sse_cast_intrin) \ + template<> inline \ + to_sse_type v_sse_reinterpret_as(const from_sse_type& a) \ + { return sse_cast_intrin(a); } + + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128i, __m128i, OPENCV_HAL_NOP) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128i, __m128, _mm_castps_si128) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128i, __m128d, _mm_castpd_si128) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128, __m128i, _mm_castsi128_ps) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128, __m128, OPENCV_HAL_NOP) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128, __m128d, _mm_castpd_ps) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128d, __m128i, _mm_castsi128_pd) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128d, __m128, _mm_castps_pd) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128d, __m128d, OPENCV_HAL_NOP) +} + +#define OPENCV_HAL_IMPL_SSE_INITVEC(_Tpvec, _Tp, suffix, zsuffix, ssuffix, _Tps, cast) \ +inline _Tpvec v_setzero_##suffix() { return _Tpvec(_mm_setzero_##zsuffix()); } \ +inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec(_mm_set1_##ssuffix((_Tps)v)); } \ +template inline _Tpvec v_reinterpret_as_##suffix(const _Tpvec0& a) \ +{ return _Tpvec(cast(a.val)); } + +OPENCV_HAL_IMPL_SSE_INITVEC(v_uint8x16, uchar, u8, si128, epi8, char, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_int8x16, schar, s8, si128, epi8, char, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_uint16x8, ushort, u16, si128, epi16, short, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_int16x8, short, s16, si128, epi16, short, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_uint32x4, unsigned, u32, si128, epi32, int, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_int32x4, int, s32, si128, epi32, int, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_float32x4, float, f32, ps, ps, float, _mm_castsi128_ps) +OPENCV_HAL_IMPL_SSE_INITVEC(v_float64x2, double, f64, pd, pd, double, _mm_castsi128_pd) + +inline v_uint64x2 v_setzero_u64() { return v_uint64x2(_mm_setzero_si128()); } +inline v_int64x2 v_setzero_s64() { return v_int64x2(_mm_setzero_si128()); } +inline v_uint64x2 v_setall_u64(uint64 val) { return v_uint64x2(val, val); } +inline v_int64x2 v_setall_s64(int64 val) { return v_int64x2(val, val); } + +template inline +v_uint64x2 v_reinterpret_as_u64(const _Tpvec& a) { return v_uint64x2(a.val); } +template inline +v_int64x2 v_reinterpret_as_s64(const _Tpvec& a) { return v_int64x2(a.val); } +inline v_float32x4 v_reinterpret_as_f32(const v_uint64x2& a) +{ return v_float32x4(_mm_castsi128_ps(a.val)); } +inline v_float32x4 v_reinterpret_as_f32(const v_int64x2& a) +{ return v_float32x4(_mm_castsi128_ps(a.val)); } +inline v_float64x2 v_reinterpret_as_f64(const v_uint64x2& a) +{ return v_float64x2(_mm_castsi128_pd(a.val)); } +inline v_float64x2 v_reinterpret_as_f64(const v_int64x2& a) +{ return v_float64x2(_mm_castsi128_pd(a.val)); } + +#define OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(_Tpvec, suffix) \ +inline _Tpvec v_reinterpret_as_##suffix(const v_float32x4& a) \ +{ return _Tpvec(_mm_castps_si128(a.val)); } \ +inline _Tpvec v_reinterpret_as_##suffix(const v_float64x2& a) \ +{ return _Tpvec(_mm_castpd_si128(a.val)); } + +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint8x16, u8) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int8x16, s8) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint16x8, u16) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int16x8, s16) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint32x4, u32) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int32x4, s32) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint64x2, u64) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int64x2, s64) + +inline v_float32x4 v_reinterpret_as_f32(const v_float32x4& a) {return a; } +inline v_float64x2 v_reinterpret_as_f64(const v_float64x2& a) {return a; } +inline v_float32x4 v_reinterpret_as_f32(const v_float64x2& a) {return v_float32x4(_mm_castpd_ps(a.val)); } +inline v_float64x2 v_reinterpret_as_f64(const v_float32x4& a) {return v_float64x2(_mm_castps_pd(a.val)); } + +//////////////// PACK /////////////// +inline v_uint8x16 v_pack(const v_uint16x8& a, const v_uint16x8& b) +{ + __m128i delta = _mm_set1_epi16(255); + return v_uint8x16(_mm_packus_epi16(_mm_subs_epu16(a.val, _mm_subs_epu16(a.val, delta)), + _mm_subs_epu16(b.val, _mm_subs_epu16(b.val, delta)))); +} + +inline void v_pack_store(uchar* ptr, const v_uint16x8& a) +{ + __m128i delta = _mm_set1_epi16(255); + __m128i a1 = _mm_subs_epu16(a.val, _mm_subs_epu16(a.val, delta)); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a1, a1)); +} + +inline v_uint8x16 v_pack_u(const v_int16x8& a, const v_int16x8& b) +{ return v_uint8x16(_mm_packus_epi16(a.val, b.val)); } + +inline void v_pack_u_store(uchar* ptr, const v_int16x8& a) +{ _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a.val, a.val)); } + +template inline +v_uint8x16 v_rshr_pack(const v_uint16x8& a, const v_uint16x8& b) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + return v_uint8x16(_mm_packus_epi16(_mm_srli_epi16(_mm_adds_epu16(a.val, delta), n), + _mm_srli_epi16(_mm_adds_epu16(b.val, delta), n))); +} + +template inline +void v_rshr_pack_store(uchar* ptr, const v_uint16x8& a) +{ + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + __m128i a1 = _mm_srli_epi16(_mm_adds_epu16(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a1, a1)); +} + +template inline +v_uint8x16 v_rshr_pack_u(const v_int16x8& a, const v_int16x8& b) +{ + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + return v_uint8x16(_mm_packus_epi16(_mm_srai_epi16(_mm_adds_epi16(a.val, delta), n), + _mm_srai_epi16(_mm_adds_epi16(b.val, delta), n))); +} + +template inline +void v_rshr_pack_u_store(uchar* ptr, const v_int16x8& a) +{ + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + __m128i a1 = _mm_srai_epi16(_mm_adds_epi16(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a1, a1)); +} + +inline v_int8x16 v_pack(const v_int16x8& a, const v_int16x8& b) +{ return v_int8x16(_mm_packs_epi16(a.val, b.val)); } + +inline void v_pack_store(schar* ptr, const v_int16x8& a) +{ _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi16(a.val, a.val)); } + +template inline +v_int8x16 v_rshr_pack(const v_int16x8& a, const v_int16x8& b) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + return v_int8x16(_mm_packs_epi16(_mm_srai_epi16(_mm_adds_epi16(a.val, delta), n), + _mm_srai_epi16(_mm_adds_epi16(b.val, delta), n))); +} +template inline +void v_rshr_pack_store(schar* ptr, const v_int16x8& a) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + __m128i a1 = _mm_srai_epi16(_mm_adds_epi16(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi16(a1, a1)); +} + + +// byte-wise "mask ? a : b" +inline __m128i v_select_si128(__m128i mask, __m128i a, __m128i b) +{ +#if CV_SSE4_1 + return _mm_blendv_epi8(b, a, mask); +#else + return _mm_xor_si128(b, _mm_and_si128(_mm_xor_si128(a, b), mask)); +#endif +} + +inline v_uint16x8 v_pack(const v_uint32x4& a, const v_uint32x4& b) +{ return v_uint16x8(_v128_packs_epu32(a.val, b.val)); } + +inline void v_pack_store(ushort* ptr, const v_uint32x4& a) +{ + __m128i z = _mm_setzero_si128(), maxval32 = _mm_set1_epi32(65535), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(v_select_si128(_mm_cmpgt_epi32(z, a.val), maxval32, a.val), delta32); + __m128i r = _mm_packs_epi32(a1, a1); + _mm_storel_epi64((__m128i*)ptr, _mm_sub_epi16(r, _mm_set1_epi16(-32768))); +} + +template inline +v_uint16x8 v_rshr_pack(const v_uint32x4& a, const v_uint32x4& b) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srli_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i b1 = _mm_sub_epi32(_mm_srli_epi32(_mm_add_epi32(b.val, delta), n), delta32); + return v_uint16x8(_mm_sub_epi16(_mm_packs_epi32(a1, b1), _mm_set1_epi16(-32768))); +} + +template inline +void v_rshr_pack_store(ushort* ptr, const v_uint32x4& a) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srli_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i a2 = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + _mm_storel_epi64((__m128i*)ptr, a2); +} + +inline v_uint16x8 v_pack_u(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + return v_uint16x8(_mm_packus_epi32(a.val, b.val)); +#else + __m128i delta32 = _mm_set1_epi32(32768); + + // preliminary saturate negative values to zero + __m128i a1 = _mm_and_si128(a.val, _mm_cmpgt_epi32(a.val, _mm_set1_epi32(0))); + __m128i b1 = _mm_and_si128(b.val, _mm_cmpgt_epi32(b.val, _mm_set1_epi32(0))); + + __m128i r = _mm_packs_epi32(_mm_sub_epi32(a1, delta32), _mm_sub_epi32(b1, delta32)); + return v_uint16x8(_mm_sub_epi16(r, _mm_set1_epi16(-32768))); +#endif +} + +inline void v_pack_u_store(ushort* ptr, const v_int32x4& a) +{ +#if CV_SSE4_1 + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi32(a.val, a.val)); +#else + __m128i delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(a.val, delta32); + __m128i r = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + _mm_storel_epi64((__m128i*)ptr, r); +#endif +} + +template inline +v_uint16x8 v_rshr_pack_u(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + __m128i delta = _mm_set1_epi32(1 << (n - 1)); + return v_uint16x8(_mm_packus_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), + _mm_srai_epi32(_mm_add_epi32(b.val, delta), n))); +#else + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i a2 = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + __m128i b1 = _mm_sub_epi32(_mm_srai_epi32(_mm_add_epi32(b.val, delta), n), delta32); + __m128i b2 = _mm_sub_epi16(_mm_packs_epi32(b1, b1), _mm_set1_epi16(-32768)); + return v_uint16x8(_mm_unpacklo_epi64(a2, b2)); +#endif +} + +template inline +void v_rshr_pack_u_store(ushort* ptr, const v_int32x4& a) +{ +#if CV_SSE4_1 + __m128i delta = _mm_set1_epi32(1 << (n - 1)); + __m128i a1 = _mm_srai_epi32(_mm_add_epi32(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi32(a1, a1)); +#else + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i a2 = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + _mm_storel_epi64((__m128i*)ptr, a2); +#endif +} + +inline v_int16x8 v_pack(const v_int32x4& a, const v_int32x4& b) +{ return v_int16x8(_mm_packs_epi32(a.val, b.val)); } + +inline void v_pack_store(short* ptr, const v_int32x4& a) +{ + _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi32(a.val, a.val)); +} + +template inline +v_int16x8 v_rshr_pack(const v_int32x4& a, const v_int32x4& b) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)); + return v_int16x8(_mm_packs_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), + _mm_srai_epi32(_mm_add_epi32(b.val, delta), n))); +} + +template inline +void v_rshr_pack_store(short* ptr, const v_int32x4& a) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)); + __m128i a1 = _mm_srai_epi32(_mm_add_epi32(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi32(a1, a1)); +} + + +// [a0 0 | b0 0] [a1 0 | b1 0] +inline v_uint32x4 v_pack(const v_uint64x2& a, const v_uint64x2& b) +{ + __m128i v0 = _mm_unpacklo_epi32(a.val, b.val); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a.val, b.val); // b0 b1 0 0 + return v_uint32x4(_mm_unpacklo_epi32(v0, v1)); +} + +inline void v_pack_store(unsigned* ptr, const v_uint64x2& a) +{ + __m128i a1 = _mm_shuffle_epi32(a.val, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a1); +} + +// [a0 0 | b0 0] [a1 0 | b1 0] +inline v_int32x4 v_pack(const v_int64x2& a, const v_int64x2& b) +{ + __m128i v0 = _mm_unpacklo_epi32(a.val, b.val); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a.val, b.val); // b0 b1 0 0 + return v_int32x4(_mm_unpacklo_epi32(v0, v1)); +} + +inline void v_pack_store(int* ptr, const v_int64x2& a) +{ + __m128i a1 = _mm_shuffle_epi32(a.val, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a1); +} + +template inline +v_uint32x4 v_rshr_pack(const v_uint64x2& a, const v_uint64x2& b) +{ + uint64 delta = (uint64)1 << (n-1); + v_uint64x2 delta2(delta, delta); + __m128i a1 = _mm_srli_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i b1 = _mm_srli_epi64(_mm_add_epi64(b.val, delta2.val), n); + __m128i v0 = _mm_unpacklo_epi32(a1, b1); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a1, b1); // b0 b1 0 0 + return v_uint32x4(_mm_unpacklo_epi32(v0, v1)); +} + +template inline +void v_rshr_pack_store(unsigned* ptr, const v_uint64x2& a) +{ + uint64 delta = (uint64)1 << (n-1); + v_uint64x2 delta2(delta, delta); + __m128i a1 = _mm_srli_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i a2 = _mm_shuffle_epi32(a1, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a2); +} + +inline __m128i v_sign_epi64(__m128i a) +{ + return _mm_shuffle_epi32(_mm_srai_epi32(a, 31), _MM_SHUFFLE(3, 3, 1, 1)); // x m0 | x m1 +} + +inline __m128i v_srai_epi64(__m128i a, int imm) +{ + __m128i smask = v_sign_epi64(a); + return _mm_xor_si128(_mm_srli_epi64(_mm_xor_si128(a, smask), imm), smask); +} + +template inline +v_int32x4 v_rshr_pack(const v_int64x2& a, const v_int64x2& b) +{ + int64 delta = (int64)1 << (n-1); + v_int64x2 delta2(delta, delta); + __m128i a1 = v_srai_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i b1 = v_srai_epi64(_mm_add_epi64(b.val, delta2.val), n); + __m128i v0 = _mm_unpacklo_epi32(a1, b1); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a1, b1); // b0 b1 0 0 + return v_int32x4(_mm_unpacklo_epi32(v0, v1)); +} + +template inline +void v_rshr_pack_store(int* ptr, const v_int64x2& a) +{ + int64 delta = (int64)1 << (n-1); + v_int64x2 delta2(delta, delta); + __m128i a1 = v_srai_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i a2 = _mm_shuffle_epi32(a1, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a2); +} + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + __m128i ab = _mm_packs_epi16(a.val, b.val); + return v_uint8x16(ab); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + __m128i ab = _mm_packs_epi32(a.val, b.val); + __m128i cd = _mm_packs_epi32(c.val, d.val); + return v_uint8x16(_mm_packs_epi16(ab, cd)); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + __m128i ab = _mm_packs_epi32(a.val, b.val); + __m128i cd = _mm_packs_epi32(c.val, d.val); + __m128i ef = _mm_packs_epi32(e.val, f.val); + __m128i gh = _mm_packs_epi32(g.val, h.val); + + __m128i abcd = _mm_packs_epi32(ab, cd); + __m128i efgh = _mm_packs_epi32(ef, gh); + return v_uint8x16(_mm_packs_epi16(abcd, efgh)); +} + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + __m128 v0 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(0, 0, 0, 0)), m0.val); + __m128 v1 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(1, 1, 1, 1)), m1.val); + __m128 v2 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(2, 2, 2, 2)), m2.val); + __m128 v3 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(3, 3, 3, 3)), m3.val); + + return v_float32x4(_mm_add_ps(_mm_add_ps(v0, v1), _mm_add_ps(v2, v3))); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + __m128 v0 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(0, 0, 0, 0)), m0.val); + __m128 v1 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(1, 1, 1, 1)), m1.val); + __m128 v2 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(2, 2, 2, 2)), m2.val); + + return v_float32x4(_mm_add_ps(_mm_add_ps(v0, v1), _mm_add_ps(v2, a.val))); +} + +#define OPENCV_HAL_IMPL_SSE_BIN_OP(bin_op, _Tpvec, intrin) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { \ + return _Tpvec(intrin(a.val, b.val)); \ + } \ + inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ + { \ + a.val = intrin(a.val, b.val); \ + return a; \ + } + +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint8x16, _mm_adds_epu8) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint8x16, _mm_subs_epu8) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int8x16, _mm_adds_epi8) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int8x16, _mm_subs_epi8) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint16x8, _mm_adds_epu16) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint16x8, _mm_subs_epu16) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int16x8, _mm_adds_epi16) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int16x8, _mm_subs_epi16) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint32x4, _mm_add_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint32x4, _mm_sub_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_uint32x4, _v128_mullo_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int32x4, _mm_add_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int32x4, _mm_sub_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_int32x4, _v128_mullo_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_float32x4, _mm_add_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_float32x4, _mm_sub_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_float32x4, _mm_mul_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(/, v_float32x4, _mm_div_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_float64x2, _mm_add_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_float64x2, _mm_sub_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_float64x2, _mm_mul_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(/, v_float64x2, _mm_div_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint64x2, _mm_add_epi64) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint64x2, _mm_sub_epi64) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int64x2, _mm_add_epi64) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int64x2, _mm_sub_epi64) + +// saturating multiply 8-bit, 16-bit +#define OPENCV_HAL_IMPL_SSE_MUL_SAT(_Tpvec, _Tpwvec) \ + inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ + { \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ + } \ + inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ + { a = a * b; return a; } + +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_uint16x8, v_uint32x4) +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_int16x8, v_int32x4) + +// Multiply and expand +inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b, + v_uint16x8& c, v_uint16x8& d) +{ + v_uint16x8 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b, + v_int16x8& c, v_int16x8& d) +{ + v_int16x8 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, + v_int32x4& c, v_int32x4& d) +{ + __m128i v0 = _mm_mullo_epi16(a.val, b.val); + __m128i v1 = _mm_mulhi_epi16(a.val, b.val); + c.val = _mm_unpacklo_epi16(v0, v1); + d.val = _mm_unpackhi_epi16(v0, v1); +} + +inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, + v_uint32x4& c, v_uint32x4& d) +{ + __m128i v0 = _mm_mullo_epi16(a.val, b.val); + __m128i v1 = _mm_mulhi_epu16(a.val, b.val); + c.val = _mm_unpacklo_epi16(v0, v1); + d.val = _mm_unpackhi_epi16(v0, v1); +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, + v_uint64x2& c, v_uint64x2& d) +{ + __m128i c0 = _mm_mul_epu32(a.val, b.val); + __m128i c1 = _mm_mul_epu32(_mm_srli_epi64(a.val, 32), _mm_srli_epi64(b.val, 32)); + c.val = _mm_unpacklo_epi64(c0, c1); + d.val = _mm_unpackhi_epi64(c0, c1); +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) { return v_int16x8(_mm_mulhi_epi16(a.val, b.val)); } +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) { return v_uint16x8(_mm_mulhi_epu16(a.val, b.val)); } + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ + return v_int32x4(_mm_madd_epi16(a.val, b.val)); +} + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ + return v_int32x4(_mm_add_epi32(_mm_madd_epi16(a.val, b.val), c.val)); +} + +#define OPENCV_HAL_IMPL_SSE_LOGIC_OP(_Tpvec, suffix, not_const) \ + OPENCV_HAL_IMPL_SSE_BIN_OP(&, _Tpvec, _mm_and_##suffix) \ + OPENCV_HAL_IMPL_SSE_BIN_OP(|, _Tpvec, _mm_or_##suffix) \ + OPENCV_HAL_IMPL_SSE_BIN_OP(^, _Tpvec, _mm_xor_##suffix) \ + inline _Tpvec operator ~ (const _Tpvec& a) \ + { \ + return _Tpvec(_mm_xor_##suffix(a.val, not_const)); \ + } + +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint8x16, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int8x16, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint16x8, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int16x8, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint32x4, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int32x4, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint64x2, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int64x2, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_float32x4, ps, _mm_castsi128_ps(_mm_set1_epi32(-1))) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_float64x2, pd, _mm_castsi128_pd(_mm_set1_epi32(-1))) + +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ return v_float32x4(_mm_sqrt_ps(x.val)); } + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + const __m128 _0_5 = _mm_set1_ps(0.5f), _1_5 = _mm_set1_ps(1.5f); + __m128 t = x.val; + __m128 h = _mm_mul_ps(t, _0_5); + t = _mm_rsqrt_ps(t); + t = _mm_mul_ps(t, _mm_sub_ps(_1_5, _mm_mul_ps(_mm_mul_ps(t, t), h))); + return v_float32x4(t); +} + +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ return v_float64x2(_mm_sqrt_pd(x.val)); } + +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ + const __m128d v_1 = _mm_set1_pd(1.); + return v_float64x2(_mm_div_pd(v_1, _mm_sqrt_pd(x.val))); +} + +#define OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(_Tpuvec, _Tpsvec, func, suffix, subWidth) \ +inline _Tpuvec v_abs(const _Tpsvec& x) \ +{ return _Tpuvec(_mm_##func##_ep##suffix(x.val, _mm_sub_ep##subWidth(_mm_setzero_si128(), x.val))); } + +OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(v_uint8x16, v_int8x16, min, u8, i8) +OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(v_uint16x8, v_int16x8, max, i16, i16) +inline v_uint32x4 v_abs(const v_int32x4& x) +{ + __m128i s = _mm_srli_epi32(x.val, 31); + __m128i f = _mm_srai_epi32(x.val, 31); + return v_uint32x4(_mm_add_epi32(_mm_xor_si128(x.val, f), s)); +} +inline v_float32x4 v_abs(const v_float32x4& x) +{ return v_float32x4(_mm_and_ps(x.val, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)))); } +inline v_float64x2 v_abs(const v_float64x2& x) +{ + return v_float64x2(_mm_and_pd(x.val, + _mm_castsi128_pd(_mm_srli_epi64(_mm_set1_epi32(-1), 1)))); +} + +// TODO: exp, log, sin, cos + +#define OPENCV_HAL_IMPL_SSE_BIN_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_min, _mm_min_epu8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_max, _mm_max_epu8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_min, _mm_min_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_max, _mm_max_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float32x4, v_min, _mm_min_ps) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float32x4, v_max, _mm_max_ps) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float64x2, v_min, _mm_min_pd) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float64x2, v_max, _mm_max_pd) + +inline v_int8x16 v_min(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_SSE4_1 + return v_int8x16(_mm_min_epi8(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi8((char)-128); + return v_int8x16(_mm_xor_si128(delta, _mm_min_epu8(_mm_xor_si128(a.val, delta), + _mm_xor_si128(b.val, delta)))); +#endif +} +inline v_int8x16 v_max(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_SSE4_1 + return v_int8x16(_mm_max_epi8(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi8((char)-128); + return v_int8x16(_mm_xor_si128(delta, _mm_max_epu8(_mm_xor_si128(a.val, delta), + _mm_xor_si128(b.val, delta)))); +#endif +} +inline v_uint16x8 v_min(const v_uint16x8& a, const v_uint16x8& b) +{ +#if CV_SSE4_1 + return v_uint16x8(_mm_min_epu16(a.val, b.val)); +#else + return v_uint16x8(_mm_subs_epu16(a.val, _mm_subs_epu16(a.val, b.val))); +#endif +} +inline v_uint16x8 v_max(const v_uint16x8& a, const v_uint16x8& b) +{ +#if CV_SSE4_1 + return v_uint16x8(_mm_max_epu16(a.val, b.val)); +#else + return v_uint16x8(_mm_adds_epu16(_mm_subs_epu16(a.val, b.val), b.val)); +#endif +} +inline v_uint32x4 v_min(const v_uint32x4& a, const v_uint32x4& b) +{ +#if CV_SSE4_1 + return v_uint32x4(_mm_min_epu32(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi32((int)0x80000000); + __m128i mask = _mm_cmpgt_epi32(_mm_xor_si128(a.val, delta), _mm_xor_si128(b.val, delta)); + return v_uint32x4(v_select_si128(mask, b.val, a.val)); +#endif +} +inline v_uint32x4 v_max(const v_uint32x4& a, const v_uint32x4& b) +{ +#if CV_SSE4_1 + return v_uint32x4(_mm_max_epu32(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi32((int)0x80000000); + __m128i mask = _mm_cmpgt_epi32(_mm_xor_si128(a.val, delta), _mm_xor_si128(b.val, delta)); + return v_uint32x4(v_select_si128(mask, a.val, b.val)); +#endif +} +inline v_int32x4 v_min(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + return v_int32x4(_mm_min_epi32(a.val, b.val)); +#else + return v_int32x4(v_select_si128(_mm_cmpgt_epi32(a.val, b.val), b.val, a.val)); +#endif +} +inline v_int32x4 v_max(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + return v_int32x4(_mm_max_epi32(a.val, b.val)); +#else + return v_int32x4(v_select_si128(_mm_cmpgt_epi32(a.val, b.val), a.val, b.val)); +#endif +} + +#define OPENCV_HAL_IMPL_SSE_INT_CMP_OP(_Tpuvec, _Tpsvec, suffix, sbit) \ +inline _Tpuvec operator == (const _Tpuvec& a, const _Tpuvec& b) \ +{ return _Tpuvec(_mm_cmpeq_##suffix(a.val, b.val)); } \ +inline _Tpuvec operator != (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpuvec(_mm_xor_si128(_mm_cmpeq_##suffix(a.val, b.val), not_mask)); \ +} \ +inline _Tpsvec operator == (const _Tpsvec& a, const _Tpsvec& b) \ +{ return _Tpsvec(_mm_cmpeq_##suffix(a.val, b.val)); } \ +inline _Tpsvec operator != (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpsvec(_mm_xor_si128(_mm_cmpeq_##suffix(a.val, b.val), not_mask)); \ +} \ +inline _Tpuvec operator < (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + return _Tpuvec(_mm_cmpgt_##suffix(_mm_xor_si128(b.val, smask), _mm_xor_si128(a.val, smask))); \ +} \ +inline _Tpuvec operator > (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + return _Tpuvec(_mm_cmpgt_##suffix(_mm_xor_si128(a.val, smask), _mm_xor_si128(b.val, smask))); \ +} \ +inline _Tpuvec operator <= (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + __m128i not_mask = _mm_set1_epi32(-1); \ + __m128i res = _mm_cmpgt_##suffix(_mm_xor_si128(a.val, smask), _mm_xor_si128(b.val, smask)); \ + return _Tpuvec(_mm_xor_si128(res, not_mask)); \ +} \ +inline _Tpuvec operator >= (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + __m128i not_mask = _mm_set1_epi32(-1); \ + __m128i res = _mm_cmpgt_##suffix(_mm_xor_si128(b.val, smask), _mm_xor_si128(a.val, smask)); \ + return _Tpuvec(_mm_xor_si128(res, not_mask)); \ +} \ +inline _Tpsvec operator < (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + return _Tpsvec(_mm_cmpgt_##suffix(b.val, a.val)); \ +} \ +inline _Tpsvec operator > (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + return _Tpsvec(_mm_cmpgt_##suffix(a.val, b.val)); \ +} \ +inline _Tpsvec operator <= (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpsvec(_mm_xor_si128(_mm_cmpgt_##suffix(a.val, b.val), not_mask)); \ +} \ +inline _Tpsvec operator >= (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpsvec(_mm_xor_si128(_mm_cmpgt_##suffix(b.val, a.val), not_mask)); \ +} + +OPENCV_HAL_IMPL_SSE_INT_CMP_OP(v_uint8x16, v_int8x16, epi8, (char)-128) +OPENCV_HAL_IMPL_SSE_INT_CMP_OP(v_uint16x8, v_int16x8, epi16, (short)-32768) +OPENCV_HAL_IMPL_SSE_INT_CMP_OP(v_uint32x4, v_int32x4, epi32, (int)0x80000000) + +#define OPENCV_HAL_IMPL_SSE_FLT_CMP_OP(_Tpvec, suffix) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpeq_##suffix(a.val, b.val)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpneq_##suffix(a.val, b.val)); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmplt_##suffix(a.val, b.val)); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpgt_##suffix(a.val, b.val)); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmple_##suffix(a.val, b.val)); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpge_##suffix(a.val, b.val)); } + +OPENCV_HAL_IMPL_SSE_FLT_CMP_OP(v_float32x4, ps) +OPENCV_HAL_IMPL_SSE_FLT_CMP_OP(v_float64x2, pd) + +#define OPENCV_HAL_IMPL_SSE_64BIT_CMP_OP(_Tpvec, cast) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return cast(v_reinterpret_as_f64(a) == v_reinterpret_as_f64(b)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return cast(v_reinterpret_as_f64(a) != v_reinterpret_as_f64(b)); } + +OPENCV_HAL_IMPL_SSE_64BIT_CMP_OP(v_uint64x2, v_reinterpret_as_u64) +OPENCV_HAL_IMPL_SSE_64BIT_CMP_OP(v_int64x2, v_reinterpret_as_s64) + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return v_float32x4(_mm_cmpord_ps(a.val, a.val)); } +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return v_float64x2(_mm_cmpord_pd(a.val, a.val)); } + +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_add_wrap, _mm_add_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int8x16, v_add_wrap, _mm_add_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_add_wrap, _mm_add_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_add_wrap, _mm_add_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_sub_wrap, _mm_sub_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int8x16, v_sub_wrap, _mm_sub_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_sub_wrap, _mm_sub_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_sub_wrap, _mm_sub_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_mul_wrap, _mm_mullo_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_mul_wrap, _mm_mullo_epi16) + +inline v_uint8x16 v_mul_wrap(const v_uint8x16& a, const v_uint8x16& b) +{ + __m128i ad = _mm_srai_epi16(a.val, 8); + __m128i bd = _mm_srai_epi16(b.val, 8); + __m128i p0 = _mm_mullo_epi16(a.val, b.val); // even + __m128i p1 = _mm_slli_epi16(_mm_mullo_epi16(ad, bd), 8); // odd + const __m128i b01 = _mm_set1_epi32(0xFF00FF00); + return v_uint8x16(_v128_blendv_epi8(p0, p1, b01)); +} +inline v_int8x16 v_mul_wrap(const v_int8x16& a, const v_int8x16& b) +{ + return v_reinterpret_as_s8(v_mul_wrap(v_reinterpret_as_u8(a), v_reinterpret_as_u8(b))); +} + +/** Absolute difference **/ + +inline v_uint8x16 v_absdiff(const v_uint8x16& a, const v_uint8x16& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint16x8 v_absdiff(const v_uint16x8& a, const v_uint16x8& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint32x4 v_absdiff(const v_uint32x4& a, const v_uint32x4& b) +{ return v_max(a, b) - v_min(a, b); } + +inline v_uint8x16 v_absdiff(const v_int8x16& a, const v_int8x16& b) +{ + v_int8x16 d = v_sub_wrap(a, b); + v_int8x16 m = a < b; + return v_reinterpret_as_u8(v_sub_wrap(d ^ m, m)); +} +inline v_uint16x8 v_absdiff(const v_int16x8& a, const v_int16x8& b) +{ + return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); +} +inline v_uint32x4 v_absdiff(const v_int32x4& a, const v_int32x4& b) +{ + v_int32x4 d = a - b; + v_int32x4 m = a < b; + return v_reinterpret_as_u32((d ^ m) - m); +} + +/** Saturating absolute difference **/ +inline v_int8x16 v_absdiffs(const v_int8x16& a, const v_int8x16& b) +{ + v_int8x16 d = a - b; + v_int8x16 m = a < b; + return (d ^ m) - m; + } +inline v_int16x8 v_absdiffs(const v_int16x8& a, const v_int16x8& b) +{ return v_max(a, b) - v_min(a, b); } + + +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return a * b + c; +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ +#if CV_FMA3 + return v_float32x4(_mm_fmadd_ps(a.val, b.val, c.val)); +#else + return v_float32x4(_mm_add_ps(_mm_mul_ps(a.val, b.val), c.val)); +#endif +} + +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ +#if CV_FMA3 + return v_float64x2(_mm_fmadd_pd(a.val, b.val, c.val)); +#else + return v_float64x2(_mm_add_pd(_mm_mul_pd(a.val, b.val), c.val)); +#endif +} + +#define OPENCV_HAL_IMPL_SSE_MISC_FLT_OP(_Tpvec, _Tp, _Tpreg, suffix, absmask_vec) \ +inline _Tpvec v_absdiff(const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpreg absmask = _mm_castsi128_##suffix(absmask_vec); \ + return _Tpvec(_mm_and_##suffix(_mm_sub_##suffix(a.val, b.val), absmask)); \ +} \ +inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpvec res = v_fma(a, a, b*b); \ + return _Tpvec(_mm_sqrt_##suffix(res.val)); \ +} \ +inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return v_fma(a, a, b*b); \ +} \ +inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ +{ \ + return v_fma(a, b, c); \ +} + +OPENCV_HAL_IMPL_SSE_MISC_FLT_OP(v_float32x4, float, __m128, ps, _mm_set1_epi32((int)0x7fffffff)) +OPENCV_HAL_IMPL_SSE_MISC_FLT_OP(v_float64x2, double, __m128d, pd, _mm_srli_epi64(_mm_set1_epi32(-1), 1)) + +#define OPENCV_HAL_IMPL_SSE_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, srai) \ +inline _Tpuvec operator << (const _Tpuvec& a, int imm) \ +{ \ + return _Tpuvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +inline _Tpsvec operator << (const _Tpsvec& a, int imm) \ +{ \ + return _Tpsvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +inline _Tpuvec operator >> (const _Tpuvec& a, int imm) \ +{ \ + return _Tpuvec(_mm_srli_##suffix(a.val, imm)); \ +} \ +inline _Tpsvec operator >> (const _Tpsvec& a, int imm) \ +{ \ + return _Tpsvec(srai(a.val, imm)); \ +} \ +template \ +inline _Tpuvec v_shl(const _Tpuvec& a) \ +{ \ + return _Tpuvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +template \ +inline _Tpsvec v_shl(const _Tpsvec& a) \ +{ \ + return _Tpsvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +template \ +inline _Tpuvec v_shr(const _Tpuvec& a) \ +{ \ + return _Tpuvec(_mm_srli_##suffix(a.val, imm)); \ +} \ +template \ +inline _Tpsvec v_shr(const _Tpsvec& a) \ +{ \ + return _Tpsvec(srai(a.val, imm)); \ +} + +OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint16x8, v_int16x8, epi16, _mm_srai_epi16) +OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint32x4, v_int32x4, epi32, _mm_srai_epi32) +OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint64x2, v_int64x2, epi64, v_srai_epi64) + +namespace hal_sse_internal +{ + template 16)), + bool is_first = (imm == 0), + bool is_half = (imm == 8), + bool is_second = (imm == 16), + bool is_other = (((imm > 0) && (imm < 8)) || ((imm > 8) && (imm < 16)))> + class v_sse_palignr_u8_class; + + template + class v_sse_palignr_u8_class; + + template + class v_sse_palignr_u8_class + { + public: + inline __m128i operator()(const __m128i& a, const __m128i&) const + { + return a; + } + }; + + template + class v_sse_palignr_u8_class + { + public: + inline __m128i operator()(const __m128i& a, const __m128i& b) const + { + return _mm_unpacklo_epi64(_mm_unpackhi_epi64(a, a), b); + } + }; + + template + class v_sse_palignr_u8_class + { + public: + inline __m128i operator()(const __m128i&, const __m128i& b) const + { + return b; + } + }; + + template + class v_sse_palignr_u8_class + { +#if CV_SSSE3 + public: + inline __m128i operator()(const __m128i& a, const __m128i& b) const + { + return _mm_alignr_epi8(b, a, imm); + } +#else + public: + inline __m128i operator()(const __m128i& a, const __m128i& b) const + { + enum { imm2 = (sizeof(__m128i) - imm) }; + return _mm_or_si128(_mm_srli_si128(a, imm), _mm_slli_si128(b, imm2)); + } +#endif + }; + + template + inline __m128i v_sse_palignr_u8(const __m128i& a, const __m128i& b) + { + CV_StaticAssert((imm >= 0) && (imm <= 16), "Invalid imm for v_sse_palignr_u8."); + return v_sse_palignr_u8_class()(a, b); + } +} + +template +inline _Tpvec v_rotate_right(const _Tpvec &a) +{ + using namespace hal_sse_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + _mm_srli_si128( + v_sse_reinterpret_as<__m128i>(a.val), imm2))); +} + +template +inline _Tpvec v_rotate_left(const _Tpvec &a) +{ + using namespace hal_sse_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + _mm_slli_si128( + v_sse_reinterpret_as<__m128i>(a.val), imm2))); +} + +template +inline _Tpvec v_rotate_right(const _Tpvec &a, const _Tpvec &b) +{ + using namespace hal_sse_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + v_sse_palignr_u8( + v_sse_reinterpret_as<__m128i>(a.val), + v_sse_reinterpret_as<__m128i>(b.val)))); +} + +template +inline _Tpvec v_rotate_left(const _Tpvec &a, const _Tpvec &b) +{ + using namespace hal_sse_internal; + enum { imm2 = ((_Tpvec::nlanes - imm) * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + v_sse_palignr_u8( + v_sse_reinterpret_as<__m128i>(b.val), + v_sse_reinterpret_as<__m128i>(a.val)))); +} + +#define OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(_Tpvec, _Tp) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(_mm_loadu_si128((const __m128i*)ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(_mm_load_si128((const __m128i*)ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(_mm_loadl_epi64((const __m128i*)ptr)); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ \ + return _Tpvec(_mm_unpacklo_epi64(_mm_loadl_epi64((const __m128i*)ptr0), \ + _mm_loadl_epi64((const __m128i*)ptr1))); \ +} \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storeu_si128((__m128i*)ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ _mm_store_si128((__m128i*)ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ _mm_stream_si128((__m128i*)ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ +{ \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm_storeu_si128((__m128i*)ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm_stream_si128((__m128i*)ptr, a.val); \ + else \ + _mm_store_si128((__m128i*)ptr, a.val); \ +} \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storel_epi64((__m128i*)ptr, a.val); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storel_epi64((__m128i*)ptr, _mm_unpackhi_epi64(a.val, a.val)); } + +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint8x16, uchar) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int8x16, schar) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint16x8, ushort) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int16x8, short) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint32x4, unsigned) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int32x4, int) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint64x2, uint64) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int64x2, int64) + +#define OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(_mm_loadu_##suffix(ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(_mm_load_##suffix(ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(_mm_castsi128_##suffix(_mm_loadl_epi64((const __m128i*)ptr))); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ \ + return _Tpvec(_mm_castsi128_##suffix( \ + _mm_unpacklo_epi64(_mm_loadl_epi64((const __m128i*)ptr0), \ + _mm_loadl_epi64((const __m128i*)ptr1)))); \ +} \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storeu_##suffix(ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ _mm_store_##suffix(ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ _mm_stream_##suffix(ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ +{ \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm_storeu_##suffix(ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm_stream_##suffix(ptr, a.val); \ + else \ + _mm_store_##suffix(ptr, a.val); \ +} \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storel_epi64((__m128i*)ptr, _mm_cast##suffix##_si128(a.val)); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ \ + __m128i a1 = _mm_cast##suffix##_si128(a.val); \ + _mm_storel_epi64((__m128i*)ptr, _mm_unpackhi_epi64(a1, a1)); \ +} + +OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float32x4, float, ps) +OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float64x2, double, pd) + +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(_Tpvec, scalartype, func, suffix, sbit) \ +inline scalartype v_reduce_##func(const v_##_Tpvec& a) \ +{ \ + __m128i val = a.val; \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,8)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,4)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,2)); \ + return (scalartype)_mm_cvtsi128_si32(val); \ +} \ +inline unsigned scalartype v_reduce_##func(const v_u##_Tpvec& a) \ +{ \ + __m128i val = a.val; \ + __m128i smask = _mm_set1_epi16(sbit); \ + val = _mm_xor_si128(val, smask); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,8)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,4)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,2)); \ + return (unsigned scalartype)(_mm_cvtsi128_si32(val) ^ sbit); \ +} +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_8_SUM(_Tpvec, scalartype, suffix) \ +inline scalartype v_reduce_sum(const v_##_Tpvec& a) \ +{ \ + __m128i val = a.val; \ + val = _mm_adds_epi##suffix(val, _mm_srli_si128(val, 8)); \ + val = _mm_adds_epi##suffix(val, _mm_srli_si128(val, 4)); \ + val = _mm_adds_epi##suffix(val, _mm_srli_si128(val, 2)); \ + return (scalartype)_mm_cvtsi128_si32(val); \ +} \ +inline unsigned scalartype v_reduce_sum(const v_u##_Tpvec& a) \ +{ \ + __m128i val = a.val; \ + val = _mm_adds_epu##suffix(val, _mm_srli_si128(val, 8)); \ + val = _mm_adds_epu##suffix(val, _mm_srli_si128(val, 4)); \ + val = _mm_adds_epu##suffix(val, _mm_srli_si128(val, 2)); \ + return (unsigned scalartype)_mm_cvtsi128_si32(val); \ +} +OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(int16x8, short, max, epi16, (short)-32768) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(int16x8, short, min, epi16, (short)-32768) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_8_SUM(int16x8, short, 16) + +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(_Tpvec, scalartype, regtype, suffix, cast_from, cast_to, extract) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + regtype val = a.val; \ + val = _mm_add_##suffix(val, cast_to(_mm_srli_si128(cast_from(val), 8))); \ + val = _mm_add_##suffix(val, cast_to(_mm_srli_si128(cast_from(val), 4))); \ + return (scalartype)_mm_cvt##extract(val); \ +} + +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(_Tpvec, scalartype, func, scalar_func) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + scalartype CV_DECL_ALIGNED(16) buf[4]; \ + v_store_aligned(buf, a); \ + scalartype s0 = scalar_func(buf[0], buf[1]); \ + scalartype s1 = scalar_func(buf[2], buf[3]); \ + return scalar_func(s0, s1); \ +} + +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(v_uint32x4, unsigned, __m128i, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP, si128_si32) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(v_int32x4, int, __m128i, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP, si128_si32) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(v_float32x4, float, __m128, ps, _mm_castps_si128, _mm_castsi128_ps, ss_f32) + +inline double v_reduce_sum(const v_float64x2& a) +{ + double CV_DECL_ALIGNED(32) idx[2]; + v_store_aligned(idx, a); + return idx[0] + idx[1]; +} + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ +#if CV_SSE3 + __m128 ab = _mm_hadd_ps(a.val, b.val); + __m128 cd = _mm_hadd_ps(c.val, d.val); + return v_float32x4(_mm_hadd_ps(ab, cd)); +#else + __m128 ac = _mm_add_ps(_mm_unpacklo_ps(a.val, c.val), _mm_unpackhi_ps(a.val, c.val)); + __m128 bd = _mm_add_ps(_mm_unpacklo_ps(b.val, d.val), _mm_unpackhi_ps(b.val, d.val)); + return v_float32x4(_mm_add_ps(_mm_unpacklo_ps(ac, bd), _mm_unpackhi_ps(ac, bd))); +#endif +} + +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_uint32x4, unsigned, max, std::max) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_uint32x4, unsigned, min, std::min) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_int32x4, int, max, std::max) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_int32x4, int, min, std::min) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_float32x4, float, max, std::max) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_float32x4, float, min, std::min) + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ + return (unsigned)_mm_cvtsi128_si32(_mm_sad_epu8(a.val, b.val)); +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ + __m128i half = _mm_set1_epi8(0x7f); + return (unsigned)_mm_cvtsi128_si32(_mm_sad_epu8(_mm_add_epi8(a.val, half), + _mm_add_epi8(b.val, half))); +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ + v_uint32x4 l, h; + v_expand(v_absdiff(a, b), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ + v_uint32x4 l, h; + v_expand(v_absdiff(a, b), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} + +#define OPENCV_HAL_IMPL_SSE_POPCOUNT(_Tpvec) \ +inline v_uint32x4 v_popcount(const _Tpvec& a) \ +{ \ + __m128i m1 = _mm_set1_epi32(0x55555555); \ + __m128i m2 = _mm_set1_epi32(0x33333333); \ + __m128i m4 = _mm_set1_epi32(0x0f0f0f0f); \ + __m128i p = a.val; \ + p = _mm_add_epi32(_mm_and_si128(_mm_srli_epi32(p, 1), m1), _mm_and_si128(p, m1)); \ + p = _mm_add_epi32(_mm_and_si128(_mm_srli_epi32(p, 2), m2), _mm_and_si128(p, m2)); \ + p = _mm_add_epi32(_mm_and_si128(_mm_srli_epi32(p, 4), m4), _mm_and_si128(p, m4)); \ + p = _mm_adds_epi8(p, _mm_srli_si128(p, 1)); \ + p = _mm_adds_epi8(p, _mm_srli_si128(p, 2)); \ + return v_uint32x4(_mm_and_si128(p, _mm_set1_epi32(0x000000ff))); \ +} + +OPENCV_HAL_IMPL_SSE_POPCOUNT(v_uint8x16) +OPENCV_HAL_IMPL_SSE_POPCOUNT(v_uint16x8) +OPENCV_HAL_IMPL_SSE_POPCOUNT(v_uint32x4) +OPENCV_HAL_IMPL_SSE_POPCOUNT(v_int8x16) +OPENCV_HAL_IMPL_SSE_POPCOUNT(v_int16x8) +OPENCV_HAL_IMPL_SSE_POPCOUNT(v_int32x4) + +#define OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(_Tpvec, suffix, pack_op, and_op, signmask, allmask) \ +inline int v_signmask(const _Tpvec& a) \ +{ \ + return and_op(_mm_movemask_##suffix(pack_op(a.val)), signmask); \ +} \ +inline bool v_check_all(const _Tpvec& a) \ +{ return and_op(_mm_movemask_##suffix(a.val), allmask) == allmask; } \ +inline bool v_check_any(const _Tpvec& a) \ +{ return and_op(_mm_movemask_##suffix(a.val), allmask) != 0; } + +#define OPENCV_HAL_PACKS(a) _mm_packs_epi16(a, a) +inline __m128i v_packq_epi32(__m128i a) +{ + __m128i b = _mm_packs_epi32(a, a); + return _mm_packs_epi16(b, b); +} + +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 65535, 65535) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 65535, 65535) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint16x8, epi8, OPENCV_HAL_PACKS, OPENCV_HAL_AND, 255, (int)0xaaaa) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int16x8, epi8, OPENCV_HAL_PACKS, OPENCV_HAL_AND, 255, (int)0xaaaa) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint32x4, epi8, v_packq_epi32, OPENCV_HAL_AND, 15, (int)0x8888) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int32x4, epi8, v_packq_epi32, OPENCV_HAL_AND, 15, (int)0x8888) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float32x4, ps, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 15, 15) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float64x2, pd, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 3, 3) + +#if CV_SSE4_1 +#define OPENCV_HAL_IMPL_SSE_SELECT(_Tpvec, cast_ret, cast, suffix) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(cast_ret(_mm_blendv_##suffix(cast(b.val), cast(a.val), cast(mask.val)))); \ +} + +OPENCV_HAL_IMPL_SSE_SELECT(v_uint8x16, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_int8x16, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint16x8, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_int16x8, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint32x4, _mm_castps_si128, _mm_castsi128_ps, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_int32x4, _mm_castps_si128, _mm_castsi128_ps, ps) +// OPENCV_HAL_IMPL_SSE_SELECT(v_uint64x2, TBD, TBD, pd) +// OPENCV_HAL_IMPL_SSE_SELECT(v_int64x2, TBD, TBD, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_float32x4, OPENCV_HAL_NOP, OPENCV_HAL_NOP, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_float64x2, OPENCV_HAL_NOP, OPENCV_HAL_NOP, pd) + +#else // CV_SSE4_1 + +#define OPENCV_HAL_IMPL_SSE_SELECT(_Tpvec, suffix) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(_mm_xor_##suffix(b.val, _mm_and_##suffix(_mm_xor_##suffix(b.val, a.val), mask.val))); \ +} + +OPENCV_HAL_IMPL_SSE_SELECT(v_uint8x16, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_int8x16, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint16x8, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_int16x8, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint32x4, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_int32x4, si128) +// OPENCV_HAL_IMPL_SSE_SELECT(v_uint64x2, si128) +// OPENCV_HAL_IMPL_SSE_SELECT(v_int64x2, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_float32x4, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_float64x2, pd) +#endif + +/* Expand */ +#define OPENCV_HAL_IMPL_SSE_EXPAND(_Tpvec, _Tpwvec, _Tp, intrin) \ + inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ + { \ + b0.val = intrin(a.val); \ + b1.val = __CV_CAT(intrin, _high)(a.val); \ + } \ + inline _Tpwvec v_expand_low(const _Tpvec& a) \ + { return _Tpwvec(intrin(a.val)); } \ + inline _Tpwvec v_expand_high(const _Tpvec& a) \ + { return _Tpwvec(__CV_CAT(intrin, _high)(a.val)); } \ + inline _Tpwvec v_load_expand(const _Tp* ptr) \ + { \ + __m128i a = _mm_loadl_epi64((const __m128i*)ptr); \ + return _Tpwvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_SSE_EXPAND(v_uint8x16, v_uint16x8, uchar, _v128_cvtepu8_epi16) +OPENCV_HAL_IMPL_SSE_EXPAND(v_int8x16, v_int16x8, schar, _v128_cvtepi8_epi16) +OPENCV_HAL_IMPL_SSE_EXPAND(v_uint16x8, v_uint32x4, ushort, _v128_cvtepu16_epi32) +OPENCV_HAL_IMPL_SSE_EXPAND(v_int16x8, v_int32x4, short, _v128_cvtepi16_epi32) +OPENCV_HAL_IMPL_SSE_EXPAND(v_uint32x4, v_uint64x2, unsigned, _v128_cvtepu32_epi64) +OPENCV_HAL_IMPL_SSE_EXPAND(v_int32x4, v_int64x2, int, _v128_cvtepi32_epi64) + +#define OPENCV_HAL_IMPL_SSE_EXPAND_Q(_Tpvec, _Tp, intrin) \ + inline _Tpvec v_load_expand_q(const _Tp* ptr) \ + { \ + __m128i a = _mm_cvtsi32_si128(*(const int*)ptr); \ + return _Tpvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_SSE_EXPAND_Q(v_uint32x4, uchar, _v128_cvtepu8_epi32) +OPENCV_HAL_IMPL_SSE_EXPAND_Q(v_int32x4, schar, _v128_cvtepi8_epi32) + +#define OPENCV_HAL_IMPL_SSE_UNPACKS(_Tpvec, suffix, cast_from, cast_to) \ +inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, _Tpvec& b0, _Tpvec& b1) \ +{ \ + b0.val = _mm_unpacklo_##suffix(a0.val, a1.val); \ + b1.val = _mm_unpackhi_##suffix(a0.val, a1.val); \ +} \ +inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ +{ \ + __m128i a1 = cast_from(a.val), b1 = cast_from(b.val); \ + return _Tpvec(cast_to(_mm_unpacklo_epi64(a1, b1))); \ +} \ +inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ +{ \ + __m128i a1 = cast_from(a.val), b1 = cast_from(b.val); \ + return _Tpvec(cast_to(_mm_unpackhi_epi64(a1, b1))); \ +} \ +inline void v_recombine(const _Tpvec& a, const _Tpvec& b, _Tpvec& c, _Tpvec& d) \ +{ \ + __m128i a1 = cast_from(a.val), b1 = cast_from(b.val); \ + c.val = cast_to(_mm_unpacklo_epi64(a1, b1)); \ + d.val = cast_to(_mm_unpackhi_epi64(a1, b1)); \ +} + +OPENCV_HAL_IMPL_SSE_UNPACKS(v_uint8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_int8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_uint16x8, epi16, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_int16x8, epi16, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_uint32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_int32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_float32x4, ps, _mm_castps_si128, _mm_castsi128_ps) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_float64x2, pd, _mm_castpd_si128, _mm_castsi128_pd) + +template +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) +{ + return v_rotate_right(a, b); +} + +inline v_int32x4 v_round(const v_float32x4& a) +{ return v_int32x4(_mm_cvtps_epi32(a.val)); } + +inline v_int32x4 v_floor(const v_float32x4& a) +{ + __m128i a1 = _mm_cvtps_epi32(a.val); + __m128i mask = _mm_castps_si128(_mm_cmpgt_ps(_mm_cvtepi32_ps(a1), a.val)); + return v_int32x4(_mm_add_epi32(a1, mask)); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + __m128i a1 = _mm_cvtps_epi32(a.val); + __m128i mask = _mm_castps_si128(_mm_cmpgt_ps(a.val, _mm_cvtepi32_ps(a1))); + return v_int32x4(_mm_sub_epi32(a1, mask)); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ return v_int32x4(_mm_cvttps_epi32(a.val)); } + +inline v_int32x4 v_round(const v_float64x2& a) +{ return v_int32x4(_mm_cvtpd_epi32(a.val)); } + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + __m128i ai = _mm_cvtpd_epi32(a.val), bi = _mm_cvtpd_epi32(b.val); + return v_int32x4(_mm_unpacklo_epi64(ai, bi)); +} + +inline v_int32x4 v_floor(const v_float64x2& a) +{ + __m128i a1 = _mm_cvtpd_epi32(a.val); + __m128i mask = _mm_castpd_si128(_mm_cmpgt_pd(_mm_cvtepi32_pd(a1), a.val)); + mask = _mm_srli_si128(_mm_slli_si128(mask, 4), 8); // m0 m0 m1 m1 => m0 m1 0 0 + return v_int32x4(_mm_add_epi32(a1, mask)); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + __m128i a1 = _mm_cvtpd_epi32(a.val); + __m128i mask = _mm_castpd_si128(_mm_cmpgt_pd(a.val, _mm_cvtepi32_pd(a1))); + mask = _mm_srli_si128(_mm_slli_si128(mask, 4), 8); // m0 m0 m1 m1 => m0 m1 0 0 + return v_int32x4(_mm_sub_epi32(a1, mask)); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ return v_int32x4(_mm_cvttpd_epi32(a.val)); } + +#define OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(_Tpvec, suffix, cast_from, cast_to) \ +inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, \ + _Tpvec& b2, _Tpvec& b3) \ +{ \ + __m128i t0 = cast_from(_mm_unpacklo_##suffix(a0.val, a1.val)); \ + __m128i t1 = cast_from(_mm_unpacklo_##suffix(a2.val, a3.val)); \ + __m128i t2 = cast_from(_mm_unpackhi_##suffix(a0.val, a1.val)); \ + __m128i t3 = cast_from(_mm_unpackhi_##suffix(a2.val, a3.val)); \ +\ + b0.val = cast_to(_mm_unpacklo_epi64(t0, t1)); \ + b1.val = cast_to(_mm_unpackhi_epi64(t0, t1)); \ + b2.val = cast_to(_mm_unpacklo_epi64(t2, t3)); \ + b3.val = cast_to(_mm_unpackhi_epi64(t2, t3)); \ +} + +OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(v_uint32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(v_int32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(v_float32x4, ps, _mm_castps_si128, _mm_castsi128_ps) + +// load deinterleave +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b) +{ + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + + __m128i t10 = _mm_unpacklo_epi8(t00, t01); + __m128i t11 = _mm_unpackhi_epi8(t00, t01); + + __m128i t20 = _mm_unpacklo_epi8(t10, t11); + __m128i t21 = _mm_unpackhi_epi8(t10, t11); + + __m128i t30 = _mm_unpacklo_epi8(t20, t21); + __m128i t31 = _mm_unpackhi_epi8(t20, t21); + + a.val = _mm_unpacklo_epi8(t30, t31); + b.val = _mm_unpackhi_epi8(t30, t31); +} + +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b, v_uint8x16& c) +{ +#if CV_SSE4_1 + const __m128i m0 = _mm_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0); + const __m128i m1 = _mm_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + __m128i s0 = _mm_loadu_si128((const __m128i*)ptr); + __m128i s1 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + __m128i s2 = _mm_loadu_si128((const __m128i*)(ptr + 32)); + __m128i a0 = _mm_blendv_epi8(_mm_blendv_epi8(s0, s1, m0), s2, m1); + __m128i b0 = _mm_blendv_epi8(_mm_blendv_epi8(s1, s2, m0), s0, m1); + __m128i c0 = _mm_blendv_epi8(_mm_blendv_epi8(s2, s0, m0), s1, m1); + const __m128i sh_b = _mm_setr_epi8(0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13); + const __m128i sh_g = _mm_setr_epi8(1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14); + const __m128i sh_r = _mm_setr_epi8(2, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15); + a0 = _mm_shuffle_epi8(a0, sh_b); + b0 = _mm_shuffle_epi8(b0, sh_g); + c0 = _mm_shuffle_epi8(c0, sh_r); + a.val = a0; + b.val = b0; + c.val = c0; +#elif CV_SSSE3 + const __m128i m0 = _mm_setr_epi8(0, 3, 6, 9, 12, 15, 1, 4, 7, 10, 13, 2, 5, 8, 11, 14); + const __m128i m1 = _mm_alignr_epi8(m0, m0, 11); + const __m128i m2 = _mm_alignr_epi8(m0, m0, 6); + + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + __m128i t2 = _mm_loadu_si128((const __m128i*)(ptr + 32)); + + __m128i s0 = _mm_shuffle_epi8(t0, m0); + __m128i s1 = _mm_shuffle_epi8(t1, m1); + __m128i s2 = _mm_shuffle_epi8(t2, m2); + + t0 = _mm_alignr_epi8(s1, _mm_slli_si128(s0, 10), 5); + a.val = _mm_alignr_epi8(s2, t0, 5); + + t1 = _mm_alignr_epi8(_mm_srli_si128(s1, 5), _mm_slli_si128(s0, 5), 6); + b.val = _mm_alignr_epi8(_mm_srli_si128(s2, 5), t1, 5); + + t2 = _mm_alignr_epi8(_mm_srli_si128(s2, 10), s1, 11); + c.val = _mm_alignr_epi8(t2, s0, 11); +#else + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + __m128i t02 = _mm_loadu_si128((const __m128i*)(ptr + 32)); + + __m128i t10 = _mm_unpacklo_epi8(t00, _mm_unpackhi_epi64(t01, t01)); + __m128i t11 = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t00, t00), t02); + __m128i t12 = _mm_unpacklo_epi8(t01, _mm_unpackhi_epi64(t02, t02)); + + __m128i t20 = _mm_unpacklo_epi8(t10, _mm_unpackhi_epi64(t11, t11)); + __m128i t21 = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t10, t10), t12); + __m128i t22 = _mm_unpacklo_epi8(t11, _mm_unpackhi_epi64(t12, t12)); + + __m128i t30 = _mm_unpacklo_epi8(t20, _mm_unpackhi_epi64(t21, t21)); + __m128i t31 = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t20, t20), t22); + __m128i t32 = _mm_unpacklo_epi8(t21, _mm_unpackhi_epi64(t22, t22)); + + a.val = _mm_unpacklo_epi8(t30, _mm_unpackhi_epi64(t31, t31)); + b.val = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t30, t30), t32); + c.val = _mm_unpacklo_epi8(t31, _mm_unpackhi_epi64(t32, t32)); +#endif +} + +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b, v_uint8x16& c, v_uint8x16& d) +{ + __m128i u0 = _mm_loadu_si128((const __m128i*)ptr); // a0 b0 c0 d0 a1 b1 c1 d1 ... + __m128i u1 = _mm_loadu_si128((const __m128i*)(ptr + 16)); // a4 b4 c4 d4 ... + __m128i u2 = _mm_loadu_si128((const __m128i*)(ptr + 32)); // a8 b8 c8 d8 ... + __m128i u3 = _mm_loadu_si128((const __m128i*)(ptr + 48)); // a12 b12 c12 d12 ... + + __m128i v0 = _mm_unpacklo_epi8(u0, u2); // a0 a8 b0 b8 ... + __m128i v1 = _mm_unpackhi_epi8(u0, u2); // a2 a10 b2 b10 ... + __m128i v2 = _mm_unpacklo_epi8(u1, u3); // a4 a12 b4 b12 ... + __m128i v3 = _mm_unpackhi_epi8(u1, u3); // a6 a14 b6 b14 ... + + u0 = _mm_unpacklo_epi8(v0, v2); // a0 a4 a8 a12 ... + u1 = _mm_unpacklo_epi8(v1, v3); // a2 a6 a10 a14 ... + u2 = _mm_unpackhi_epi8(v0, v2); // a1 a5 a9 a13 ... + u3 = _mm_unpackhi_epi8(v1, v3); // a3 a7 a11 a15 ... + + v0 = _mm_unpacklo_epi8(u0, u1); // a0 a2 a4 a6 ... + v1 = _mm_unpacklo_epi8(u2, u3); // a1 a3 a5 a7 ... + v2 = _mm_unpackhi_epi8(u0, u1); // c0 c2 c4 c6 ... + v3 = _mm_unpackhi_epi8(u2, u3); // c1 c3 c5 c7 ... + + a.val = _mm_unpacklo_epi8(v0, v1); + b.val = _mm_unpackhi_epi8(v0, v1); + c.val = _mm_unpacklo_epi8(v2, v3); + d.val = _mm_unpackhi_epi8(v2, v3); +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b) +{ + __m128i v0 = _mm_loadu_si128((__m128i*)(ptr)); // a0 b0 a1 b1 a2 b2 a3 b3 + __m128i v1 = _mm_loadu_si128((__m128i*)(ptr + 8)); // a4 b4 a5 b5 a6 b6 a7 b7 + + __m128i v2 = _mm_unpacklo_epi16(v0, v1); // a0 a4 b0 b4 a1 a5 b1 b5 + __m128i v3 = _mm_unpackhi_epi16(v0, v1); // a2 a6 b2 b6 a3 a7 b3 b7 + __m128i v4 = _mm_unpacklo_epi16(v2, v3); // a0 a2 a4 a6 b0 b2 b4 b6 + __m128i v5 = _mm_unpackhi_epi16(v2, v3); // a1 a3 a5 a7 b1 b3 b5 b7 + + a.val = _mm_unpacklo_epi16(v4, v5); // a0 a1 a2 a3 a4 a5 a6 a7 + b.val = _mm_unpackhi_epi16(v4, v5); // b0 b1 ab b3 b4 b5 b6 b7 +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b, v_uint16x8& c) +{ +#if CV_SSE4_1 + __m128i v0 = _mm_loadu_si128((__m128i*)(ptr)); + __m128i v1 = _mm_loadu_si128((__m128i*)(ptr + 8)); + __m128i v2 = _mm_loadu_si128((__m128i*)(ptr + 16)); + __m128i a0 = _mm_blend_epi16(_mm_blend_epi16(v0, v1, 0x92), v2, 0x24); + __m128i b0 = _mm_blend_epi16(_mm_blend_epi16(v2, v0, 0x92), v1, 0x24); + __m128i c0 = _mm_blend_epi16(_mm_blend_epi16(v1, v2, 0x92), v0, 0x24); + + const __m128i sh_a = _mm_setr_epi8(0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m128i sh_b = _mm_setr_epi8(2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 0, 1, 6, 7, 12, 13); + const __m128i sh_c = _mm_setr_epi8(4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + a0 = _mm_shuffle_epi8(a0, sh_a); + b0 = _mm_shuffle_epi8(b0, sh_b); + c0 = _mm_shuffle_epi8(c0, sh_c); + + a.val = a0; + b.val = b0; + c.val = c0; +#else + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 8)); + __m128i t02 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + + __m128i t10 = _mm_unpacklo_epi16(t00, _mm_unpackhi_epi64(t01, t01)); + __m128i t11 = _mm_unpacklo_epi16(_mm_unpackhi_epi64(t00, t00), t02); + __m128i t12 = _mm_unpacklo_epi16(t01, _mm_unpackhi_epi64(t02, t02)); + + __m128i t20 = _mm_unpacklo_epi16(t10, _mm_unpackhi_epi64(t11, t11)); + __m128i t21 = _mm_unpacklo_epi16(_mm_unpackhi_epi64(t10, t10), t12); + __m128i t22 = _mm_unpacklo_epi16(t11, _mm_unpackhi_epi64(t12, t12)); + + a.val = _mm_unpacklo_epi16(t20, _mm_unpackhi_epi64(t21, t21)); + b.val = _mm_unpacklo_epi16(_mm_unpackhi_epi64(t20, t20), t22); + c.val = _mm_unpacklo_epi16(t21, _mm_unpackhi_epi64(t22, t22)); +#endif +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b, v_uint16x8& c, v_uint16x8& d) +{ + __m128i u0 = _mm_loadu_si128((const __m128i*)ptr); // a0 b0 c0 d0 a1 b1 c1 d1 + __m128i u1 = _mm_loadu_si128((const __m128i*)(ptr + 8)); // a2 b2 c2 d2 ... + __m128i u2 = _mm_loadu_si128((const __m128i*)(ptr + 16)); // a4 b4 c4 d4 ... + __m128i u3 = _mm_loadu_si128((const __m128i*)(ptr + 24)); // a6 b6 c6 d6 ... + + __m128i v0 = _mm_unpacklo_epi16(u0, u2); // a0 a4 b0 b4 ... + __m128i v1 = _mm_unpackhi_epi16(u0, u2); // a1 a5 b1 b5 ... + __m128i v2 = _mm_unpacklo_epi16(u1, u3); // a2 a6 b2 b6 ... + __m128i v3 = _mm_unpackhi_epi16(u1, u3); // a3 a7 b3 b7 ... + + u0 = _mm_unpacklo_epi16(v0, v2); // a0 a2 a4 a6 ... + u1 = _mm_unpacklo_epi16(v1, v3); // a1 a3 a5 a7 ... + u2 = _mm_unpackhi_epi16(v0, v2); // c0 c2 c4 c6 ... + u3 = _mm_unpackhi_epi16(v1, v3); // c1 c3 c5 c7 ... + + a.val = _mm_unpacklo_epi16(u0, u1); + b.val = _mm_unpackhi_epi16(u0, u1); + c.val = _mm_unpacklo_epi16(u2, u3); + d.val = _mm_unpackhi_epi16(u2, u3); +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b) +{ + __m128i v0 = _mm_loadu_si128((__m128i*)(ptr)); // a0 b0 a1 b1 + __m128i v1 = _mm_loadu_si128((__m128i*)(ptr + 4)); // a2 b2 a3 b3 + + __m128i v2 = _mm_unpacklo_epi32(v0, v1); // a0 a2 b0 b2 + __m128i v3 = _mm_unpackhi_epi32(v0, v1); // a1 a3 b1 b3 + + a.val = _mm_unpacklo_epi32(v2, v3); // a0 a1 a2 a3 + b.val = _mm_unpackhi_epi32(v2, v3); // b0 b1 ab b3 +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b, v_uint32x4& c) +{ + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 4)); + __m128i t02 = _mm_loadu_si128((const __m128i*)(ptr + 8)); + + __m128i t10 = _mm_unpacklo_epi32(t00, _mm_unpackhi_epi64(t01, t01)); + __m128i t11 = _mm_unpacklo_epi32(_mm_unpackhi_epi64(t00, t00), t02); + __m128i t12 = _mm_unpacklo_epi32(t01, _mm_unpackhi_epi64(t02, t02)); + + a.val = _mm_unpacklo_epi32(t10, _mm_unpackhi_epi64(t11, t11)); + b.val = _mm_unpacklo_epi32(_mm_unpackhi_epi64(t10, t10), t12); + c.val = _mm_unpacklo_epi32(t11, _mm_unpackhi_epi64(t12, t12)); +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b, v_uint32x4& c, v_uint32x4& d) +{ + v_uint32x4 s0(_mm_loadu_si128((const __m128i*)ptr)); // a0 b0 c0 d0 + v_uint32x4 s1(_mm_loadu_si128((const __m128i*)(ptr + 4))); // a1 b1 c1 d1 + v_uint32x4 s2(_mm_loadu_si128((const __m128i*)(ptr + 8))); // a2 b2 c2 d2 + v_uint32x4 s3(_mm_loadu_si128((const __m128i*)(ptr + 12))); // a3 b3 c3 d3 + + v_transpose4x4(s0, s1, s2, s3, a, b, c, d); +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b) +{ + __m128 u0 = _mm_loadu_ps(ptr); // a0 b0 a1 b1 + __m128 u1 = _mm_loadu_ps((ptr + 4)); // a2 b2 a3 b3 + + a.val = _mm_shuffle_ps(u0, u1, _MM_SHUFFLE(2, 0, 2, 0)); // a0 a1 a2 a3 + b.val = _mm_shuffle_ps(u0, u1, _MM_SHUFFLE(3, 1, 3, 1)); // b0 b1 ab b3 +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b, v_float32x4& c) +{ + __m128 t0 = _mm_loadu_ps(ptr + 0); + __m128 t1 = _mm_loadu_ps(ptr + 4); + __m128 t2 = _mm_loadu_ps(ptr + 8); + + __m128 at12 = _mm_shuffle_ps(t1, t2, _MM_SHUFFLE(0, 1, 0, 2)); + a.val = _mm_shuffle_ps(t0, at12, _MM_SHUFFLE(2, 0, 3, 0)); + + __m128 bt01 = _mm_shuffle_ps(t0, t1, _MM_SHUFFLE(0, 0, 0, 1)); + __m128 bt12 = _mm_shuffle_ps(t1, t2, _MM_SHUFFLE(0, 2, 0, 3)); + b.val = _mm_shuffle_ps(bt01, bt12, _MM_SHUFFLE(2, 0, 2, 0)); + + __m128 ct01 = _mm_shuffle_ps(t0, t1, _MM_SHUFFLE(0, 1, 0, 2)); + c.val = _mm_shuffle_ps(ct01, t2, _MM_SHUFFLE(3, 0, 2, 0)); +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b, v_float32x4& c, v_float32x4& d) +{ + __m128 t0 = _mm_loadu_ps(ptr + 0); + __m128 t1 = _mm_loadu_ps(ptr + 4); + __m128 t2 = _mm_loadu_ps(ptr + 8); + __m128 t3 = _mm_loadu_ps(ptr + 12); + __m128 t02lo = _mm_unpacklo_ps(t0, t2); + __m128 t13lo = _mm_unpacklo_ps(t1, t3); + __m128 t02hi = _mm_unpackhi_ps(t0, t2); + __m128 t13hi = _mm_unpackhi_ps(t1, t3); + a.val = _mm_unpacklo_ps(t02lo, t13lo); + b.val = _mm_unpackhi_ps(t02lo, t13lo); + c.val = _mm_unpacklo_ps(t02hi, t13hi); + d.val = _mm_unpackhi_ps(t02hi, t13hi); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, v_uint64x2& b) +{ + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 2)); + + a = v_uint64x2(_mm_unpacklo_epi64(t0, t1)); + b = v_uint64x2(_mm_unpackhi_epi64(t0, t1)); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, v_uint64x2& b, v_uint64x2& c) +{ + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); // a0, b0 + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 2)); // c0, a1 + __m128i t2 = _mm_loadu_si128((const __m128i*)(ptr + 4)); // b1, c1 + + t1 = _mm_shuffle_epi32(t1, 0x4e); // a1, c0 + + a = v_uint64x2(_mm_unpacklo_epi64(t0, t1)); + b = v_uint64x2(_mm_unpacklo_epi64(_mm_unpackhi_epi64(t0, t0), t2)); + c = v_uint64x2(_mm_unpackhi_epi64(t1, t2)); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, + v_uint64x2& b, v_uint64x2& c, v_uint64x2& d) +{ + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); // a0 b0 + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 2)); // c0 d0 + __m128i t2 = _mm_loadu_si128((const __m128i*)(ptr + 4)); // a1 b1 + __m128i t3 = _mm_loadu_si128((const __m128i*)(ptr + 6)); // c1 d1 + + a = v_uint64x2(_mm_unpacklo_epi64(t0, t2)); + b = v_uint64x2(_mm_unpackhi_epi64(t0, t2)); + c = v_uint64x2(_mm_unpacklo_epi64(t1, t3)); + d = v_uint64x2(_mm_unpackhi_epi64(t1, t3)); +} + +// store interleave + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi8(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi8(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 16), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 16), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 16), v1); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + const v_uint8x16& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ +#if CV_SSE4_1 + const __m128i sh_a = _mm_setr_epi8(0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, 5); + const __m128i sh_b = _mm_setr_epi8(5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10); + const __m128i sh_c = _mm_setr_epi8(10, 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15); + __m128i a0 = _mm_shuffle_epi8(a.val, sh_a); + __m128i b0 = _mm_shuffle_epi8(b.val, sh_b); + __m128i c0 = _mm_shuffle_epi8(c.val, sh_c); + + const __m128i m0 = _mm_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0); + const __m128i m1 = _mm_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + __m128i v0 = _mm_blendv_epi8(_mm_blendv_epi8(a0, b0, m1), c0, m0); + __m128i v1 = _mm_blendv_epi8(_mm_blendv_epi8(b0, c0, m1), a0, m0); + __m128i v2 = _mm_blendv_epi8(_mm_blendv_epi8(c0, a0, m1), b0, m0); +#elif CV_SSSE3 + const __m128i m0 = _mm_setr_epi8(0, 6, 11, 1, 7, 12, 2, 8, 13, 3, 9, 14, 4, 10, 15, 5); + const __m128i m1 = _mm_setr_epi8(5, 11, 0, 6, 12, 1, 7, 13, 2, 8, 14, 3, 9, 15, 4, 10); + const __m128i m2 = _mm_setr_epi8(10, 0, 5, 11, 1, 6, 12, 2, 7, 13, 3, 8, 14, 4, 9, 15); + + __m128i t0 = _mm_alignr_epi8(b.val, _mm_slli_si128(a.val, 10), 5); + t0 = _mm_alignr_epi8(c.val, t0, 5); + __m128i v0 = _mm_shuffle_epi8(t0, m0); + + __m128i t1 = _mm_alignr_epi8(_mm_srli_si128(b.val, 5), _mm_slli_si128(a.val, 5), 6); + t1 = _mm_alignr_epi8(_mm_srli_si128(c.val, 5), t1, 5); + __m128i v1 = _mm_shuffle_epi8(t1, m1); + + __m128i t2 = _mm_alignr_epi8(_mm_srli_si128(c.val, 10), b.val, 11); + t2 = _mm_alignr_epi8(t2, a.val, 11); + __m128i v2 = _mm_shuffle_epi8(t2, m2); +#else + __m128i z = _mm_setzero_si128(); + __m128i ab0 = _mm_unpacklo_epi8(a.val, b.val); + __m128i ab1 = _mm_unpackhi_epi8(a.val, b.val); + __m128i c0 = _mm_unpacklo_epi8(c.val, z); + __m128i c1 = _mm_unpackhi_epi8(c.val, z); + + __m128i p00 = _mm_unpacklo_epi16(ab0, c0); + __m128i p01 = _mm_unpackhi_epi16(ab0, c0); + __m128i p02 = _mm_unpacklo_epi16(ab1, c1); + __m128i p03 = _mm_unpackhi_epi16(ab1, c1); + + __m128i p10 = _mm_unpacklo_epi32(p00, p01); + __m128i p11 = _mm_unpackhi_epi32(p00, p01); + __m128i p12 = _mm_unpacklo_epi32(p02, p03); + __m128i p13 = _mm_unpackhi_epi32(p02, p03); + + __m128i p20 = _mm_unpacklo_epi64(p10, p11); + __m128i p21 = _mm_unpackhi_epi64(p10, p11); + __m128i p22 = _mm_unpacklo_epi64(p12, p13); + __m128i p23 = _mm_unpackhi_epi64(p12, p13); + + p20 = _mm_slli_si128(p20, 1); + p22 = _mm_slli_si128(p22, 1); + + __m128i p30 = _mm_slli_epi64(_mm_unpacklo_epi32(p20, p21), 8); + __m128i p31 = _mm_srli_epi64(_mm_unpackhi_epi32(p20, p21), 8); + __m128i p32 = _mm_slli_epi64(_mm_unpacklo_epi32(p22, p23), 8); + __m128i p33 = _mm_srli_epi64(_mm_unpackhi_epi32(p22, p23), 8); + + __m128i p40 = _mm_unpacklo_epi64(p30, p31); + __m128i p41 = _mm_unpackhi_epi64(p30, p31); + __m128i p42 = _mm_unpacklo_epi64(p32, p33); + __m128i p43 = _mm_unpackhi_epi64(p32, p33); + + __m128i v0 = _mm_or_si128(_mm_srli_si128(p40, 2), _mm_slli_si128(p41, 10)); + __m128i v1 = _mm_or_si128(_mm_srli_si128(p41, 6), _mm_slli_si128(p42, 6)); + __m128i v2 = _mm_or_si128(_mm_srli_si128(p42, 10), _mm_slli_si128(p43, 2)); +#endif + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 16), v1); + _mm_stream_si128((__m128i*)(ptr + 32), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 16), v1); + _mm_store_si128((__m128i*)(ptr + 32), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 16), v1); + _mm_storeu_si128((__m128i*)(ptr + 32), v2); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + const v_uint8x16& c, const v_uint8x16& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + // a0 a1 a2 a3 .... + // b0 b1 b2 b3 .... + // c0 c1 c2 c3 .... + // d0 d1 d2 d3 .... + __m128i u0 = _mm_unpacklo_epi8(a.val, c.val); // a0 c0 a1 c1 ... + __m128i u1 = _mm_unpackhi_epi8(a.val, c.val); // a8 c8 a9 c9 ... + __m128i u2 = _mm_unpacklo_epi8(b.val, d.val); // b0 d0 b1 d1 ... + __m128i u3 = _mm_unpackhi_epi8(b.val, d.val); // b8 d8 b9 d9 ... + + __m128i v0 = _mm_unpacklo_epi8(u0, u2); // a0 b0 c0 d0 ... + __m128i v1 = _mm_unpackhi_epi8(u0, u2); // a4 b4 c4 d4 ... + __m128i v2 = _mm_unpacklo_epi8(u1, u3); // a8 b8 c8 d8 ... + __m128i v3 = _mm_unpackhi_epi8(u1, u3); // a12 b12 c12 d12 ... + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 16), v1); + _mm_stream_si128((__m128i*)(ptr + 32), v2); + _mm_stream_si128((__m128i*)(ptr + 48), v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 16), v1); + _mm_store_si128((__m128i*)(ptr + 32), v2); + _mm_store_si128((__m128i*)(ptr + 48), v3); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 16), v1); + _mm_storeu_si128((__m128i*)(ptr + 32), v2); + _mm_storeu_si128((__m128i*)(ptr + 48), v3); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, const v_uint16x8& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi16(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi16(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 8), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 8), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 8), v1); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, + const v_uint16x8& b, const v_uint16x8& c, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ +#if CV_SSE4_1 + const __m128i sh_a = _mm_setr_epi8(0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m128i sh_b = _mm_setr_epi8(10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5); + const __m128i sh_c = _mm_setr_epi8(4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + __m128i a0 = _mm_shuffle_epi8(a.val, sh_a); + __m128i b0 = _mm_shuffle_epi8(b.val, sh_b); + __m128i c0 = _mm_shuffle_epi8(c.val, sh_c); + + __m128i v0 = _mm_blend_epi16(_mm_blend_epi16(a0, b0, 0x92), c0, 0x24); + __m128i v1 = _mm_blend_epi16(_mm_blend_epi16(c0, a0, 0x92), b0, 0x24); + __m128i v2 = _mm_blend_epi16(_mm_blend_epi16(b0, c0, 0x92), a0, 0x24); +#else + __m128i z = _mm_setzero_si128(); + __m128i ab0 = _mm_unpacklo_epi16(a.val, b.val); + __m128i ab1 = _mm_unpackhi_epi16(a.val, b.val); + __m128i c0 = _mm_unpacklo_epi16(c.val, z); + __m128i c1 = _mm_unpackhi_epi16(c.val, z); + + __m128i p10 = _mm_unpacklo_epi32(ab0, c0); + __m128i p11 = _mm_unpackhi_epi32(ab0, c0); + __m128i p12 = _mm_unpacklo_epi32(ab1, c1); + __m128i p13 = _mm_unpackhi_epi32(ab1, c1); + + __m128i p20 = _mm_unpacklo_epi64(p10, p11); + __m128i p21 = _mm_unpackhi_epi64(p10, p11); + __m128i p22 = _mm_unpacklo_epi64(p12, p13); + __m128i p23 = _mm_unpackhi_epi64(p12, p13); + + p20 = _mm_slli_si128(p20, 2); + p22 = _mm_slli_si128(p22, 2); + + __m128i p30 = _mm_unpacklo_epi64(p20, p21); + __m128i p31 = _mm_unpackhi_epi64(p20, p21); + __m128i p32 = _mm_unpacklo_epi64(p22, p23); + __m128i p33 = _mm_unpackhi_epi64(p22, p23); + + __m128i v0 = _mm_or_si128(_mm_srli_si128(p30, 2), _mm_slli_si128(p31, 10)); + __m128i v1 = _mm_or_si128(_mm_srli_si128(p31, 6), _mm_slli_si128(p32, 6)); + __m128i v2 = _mm_or_si128(_mm_srli_si128(p32, 10), _mm_slli_si128(p33, 2)); +#endif + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 8), v1); + _mm_stream_si128((__m128i*)(ptr + 16), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 8), v1); + _mm_store_si128((__m128i*)(ptr + 16), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 8), v1); + _mm_storeu_si128((__m128i*)(ptr + 16), v2); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, const v_uint16x8& b, + const v_uint16x8& c, const v_uint16x8& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + // a0 a1 a2 a3 .... + // b0 b1 b2 b3 .... + // c0 c1 c2 c3 .... + // d0 d1 d2 d3 .... + __m128i u0 = _mm_unpacklo_epi16(a.val, c.val); // a0 c0 a1 c1 ... + __m128i u1 = _mm_unpackhi_epi16(a.val, c.val); // a4 c4 a5 c5 ... + __m128i u2 = _mm_unpacklo_epi16(b.val, d.val); // b0 d0 b1 d1 ... + __m128i u3 = _mm_unpackhi_epi16(b.val, d.val); // b4 d4 b5 d5 ... + + __m128i v0 = _mm_unpacklo_epi16(u0, u2); // a0 b0 c0 d0 ... + __m128i v1 = _mm_unpackhi_epi16(u0, u2); // a2 b2 c2 d2 ... + __m128i v2 = _mm_unpacklo_epi16(u1, u3); // a4 b4 c4 d4 ... + __m128i v3 = _mm_unpackhi_epi16(u1, u3); // a6 b6 c6 d6 ... + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 8), v1); + _mm_stream_si128((__m128i*)(ptr + 16), v2); + _mm_stream_si128((__m128i*)(ptr + 24), v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 8), v1); + _mm_store_si128((__m128i*)(ptr + 16), v2); + _mm_store_si128((__m128i*)(ptr + 24), v3); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 8), v1); + _mm_storeu_si128((__m128i*)(ptr + 16), v2); + _mm_storeu_si128((__m128i*)(ptr + 24), v3); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi32(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi32(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 4), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 4), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 4), v1); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + v_uint32x4 z = v_setzero_u32(), u0, u1, u2, u3; + v_transpose4x4(a, b, c, z, u0, u1, u2, u3); + + __m128i v0 = _mm_or_si128(u0.val, _mm_slli_si128(u1.val, 12)); + __m128i v1 = _mm_or_si128(_mm_srli_si128(u1.val, 4), _mm_slli_si128(u2.val, 8)); + __m128i v2 = _mm_or_si128(_mm_srli_si128(u2.val, 8), _mm_slli_si128(u3.val, 4)); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 4), v1); + _mm_stream_si128((__m128i*)(ptr + 8), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 4), v1); + _mm_store_si128((__m128i*)(ptr + 8), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 4), v1); + _mm_storeu_si128((__m128i*)(ptr + 8), v2); + } +} + +inline void v_store_interleave(unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + v_uint32x4 v0, v1, v2, v3; + v_transpose4x4(a, b, c, d, v0, v1, v2, v3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0.val); + _mm_stream_si128((__m128i*)(ptr + 4), v1.val); + _mm_stream_si128((__m128i*)(ptr + 8), v2.val); + _mm_stream_si128((__m128i*)(ptr + 12), v3.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0.val); + _mm_store_si128((__m128i*)(ptr + 4), v1.val); + _mm_store_si128((__m128i*)(ptr + 8), v2.val); + _mm_store_si128((__m128i*)(ptr + 12), v3.val); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0.val); + _mm_storeu_si128((__m128i*)(ptr + 4), v1.val); + _mm_storeu_si128((__m128i*)(ptr + 8), v2.val); + _mm_storeu_si128((__m128i*)(ptr + 12), v3.val); + } +} + +// 2-channel, float only +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128 v0 = _mm_unpacklo_ps(a.val, b.val); // a0 b0 a1 b1 + __m128 v1 = _mm_unpackhi_ps(a.val, b.val); // a2 b2 a3 b3 + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_ps(ptr, v0); + _mm_stream_ps(ptr + 4, v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_ps(ptr, v0); + _mm_store_ps(ptr + 4, v1); + } + else + { + _mm_storeu_ps(ptr, v0); + _mm_storeu_ps(ptr + 4, v1); + } +} + +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128 u0 = _mm_shuffle_ps(a.val, b.val, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 u1 = _mm_shuffle_ps(c.val, a.val, _MM_SHUFFLE(1, 1, 0, 0)); + __m128 v0 = _mm_shuffle_ps(u0, u1, _MM_SHUFFLE(2, 0, 2, 0)); + __m128 u2 = _mm_shuffle_ps(b.val, c.val, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 u3 = _mm_shuffle_ps(a.val, b.val, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v1 = _mm_shuffle_ps(u2, u3, _MM_SHUFFLE(2, 0, 2, 0)); + __m128 u4 = _mm_shuffle_ps(c.val, a.val, _MM_SHUFFLE(3, 3, 2, 2)); + __m128 u5 = _mm_shuffle_ps(b.val, c.val, _MM_SHUFFLE(3, 3, 3, 3)); + __m128 v2 = _mm_shuffle_ps(u4, u5, _MM_SHUFFLE(2, 0, 2, 0)); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_ps(ptr, v0); + _mm_stream_ps(ptr + 4, v1); + _mm_stream_ps(ptr + 8, v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_ps(ptr, v0); + _mm_store_ps(ptr + 4, v1); + _mm_store_ps(ptr + 8, v2); + } + else + { + _mm_storeu_ps(ptr, v0); + _mm_storeu_ps(ptr + 4, v1); + _mm_storeu_ps(ptr + 8, v2); + } +} + +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128 u0 = _mm_unpacklo_ps(a.val, c.val); + __m128 u1 = _mm_unpacklo_ps(b.val, d.val); + __m128 u2 = _mm_unpackhi_ps(a.val, c.val); + __m128 u3 = _mm_unpackhi_ps(b.val, d.val); + __m128 v0 = _mm_unpacklo_ps(u0, u1); + __m128 v2 = _mm_unpacklo_ps(u2, u3); + __m128 v1 = _mm_unpackhi_ps(u0, u1); + __m128 v3 = _mm_unpackhi_ps(u2, u3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_ps(ptr, v0); + _mm_stream_ps(ptr + 4, v1); + _mm_stream_ps(ptr + 8, v2); + _mm_stream_ps(ptr + 12, v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_ps(ptr, v0); + _mm_store_ps(ptr + 4, v1); + _mm_store_ps(ptr + 8, v2); + _mm_store_ps(ptr + 12, v3); + } + else + { + _mm_storeu_ps(ptr, v0); + _mm_storeu_ps(ptr + 4, v1); + _mm_storeu_ps(ptr + 8, v2); + _mm_storeu_ps(ptr + 12, v3); + } +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi64(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi64(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 2), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 2), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 2), v1); + } +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + const v_uint64x2& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi64(a.val, b.val); + __m128i v1 = _mm_unpacklo_epi64(c.val, _mm_unpackhi_epi64(a.val, a.val)); + __m128i v2 = _mm_unpackhi_epi64(b.val, c.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 2), v1); + _mm_stream_si128((__m128i*)(ptr + 4), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 2), v1); + _mm_store_si128((__m128i*)(ptr + 4), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 2), v1); + _mm_storeu_si128((__m128i*)(ptr + 4), v2); + } +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + const v_uint64x2& c, const v_uint64x2& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi64(a.val, b.val); + __m128i v1 = _mm_unpacklo_epi64(c.val, d.val); + __m128i v2 = _mm_unpackhi_epi64(a.val, b.val); + __m128i v3 = _mm_unpackhi_epi64(c.val, d.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 2), v1); + _mm_stream_si128((__m128i*)(ptr + 4), v2); + _mm_stream_si128((__m128i*)(ptr + 6), v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 2), v1); + _mm_store_si128((__m128i*)(ptr + 4), v2); + _mm_store_si128((__m128i*)(ptr + 6), v3); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 2), v1); + _mm_storeu_si128((__m128i*)(ptr + 4), v2); + _mm_storeu_si128((__m128i*)(ptr + 6), v3); + } +} + +#define OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(_Tpvec0, _Tp0, suffix0, _Tpvec1, _Tp1, suffix1) \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0 ) \ +{ \ + _Tpvec1 a1, b1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0 ) \ +{ \ + _Tpvec1 a1, b1, c1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0, _Tpvec0& d0 ) \ +{ \ + _Tpvec1 a1, b1, c1, d1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1, d1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ + d0 = v_reinterpret_as_##suffix0(d1); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, const _Tpvec0& d0, \ + hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + _Tpvec1 d1 = v_reinterpret_as_##suffix1(d0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, d1, mode); \ +} + +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int8x16, schar, s8, v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int16x8, short, s16, v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int32x4, int, s32, v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int64x2, int64, s64, v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_float64x2, double, f64, v_uint64x2, uint64, u64) + +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(_mm_cvtepi32_ps(a.val)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + return v_float32x4(_mm_cvtpd_ps(a.val)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + return v_float32x4(_mm_movelh_ps(_mm_cvtpd_ps(a.val), _mm_cvtpd_ps(b.val))); +} + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ + return v_float64x2(_mm_cvtepi32_pd(a.val)); +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ + return v_float64x2(_mm_cvtepi32_pd(_mm_srli_si128(a.val,8))); +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + return v_float64x2(_mm_cvtps_pd(a.val)); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + return v_float64x2(_mm_cvtps_pd(_mm_movehl_ps(a.val, a.val))); +} + +#if CV_FP16 +inline v_float32x4 v128_load_fp16_f32(const short* ptr) +{ + return v_float32x4(_mm_cvtph_ps(_mm_loadu_si128((const __m128i*)ptr))); +} + +inline void v_store_fp16(short* ptr, const v_float32x4& a) +{ + __m128i fp16_value = _mm_cvtps_ph(a.val, 0); + _mm_storel_epi64((__m128i*)ptr, fp16_value); +} +#endif + +////////////// Lookup table access //////////////////// + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + return v_int32x4(_mm_setr_epi32(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]])); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + return v_float32x4(_mm_setr_ps(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]])); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + int idx[2]; + v_store_low(idx, idxvec); + return v_float64x2(_mm_setr_pd(tab[idx[0]], tab[idx[1]])); +} + +// loads pairs from the table and deinterleaves them, e.g. returns: +// x = (tab[idxvec[0], tab[idxvec[1]], tab[idxvec[2]], tab[idxvec[3]]), +// y = (tab[idxvec[0]+1], tab[idxvec[1]+1], tab[idxvec[2]+1], tab[idxvec[3]+1]) +// note that the indices are float's indices, not the float-pair indices. +// in theory, this function can be used to implement bilinear interpolation, +// when idxvec are the offsets within the image. +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + __m128 z = _mm_setzero_ps(); + __m128 xy01 = _mm_loadl_pi(z, (__m64*)(tab + idx[0])); + __m128 xy23 = _mm_loadl_pi(z, (__m64*)(tab + idx[2])); + xy01 = _mm_loadh_pi(xy01, (__m64*)(tab + idx[1])); + xy23 = _mm_loadh_pi(xy23, (__m64*)(tab + idx[3])); + __m128 xxyy02 = _mm_unpacklo_ps(xy01, xy23); + __m128 xxyy13 = _mm_unpackhi_ps(xy01, xy23); + x = v_float32x4(_mm_unpacklo_ps(xxyy02, xxyy13)); + y = v_float32x4(_mm_unpackhi_ps(xxyy02, xxyy13)); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int idx[2]; + v_store_low(idx, idxvec); + __m128d xy0 = _mm_loadu_pd(tab + idx[0]); + __m128d xy1 = _mm_loadu_pd(tab + idx[1]); + x = v_float64x2(_mm_unpacklo_pd(xy0, xy1)); + y = v_float64x2(_mm_unpackhi_pd(xy0, xy1)); +} + + +////////////// FP16 support /////////////////////////// + +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + const __m128i z = _mm_setzero_si128(), delta = _mm_set1_epi32(0x38000000); + const __m128i signmask = _mm_set1_epi32(0x80000000), maxexp = _mm_set1_epi32(0x7c000000); + const __m128 deltaf = _mm_castsi128_ps(_mm_set1_epi32(0x38800000)); + __m128i bits = _mm_unpacklo_epi16(z, _mm_loadl_epi64((const __m128i*)ptr)); // h << 16 + __m128i e = _mm_and_si128(bits, maxexp), sign = _mm_and_si128(bits, signmask); + __m128i t = _mm_add_epi32(_mm_srli_epi32(_mm_xor_si128(bits, sign), 3), delta); // ((h & 0x7fff) << 13) + delta + __m128i zt = _mm_castps_si128(_mm_sub_ps(_mm_castsi128_ps(_mm_add_epi32(t, _mm_set1_epi32(1 << 23))), deltaf)); + + t = _mm_add_epi32(t, _mm_and_si128(delta, _mm_cmpeq_epi32(maxexp, e))); + __m128i zmask = _mm_cmpeq_epi32(e, z); + __m128i ft = v_select_si128(zmask, zt, t); + return v_float32x4(_mm_castsi128_ps(_mm_or_si128(ft, sign))); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + const __m128i signmask = _mm_set1_epi32(0x80000000); + const __m128i rval = _mm_set1_epi32(0x3f000000); + + __m128i t = _mm_castps_si128(v.val); + __m128i sign = _mm_srai_epi32(_mm_and_si128(t, signmask), 16); + t = _mm_andnot_si128(signmask, t); + + __m128i finitemask = _mm_cmpgt_epi32(_mm_set1_epi32(0x47800000), t); + __m128i isnan = _mm_cmpgt_epi32(t, _mm_set1_epi32(0x7f800000)); + __m128i naninf = v_select_si128(isnan, _mm_set1_epi32(0x7e00), _mm_set1_epi32(0x7c00)); + __m128i tinymask = _mm_cmpgt_epi32(_mm_set1_epi32(0x38800000), t); + __m128i tt = _mm_castps_si128(_mm_add_ps(_mm_castsi128_ps(t), _mm_castsi128_ps(rval))); + tt = _mm_sub_epi32(tt, rval); + __m128i odd = _mm_and_si128(_mm_srli_epi32(t, 13), _mm_set1_epi32(1)); + __m128i nt = _mm_add_epi32(t, _mm_set1_epi32(0xc8000fff)); + nt = _mm_srli_epi32(_mm_add_epi32(nt, odd), 13); + t = v_select_si128(tinymask, tt, nt); + t = v_select_si128(finitemask, t, naninf); + t = _mm_or_si128(t, sign); + t = _mm_packs_epi32(t, t); + _mm_storel_epi64((__m128i*)ptr, t); +} + +inline void v_cleanup() {} + +//! @name Check SIMD support +//! @{ +//! @brief Check CPU capability of SIMD operation +static inline bool hasSIMD128() +{ + return (CV_CPU_HAS_SUPPORT_SSE2) ? true : false; +} + +//! @} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif diff --git a/include/opencv2/core/hal/intrin_sse_em.hpp b/include/opencv2/core/hal/intrin_sse_em.hpp new file mode 100644 index 0000000..be27668 --- /dev/null +++ b/include/opencv2/core/hal/intrin_sse_em.hpp @@ -0,0 +1,167 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_INTRIN_SSE_EM_HPP +#define OPENCV_HAL_INTRIN_SSE_EM_HPP + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#define OPENCV_HAL_SSE_WRAP_1(fun, tp) \ + inline tp _v128_##fun(const tp& a) \ + { return _mm_##fun(a); } + +#define OPENCV_HAL_SSE_WRAP_2(fun, tp) \ + inline tp _v128_##fun(const tp& a, const tp& b) \ + { return _mm_##fun(a, b); } + +#define OPENCV_HAL_SSE_WRAP_3(fun, tp) \ + inline tp _v128_##fun(const tp& a, const tp& b, const tp& c) \ + { return _mm_##fun(a, b, c); } + +///////////////////////////// XOP ///////////////////////////// + +// [todo] define CV_XOP +#if 1 // CV_XOP +inline __m128i _v128_comgt_epu32(const __m128i& a, const __m128i& b) +{ + const __m128i delta = _mm_set1_epi32((int)0x80000000); + return _mm_cmpgt_epi32(_mm_xor_si128(a, delta), _mm_xor_si128(b, delta)); +} +// wrapping XOP +#else +OPENCV_HAL_SSE_WRAP_2(_v128_comgt_epu32, __m128i) +#endif // !CV_XOP + +///////////////////////////// SSE4.1 ///////////////////////////// + +#if !CV_SSE4_1 + +/** Swizzle **/ +inline __m128i _v128_blendv_epi8(const __m128i& a, const __m128i& b, const __m128i& mask) +{ return _mm_xor_si128(a, _mm_and_si128(_mm_xor_si128(b, a), mask)); } + +/** Convert **/ +// 8 >> 16 +inline __m128i _v128_cvtepu8_epi16(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi8(a, z); +} +inline __m128i _v128_cvtepi8_epi16(const __m128i& a) +{ return _mm_srai_epi16(_mm_unpacklo_epi8(a, a), 8); } +// 8 >> 32 +inline __m128i _v128_cvtepu8_epi32(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi16(_mm_unpacklo_epi8(a, z), z); +} +inline __m128i _v128_cvtepi8_epi32(const __m128i& a) +{ + __m128i r = _mm_unpacklo_epi8(a, a); + r = _mm_unpacklo_epi8(r, r); + return _mm_srai_epi32(r, 24); +} +// 16 >> 32 +inline __m128i _v128_cvtepu16_epi32(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi16(a, z); +} +inline __m128i _v128_cvtepi16_epi32(const __m128i& a) +{ return _mm_srai_epi32(_mm_unpacklo_epi16(a, a), 16); } +// 32 >> 64 +inline __m128i _v128_cvtepu32_epi64(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi32(a, z); +} +inline __m128i _v128_cvtepi32_epi64(const __m128i& a) +{ return _mm_unpacklo_epi32(a, _mm_srai_epi32(a, 31)); } + +/** Arithmetic **/ +inline __m128i _v128_mullo_epi32(const __m128i& a, const __m128i& b) +{ + __m128i c0 = _mm_mul_epu32(a, b); + __m128i c1 = _mm_mul_epu32(_mm_srli_epi64(a, 32), _mm_srli_epi64(b, 32)); + __m128i d0 = _mm_unpacklo_epi32(c0, c1); + __m128i d1 = _mm_unpackhi_epi32(c0, c1); + return _mm_unpacklo_epi64(d0, d1); +} + +/** Math **/ +inline __m128i _v128_min_epu32(const __m128i& a, const __m128i& b) +{ return _v128_blendv_epi8(a, b, _v128_comgt_epu32(a, b)); } + +// wrapping SSE4.1 +#else +OPENCV_HAL_SSE_WRAP_1(cvtepu8_epi16, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi8_epi16, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepu8_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi8_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepu16_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi16_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepu32_epi64, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi32_epi64, __m128i) +OPENCV_HAL_SSE_WRAP_2(min_epu32, __m128i) +OPENCV_HAL_SSE_WRAP_2(mullo_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_3(blendv_epi8, __m128i) +#endif // !CV_SSE4_1 + +///////////////////////////// Revolutionary ///////////////////////////// + +/** Convert **/ +// 16 << 8 +inline __m128i _v128_cvtepu8_epi16_high(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpackhi_epi8(a, z); +} +inline __m128i _v128_cvtepi8_epi16_high(const __m128i& a) +{ return _mm_srai_epi16(_mm_unpackhi_epi8(a, a), 8); } +// 32 << 16 +inline __m128i _v128_cvtepu16_epi32_high(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpackhi_epi16(a, z); +} +inline __m128i _v128_cvtepi16_epi32_high(const __m128i& a) +{ return _mm_srai_epi32(_mm_unpackhi_epi16(a, a), 16); } +// 64 << 32 +inline __m128i _v128_cvtepu32_epi64_high(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpackhi_epi32(a, z); +} +inline __m128i _v128_cvtepi32_epi64_high(const __m128i& a) +{ return _mm_unpackhi_epi32(a, _mm_srai_epi32(a, 31)); } + +/** Miscellaneous **/ +inline __m128i _v128_packs_epu32(const __m128i& a, const __m128i& b) +{ + const __m128i m = _mm_set1_epi32(65535); + __m128i am = _v128_min_epu32(a, m); + __m128i bm = _v128_min_epu32(b, m); +#if CV_SSE4_1 + return _mm_packus_epi32(am, bm); +#else + const __m128i d = _mm_set1_epi32(32768), nd = _mm_set1_epi16(-32768); + am = _mm_sub_epi32(am, d); + bm = _mm_sub_epi32(bm, d); + am = _mm_packs_epi32(am, bm); + return _mm_sub_epi16(am, nd); +#endif +} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} // cv:: + +#endif // OPENCV_HAL_INTRIN_SSE_EM_HPP \ No newline at end of file diff --git a/include/opencv2/core/hal/intrin_vsx.hpp b/include/opencv2/core/hal/intrin_vsx.hpp new file mode 100644 index 0000000..fce5c44 --- /dev/null +++ b/include/opencv2/core/hal/intrin_vsx.hpp @@ -0,0 +1,1120 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_VSX_HPP +#define OPENCV_HAL_VSX_HPP + +#include +#include "opencv2/core/utility.hpp" + +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 + +/** + * todo: supporting half precision for power9 + * convert instractions xvcvhpsp, xvcvsphp +**/ + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +///////// Types //////////// + +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + vec_uchar16 val; + + explicit v_uint8x16(const vec_uchar16& v) : val(v) + {} + v_uint8x16() : val(vec_uchar16_z) + {} + v_uint8x16(vec_bchar16 v) : val(vec_uchar16_c(v)) + {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + : val(vec_uchar16_set(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)) + {} + uchar get0() const + { return vec_extract(val, 0); } +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + vec_char16 val; + + explicit v_int8x16(const vec_char16& v) : val(v) + {} + v_int8x16() : val(vec_char16_z) + {} + v_int8x16(vec_bchar16 v) : val(vec_char16_c(v)) + {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + : val(vec_char16_set(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)) + {} + schar get0() const + { return vec_extract(val, 0); } +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + vec_ushort8 val; + + explicit v_uint16x8(const vec_ushort8& v) : val(v) + {} + v_uint16x8() : val(vec_ushort8_z) + {} + v_uint16x8(vec_bshort8 v) : val(vec_ushort8_c(v)) + {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + : val(vec_ushort8_set(v0, v1, v2, v3, v4, v5, v6, v7)) + {} + ushort get0() const + { return vec_extract(val, 0); } +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + vec_short8 val; + + explicit v_int16x8(const vec_short8& v) : val(v) + {} + v_int16x8() : val(vec_short8_z) + {} + v_int16x8(vec_bshort8 v) : val(vec_short8_c(v)) + {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + : val(vec_short8_set(v0, v1, v2, v3, v4, v5, v6, v7)) + {} + short get0() const + { return vec_extract(val, 0); } +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + enum { nlanes = 4 }; + vec_uint4 val; + + explicit v_uint32x4(const vec_uint4& v) : val(v) + {} + v_uint32x4() : val(vec_uint4_z) + {} + v_uint32x4(vec_bint4 v) : val(vec_uint4_c(v)) + {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) : val(vec_uint4_set(v0, v1, v2, v3)) + {} + uint get0() const + { return vec_extract(val, 0); } +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + vec_int4 val; + + explicit v_int32x4(const vec_int4& v) : val(v) + {} + v_int32x4() : val(vec_int4_z) + {} + v_int32x4(vec_bint4 v) : val(vec_int4_c(v)) + {} + v_int32x4(int v0, int v1, int v2, int v3) : val(vec_int4_set(v0, v1, v2, v3)) + {} + int get0() const + { return vec_extract(val, 0); } +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + vec_float4 val; + + explicit v_float32x4(const vec_float4& v) : val(v) + {} + v_float32x4() : val(vec_float4_z) + {} + v_float32x4(vec_bint4 v) : val(vec_float4_c(v)) + {} + v_float32x4(float v0, float v1, float v2, float v3) : val(vec_float4_set(v0, v1, v2, v3)) + {} + float get0() const + { return vec_extract(val, 0); } +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + vec_udword2 val; + + explicit v_uint64x2(const vec_udword2& v) : val(v) + {} + v_uint64x2() : val(vec_udword2_z) + {} + v_uint64x2(vec_bdword2 v) : val(vec_udword2_c(v)) + {} + v_uint64x2(uint64 v0, uint64 v1) : val(vec_udword2_set(v0, v1)) + {} + uint64 get0() const + { return vec_extract(val, 0); } +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + vec_dword2 val; + + explicit v_int64x2(const vec_dword2& v) : val(v) + {} + v_int64x2() : val(vec_dword2_z) + {} + v_int64x2(vec_bdword2 v) : val(vec_dword2_c(v)) + {} + v_int64x2(int64 v0, int64 v1) : val(vec_dword2_set(v0, v1)) + {} + int64 get0() const + { return vec_extract(val, 0); } +}; + +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + vec_double2 val; + + explicit v_float64x2(const vec_double2& v) : val(v) + {} + v_float64x2() : val(vec_double2_z) + {} + v_float64x2(vec_bdword2 v) : val(vec_double2_c(v)) + {} + v_float64x2(double v0, double v1) : val(vec_double2_set(v0, v1)) + {} + double get0() const + { return vec_extract(val, 0); } +}; + +//////////////// Load and store operations /////////////// + +/* + * clang-5 aborted during parse "vec_xxx_c" only if it's + * inside a function template which is defined by preprocessor macro. + * + * if vec_xxx_c defined as C++ cast, clang-5 will pass it +*/ +#define OPENCV_HAL_IMPL_VSX_INITVEC(_Tpvec, _Tp, suffix, cast) \ +inline _Tpvec v_setzero_##suffix() { return _Tpvec(); } \ +inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec(vec_splats((_Tp)v));} \ +template inline _Tpvec v_reinterpret_as_##suffix(const _Tpvec0 &a) \ +{ return _Tpvec((cast)a.val); } + +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint8x16, uchar, u8, vec_uchar16) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int8x16, schar, s8, vec_char16) +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint16x8, ushort, u16, vec_ushort8) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int16x8, short, s16, vec_short8) +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint32x4, uint, u32, vec_uint4) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int32x4, int, s32, vec_int4) +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint64x2, uint64, u64, vec_udword2) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int64x2, int64, s64, vec_dword2) +OPENCV_HAL_IMPL_VSX_INITVEC(v_float32x4, float, f32, vec_float4) +OPENCV_HAL_IMPL_VSX_INITVEC(v_float64x2, double, f64, vec_double2) + +#define OPENCV_HAL_IMPL_VSX_LOADSTORE_C(_Tpvec, _Tp, ld, ld_a, st, st_a) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(ld(0, ptr)); } \ +inline _Tpvec v_load_aligned(VSX_UNUSED(const _Tp* ptr)) \ +{ return _Tpvec(ld_a(0, ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(vec_ld_l8(ptr)); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ return _Tpvec(vec_mergesqh(vec_ld_l8(ptr0), vec_ld_l8(ptr1))); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ st(a.val, 0, ptr); } \ +inline void v_store_aligned(VSX_UNUSED(_Tp* ptr), const _Tpvec& a) \ +{ st_a(a.val, 0, ptr); } \ +inline void v_store_aligned_nocache(VSX_UNUSED(_Tp* ptr), const _Tpvec& a) \ +{ st_a(a.val, 0, ptr); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ +{ if(mode == hal::STORE_UNALIGNED) st(a.val, 0, ptr); else st_a(a.val, 0, ptr); } \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ vec_st_l8(a.val, ptr); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ vec_st_h8(a.val, ptr); } + +#define OPENCV_HAL_IMPL_VSX_LOADSTORE(_Tpvec, _Tp) \ +OPENCV_HAL_IMPL_VSX_LOADSTORE_C(_Tpvec, _Tp, vsx_ld, vec_ld, vsx_st, vec_st) + +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_uint8x16, uchar) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_int8x16, schar) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_uint16x8, ushort) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_int16x8, short) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_uint32x4, uint) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_int32x4, int) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_float32x4, float) + +OPENCV_HAL_IMPL_VSX_LOADSTORE_C(v_float64x2, double, vsx_ld, vsx_ld, vsx_st, vsx_st) +OPENCV_HAL_IMPL_VSX_LOADSTORE_C(v_uint64x2, uint64, vsx_ld2, vsx_ld2, vsx_st2, vsx_st2) +OPENCV_HAL_IMPL_VSX_LOADSTORE_C(v_int64x2, int64, vsx_ld2, vsx_ld2, vsx_st2, vsx_st2) + +//////////////// Value reordering /////////////// + +/* de&interleave */ +#define OPENCV_HAL_IMPL_VSX_INTERLEAVE(_Tp, _Tpvec) \ +inline void v_load_deinterleave(const _Tp* ptr, _Tpvec& a, _Tpvec& b) \ +{ vec_ld_deinterleave(ptr, a.val, b.val);} \ +inline void v_load_deinterleave(const _Tp* ptr, _Tpvec& a, \ + _Tpvec& b, _Tpvec& c) \ +{ vec_ld_deinterleave(ptr, a.val, b.val, c.val); } \ +inline void v_load_deinterleave(const _Tp* ptr, _Tpvec& a, _Tpvec& b, \ + _Tpvec& c, _Tpvec& d) \ +{ vec_ld_deinterleave(ptr, a.val, b.val, c.val, d.val); } \ +inline void v_store_interleave(_Tp* ptr, const _Tpvec& a, const _Tpvec& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ vec_st_interleave(a.val, b.val, ptr); } \ +inline void v_store_interleave(_Tp* ptr, const _Tpvec& a, \ + const _Tpvec& b, const _Tpvec& c, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ vec_st_interleave(a.val, b.val, c.val, ptr); } \ +inline void v_store_interleave(_Tp* ptr, const _Tpvec& a, const _Tpvec& b, \ + const _Tpvec& c, const _Tpvec& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ vec_st_interleave(a.val, b.val, c.val, d.val, ptr); } + +OPENCV_HAL_IMPL_VSX_INTERLEAVE(uchar, v_uint8x16) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(schar, v_int8x16) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(ushort, v_uint16x8) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(short, v_int16x8) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(uint, v_uint32x4) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(int, v_int32x4) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(float, v_float32x4) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(double, v_float64x2) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(int64, v_int64x2) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(uint64, v_uint64x2) + +/* Expand */ +#define OPENCV_HAL_IMPL_VSX_EXPAND(_Tpvec, _Tpwvec, _Tp, fl, fh) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + b0.val = fh(a.val); \ + b1.val = fl(a.val); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ return _Tpwvec(fh(a.val)); } \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ return _Tpwvec(fl(a.val)); } \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ return _Tpwvec(fh(vec_ld_l8(ptr))); } + +OPENCV_HAL_IMPL_VSX_EXPAND(v_uint8x16, v_uint16x8, uchar, vec_unpacklu, vec_unpackhu) +OPENCV_HAL_IMPL_VSX_EXPAND(v_int8x16, v_int16x8, schar, vec_unpackl, vec_unpackh) +OPENCV_HAL_IMPL_VSX_EXPAND(v_uint16x8, v_uint32x4, ushort, vec_unpacklu, vec_unpackhu) +OPENCV_HAL_IMPL_VSX_EXPAND(v_int16x8, v_int32x4, short, vec_unpackl, vec_unpackh) +OPENCV_HAL_IMPL_VSX_EXPAND(v_uint32x4, v_uint64x2, uint, vec_unpacklu, vec_unpackhu) +OPENCV_HAL_IMPL_VSX_EXPAND(v_int32x4, v_int64x2, int, vec_unpackl, vec_unpackh) + +inline v_uint32x4 v_load_expand_q(const uchar* ptr) +{ return v_uint32x4(vec_uint4_set(ptr[0], ptr[1], ptr[2], ptr[3])); } + +inline v_int32x4 v_load_expand_q(const schar* ptr) +{ return v_int32x4(vec_int4_set(ptr[0], ptr[1], ptr[2], ptr[3])); } + +/* pack */ +#define OPENCV_HAL_IMPL_VSX_PACK(_Tpvec, _Tp, _Tpwvec, _Tpvn, _Tpdel, sfnc, pkfnc, addfnc, pack) \ +inline _Tpvec v_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + return _Tpvec(pkfnc(a.val, b.val)); \ +} \ +inline void v_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + vec_st_l8(pkfnc(a.val, a.val), ptr); \ +} \ +template \ +inline _Tpvec v_rshr_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + const __vector _Tpvn vn = vec_splats((_Tpvn)n); \ + const __vector _Tpdel delta = vec_splats((_Tpdel)((_Tpdel)1 << (n-1))); \ + return _Tpvec(pkfnc(sfnc(addfnc(a.val, delta), vn), sfnc(addfnc(b.val, delta), vn))); \ +} \ +template \ +inline void v_rshr_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + const __vector _Tpvn vn = vec_splats((_Tpvn)n); \ + const __vector _Tpdel delta = vec_splats((_Tpdel)((_Tpdel)1 << (n-1))); \ + vec_st_l8(pkfnc(sfnc(addfnc(a.val, delta), vn), delta), ptr); \ +} + +OPENCV_HAL_IMPL_VSX_PACK(v_uint8x16, uchar, v_uint16x8, unsigned short, unsigned short, + vec_sr, vec_packs, vec_adds, pack) +OPENCV_HAL_IMPL_VSX_PACK(v_int8x16, schar, v_int16x8, unsigned short, short, + vec_sra, vec_packs, vec_adds, pack) + +OPENCV_HAL_IMPL_VSX_PACK(v_uint16x8, ushort, v_uint32x4, unsigned int, unsigned int, + vec_sr, vec_packs, vec_add, pack) +OPENCV_HAL_IMPL_VSX_PACK(v_int16x8, short, v_int32x4, unsigned int, int, + vec_sra, vec_packs, vec_add, pack) + +OPENCV_HAL_IMPL_VSX_PACK(v_uint32x4, uint, v_uint64x2, unsigned long long, unsigned long long, + vec_sr, vec_pack, vec_add, pack) +OPENCV_HAL_IMPL_VSX_PACK(v_int32x4, int, v_int64x2, unsigned long long, long long, + vec_sra, vec_pack, vec_add, pack) + +OPENCV_HAL_IMPL_VSX_PACK(v_uint8x16, uchar, v_int16x8, unsigned short, short, + vec_sra, vec_packsu, vec_adds, pack_u) +OPENCV_HAL_IMPL_VSX_PACK(v_uint16x8, ushort, v_int32x4, unsigned int, int, + vec_sra, vec_packsu, vec_add, pack_u) +// Following variant is not implemented on other platforms: +//OPENCV_HAL_IMPL_VSX_PACK(v_uint32x4, uint, v_int64x2, unsigned long long, long long, +// vec_sra, vec_packsu, vec_add, pack_u) + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + vec_uchar16 ab = vec_pack(a.val, b.val); + return v_uint8x16(ab); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + vec_ushort8 ab = vec_pack(a.val, b.val); + vec_ushort8 cd = vec_pack(c.val, d.val); + return v_uint8x16(vec_pack(ab, cd)); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + vec_uint4 ab = vec_pack(a.val, b.val); + vec_uint4 cd = vec_pack(c.val, d.val); + vec_uint4 ef = vec_pack(e.val, f.val); + vec_uint4 gh = vec_pack(g.val, h.val); + + vec_ushort8 abcd = vec_pack(ab, cd); + vec_ushort8 efgh = vec_pack(ef, gh); + return v_uint8x16(vec_pack(abcd, efgh)); +} + +/* Recombine */ +template +inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, _Tpvec& b0, _Tpvec& b1) +{ + b0.val = vec_mergeh(a0.val, a1.val); + b1.val = vec_mergel(a0.val, a1.val); +} + +template +inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(vec_mergesql(a.val, b.val)); } + +template +inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(vec_mergesqh(a.val, b.val)); } + +template +inline void v_recombine(const _Tpvec& a, const _Tpvec& b, _Tpvec& c, _Tpvec& d) +{ + c.val = vec_mergesqh(a.val, b.val); + d.val = vec_mergesql(a.val, b.val); +} + +////////// Arithmetic, bitwise and comparison operations ///////// + +/* Element-wise binary and unary operations */ +/** Arithmetics **/ +#define OPENCV_HAL_IMPL_VSX_BIN_OP(bin_op, _Tpvec, intrin) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(intrin(a.val, b.val)); } \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ a.val = intrin(a.val, b.val); return a; } + +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint8x16, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint8x16, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int8x16, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int8x16, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint16x8, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint16x8, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int16x8, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int16x8, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint32x4, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint32x4, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_uint32x4, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int32x4, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int32x4, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_int32x4, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_float32x4, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_float32x4, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_float32x4, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(/, v_float32x4, vec_div) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_float64x2, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_float64x2, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_float64x2, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(/, v_float64x2, vec_div) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint64x2, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint64x2, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int64x2, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int64x2, vec_sub) + +// saturating multiply +#define OPENCV_HAL_IMPL_VSX_MUL_SAT(_Tpvec, _Tpwvec) \ + inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ + { \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ + } \ + inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ + { a = a * b; return a; } + +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_int16x8, v_int32x4) +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_uint16x8, v_uint32x4) + +template +inline void v_mul_expand(const Tvec& a, const Tvec& b, Twvec& c, Twvec& d) +{ + Twvec p0 = Twvec(vec_mule(a.val, b.val)); + Twvec p1 = Twvec(vec_mulo(a.val, b.val)); + v_zip(p0, p1, c, d); +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, v_uint64x2& c, v_uint64x2& d) +{ + c.val = vec_mul(vec_unpackhu(a.val), vec_unpackhu(b.val)); + d.val = vec_mul(vec_unpacklu(a.val), vec_unpacklu(b.val)); +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + vec_int4 p0 = vec_mule(a.val, b.val); + vec_int4 p1 = vec_mulo(a.val, b.val); + static const vec_uchar16 perm = {2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31}; + return v_int16x8(vec_perm(vec_short8_c(p0), vec_short8_c(p1), perm)); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + vec_uint4 p0 = vec_mule(a.val, b.val); + vec_uint4 p1 = vec_mulo(a.val, b.val); + static const vec_uchar16 perm = {2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31}; + return v_uint16x8(vec_perm(vec_ushort8_c(p0), vec_ushort8_c(p1), perm)); +} + +/** Non-saturating arithmetics **/ +#define OPENCV_HAL_IMPL_VSX_BIN_FUNC(func, intrin) \ +template \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(intrin(a.val, b.val)); } + +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_add_wrap, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_sub_wrap, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_mul_wrap, vec_mul) + +/** Bitwise shifts **/ +#define OPENCV_HAL_IMPL_VSX_SHIFT_OP(_Tpvec, shr, splfunc) \ +inline _Tpvec operator << (const _Tpvec& a, int imm) \ +{ return _Tpvec(vec_sl(a.val, splfunc(imm))); } \ +inline _Tpvec operator >> (const _Tpvec& a, int imm) \ +{ return _Tpvec(shr(a.val, splfunc(imm))); } \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ return _Tpvec(vec_sl(a.val, splfunc(imm))); } \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ return _Tpvec(shr(a.val, splfunc(imm))); } + +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint8x16, vec_sr, vec_uchar16_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint16x8, vec_sr, vec_ushort8_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint32x4, vec_sr, vec_uint4_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint64x2, vec_sr, vec_udword2_sp) +// algebraic right shift +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int8x16, vec_sra, vec_uchar16_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int16x8, vec_sra, vec_ushort8_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int32x4, vec_sra, vec_uint4_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int64x2, vec_sra, vec_udword2_sp) + +/** Bitwise logic **/ +#define OPENCV_HAL_IMPL_VSX_LOGIC_OP(_Tpvec) \ +OPENCV_HAL_IMPL_VSX_BIN_OP(&, _Tpvec, vec_and) \ +OPENCV_HAL_IMPL_VSX_BIN_OP(|, _Tpvec, vec_or) \ +OPENCV_HAL_IMPL_VSX_BIN_OP(^, _Tpvec, vec_xor) \ +inline _Tpvec operator ~ (const _Tpvec& a) \ +{ return _Tpvec(vec_not(a.val)); } + +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint8x16) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int8x16) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint16x8) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int16x8) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint32x4) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int32x4) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint64x2) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int64x2) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_float32x4) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_float64x2) + +/** Bitwise select **/ +#define OPENCV_HAL_IMPL_VSX_SELECT(_Tpvec, cast) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_sel(b.val, a.val, cast(mask.val))); } + +OPENCV_HAL_IMPL_VSX_SELECT(v_uint8x16, vec_bchar16_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_int8x16, vec_bchar16_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_uint16x8, vec_bshort8_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_int16x8, vec_bshort8_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_uint32x4, vec_bint4_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_int32x4, vec_bint4_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_float32x4, vec_bint4_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_float64x2, vec_bdword2_c) + +/** Comparison **/ +#define OPENCV_HAL_IMPL_VSX_INT_CMP_OP(_Tpvec) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpeq(a.val, b.val)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpne(a.val, b.val)); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmplt(a.val, b.val)); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpgt(a.val, b.val)); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmple(a.val, b.val)); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpge(a.val, b.val)); } + +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint8x16) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int8x16) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint16x8) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int16x8) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint32x4) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int32x4) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_float32x4) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_float64x2) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint64x2) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int64x2) + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return v_float32x4(vec_cmpeq(a.val, a.val)); } +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return v_float64x2(vec_cmpeq(a.val, a.val)); } + +/** min/max **/ +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_min, vec_min) +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_max, vec_max) + +/** Rotate **/ +#define OPENCV_IMPL_VSX_ROTATE(_Tpvec, suffix, shf, cast) \ +template \ +inline _Tpvec v_rotate_##suffix(const _Tpvec& a) \ +{ \ + const int wd = imm * sizeof(typename _Tpvec::lane_type); \ + if (wd > 15) \ + return _Tpvec(); \ + return _Tpvec((cast)shf(vec_uchar16_c(a.val), vec_uchar16_sp(wd << 3))); \ +} + +#define OPENCV_IMPL_VSX_ROTATE_LR(_Tpvec, cast) \ +OPENCV_IMPL_VSX_ROTATE(_Tpvec, left, vec_slo, cast) \ +OPENCV_IMPL_VSX_ROTATE(_Tpvec, right, vec_sro, cast) + +OPENCV_IMPL_VSX_ROTATE_LR(v_uint8x16, vec_uchar16) +OPENCV_IMPL_VSX_ROTATE_LR(v_int8x16, vec_char16) +OPENCV_IMPL_VSX_ROTATE_LR(v_uint16x8, vec_ushort8) +OPENCV_IMPL_VSX_ROTATE_LR(v_int16x8, vec_short8) +OPENCV_IMPL_VSX_ROTATE_LR(v_uint32x4, vec_uint4) +OPENCV_IMPL_VSX_ROTATE_LR(v_int32x4, vec_int4) +OPENCV_IMPL_VSX_ROTATE_LR(v_float32x4, vec_float4) +OPENCV_IMPL_VSX_ROTATE_LR(v_uint64x2, vec_udword2) +OPENCV_IMPL_VSX_ROTATE_LR(v_int64x2, vec_dword2) +OPENCV_IMPL_VSX_ROTATE_LR(v_float64x2, vec_double2) + +template +inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) +{ + enum { CV_SHIFT = 16 - imm * (sizeof(typename _Tpvec::lane_type)) }; + if (CV_SHIFT == 16) + return a; +#ifdef __IBMCPP__ + return _Tpvec(vec_sld(b.val, a.val, CV_SHIFT & 15)); +#else + return _Tpvec(vec_sld(b.val, a.val, CV_SHIFT)); +#endif +} + +template +inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) +{ + enum { CV_SHIFT = imm * (sizeof(typename _Tpvec::lane_type)) }; + if (CV_SHIFT == 16) + return b; + return _Tpvec(vec_sld(a.val, b.val, CV_SHIFT)); +} + +#define OPENCV_IMPL_VSX_ROTATE_64_2RG(_Tpvec, suffix, rg1, rg2) \ +template \ +inline _Tpvec v_rotate_##suffix(const _Tpvec& a, const _Tpvec& b) \ +{ \ + if (imm == 1) \ + return _Tpvec(vec_permi(rg1.val, rg2.val, 2)); \ + return imm ? b : a; \ +} + +#define OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(_Tpvec) \ +OPENCV_IMPL_VSX_ROTATE_64_2RG(_Tpvec, left, b, a) \ +OPENCV_IMPL_VSX_ROTATE_64_2RG(_Tpvec, right, a, b) + +OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(v_float64x2) +OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(v_uint64x2) +OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(v_int64x2) + +/* Extract */ +template +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) +{ return v_rotate_right(a, b); } + +////////// Reduce and mask ///////// + +/** Reduce **/ +inline short v_reduce_sum(const v_int16x8& a) +{ + const vec_int4 zero = vec_int4_z; + return saturate_cast(vec_extract(vec_sums(vec_sum4s(a.val, zero), zero), 3)); +} +inline ushort v_reduce_sum(const v_uint16x8& a) +{ + const vec_int4 v4 = vec_int4_c(vec_unpackhu(vec_adds(a.val, vec_sld(a.val, a.val, 8)))); + return saturate_cast(vec_extract(vec_sums(v4, vec_int4_z), 3)); +} + +#define OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(_Tpvec, _Tpvec2, scalartype, suffix, func) \ +inline scalartype v_reduce_##suffix(const _Tpvec& a) \ +{ \ + const _Tpvec2 rs = func(a.val, vec_sld(a.val, a.val, 8)); \ + return vec_extract(func(rs, vec_sld(rs, rs, 4)), 0); \ +} +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_uint32x4, vec_uint4, uint, sum, vec_add) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_uint32x4, vec_uint4, uint, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_uint32x4, vec_uint4, uint, min, vec_min) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_int32x4, vec_int4, int, sum, vec_add) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_int32x4, vec_int4, int, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_int32x4, vec_int4, int, min, vec_min) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_float32x4, vec_float4, float, sum, vec_add) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_float32x4, vec_float4, float, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_float32x4, vec_float4, float, min, vec_min) + +inline double v_reduce_sum(const v_float64x2& a) +{ + return vec_extract(vec_add(a.val, vec_permi(a.val, a.val, 3)), 0); +} + +#define OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(_Tpvec, _Tpvec2, scalartype, suffix, func) \ +inline scalartype v_reduce_##suffix(const _Tpvec& a) \ +{ \ + _Tpvec2 rs = func(a.val, vec_sld(a.val, a.val, 8)); \ + rs = func(rs, vec_sld(rs, rs, 4)); \ + return vec_extract(func(rs, vec_sld(rs, rs, 2)), 0); \ +} +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_uint16x8, vec_ushort8, ushort, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_uint16x8, vec_ushort8, ushort, min, vec_min) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_int16x8, vec_short8, short, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_int16x8, vec_short8, short, min, vec_min) + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + vec_float4 ac = vec_add(vec_mergel(a.val, c.val), vec_mergeh(a.val, c.val)); + ac = vec_add(ac, vec_sld(ac, ac, 8)); + + vec_float4 bd = vec_add(vec_mergel(b.val, d.val), vec_mergeh(b.val, d.val)); + bd = vec_add(bd, vec_sld(bd, bd, 8)); + return v_float32x4(vec_mergeh(ac, bd)); +} + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ + const vec_uint4 zero4 = vec_uint4_z; + vec_uint4 sum4 = vec_sum4s(vec_absd(a.val, b.val), zero4); + return (unsigned)vec_extract(vec_sums(vec_int4_c(sum4), vec_int4_c(zero4)), 3); +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ + const vec_int4 zero4 = vec_int4_z; + vec_char16 ad = vec_abss(vec_subs(a.val, b.val)); + vec_int4 sum4 = vec_sum4s(ad, zero4); + return (unsigned)vec_extract(vec_sums(sum4, zero4), 3); +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ + vec_ushort8 ad = vec_absd(a.val, b.val); + VSX_UNUSED(vec_int4) sum = vec_sums(vec_int4_c(vec_unpackhu(ad)), vec_int4_c(vec_unpacklu(ad))); + return (unsigned)vec_extract(sum, 3); +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ + const vec_int4 zero4 = vec_int4_z; + vec_short8 ad = vec_abss(vec_subs(a.val, b.val)); + vec_int4 sum4 = vec_sum4s(ad, zero4); + return (unsigned)vec_extract(vec_sums(sum4, zero4), 3); +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ + const vec_uint4 ad = vec_absd(a.val, b.val); + const vec_uint4 rd = vec_add(ad, vec_sld(ad, ad, 8)); + return vec_extract(vec_add(rd, vec_sld(rd, rd, 4)), 0); +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ + vec_int4 ad = vec_abss(vec_sub(a.val, b.val)); + return (unsigned)vec_extract(vec_sums(ad, vec_int4_z), 3); +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + const vec_float4 ad = vec_abs(vec_sub(a.val, b.val)); + const vec_float4 rd = vec_add(ad, vec_sld(ad, ad, 8)); + return vec_extract(vec_add(rd, vec_sld(rd, rd, 4)), 0); +} + +/** Popcount **/ +template +inline v_uint32x4 v_popcount(const _Tpvec& a) +{ return v_uint32x4(vec_popcntu(vec_uint4_c(a.val))); } + +/** Mask **/ +inline int v_signmask(const v_uint8x16& a) +{ + vec_uchar16 sv = vec_sr(a.val, vec_uchar16_sp(7)); + static const vec_uchar16 slm = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7}; + sv = vec_sl(sv, slm); + vec_uint4 sv4 = vec_sum4s(sv, vec_uint4_z); + static const vec_uint4 slm4 = {0, 0, 8, 8}; + sv4 = vec_sl(sv4, slm4); + return vec_extract(vec_sums((vec_int4) sv4, vec_int4_z), 3); +} +inline int v_signmask(const v_int8x16& a) +{ return v_signmask(v_reinterpret_as_u8(a)); } + +inline int v_signmask(const v_int16x8& a) +{ + static const vec_ushort8 slm = {0, 1, 2, 3, 4, 5, 6, 7}; + vec_short8 sv = vec_sr(a.val, vec_ushort8_sp(15)); + sv = vec_sl(sv, slm); + vec_int4 svi = vec_int4_z; + svi = vec_sums(vec_sum4s(sv, svi), svi); + return vec_extract(svi, 3); +} +inline int v_signmask(const v_uint16x8& a) +{ return v_signmask(v_reinterpret_as_s16(a)); } + +inline int v_signmask(const v_int32x4& a) +{ + static const vec_uint4 slm = {0, 1, 2, 3}; + vec_int4 sv = vec_sr(a.val, vec_uint4_sp(31)); + sv = vec_sl(sv, slm); + sv = vec_sums(sv, vec_int4_z); + return vec_extract(sv, 3); +} +inline int v_signmask(const v_uint32x4& a) +{ return v_signmask(v_reinterpret_as_s32(a)); } +inline int v_signmask(const v_float32x4& a) +{ return v_signmask(v_reinterpret_as_s32(a)); } + +inline int v_signmask(const v_int64x2& a) +{ + VSX_UNUSED(const vec_dword2) sv = vec_sr(a.val, vec_udword2_sp(63)); + return (int)vec_extract(sv, 0) | (int)vec_extract(sv, 1) << 1; +} +inline int v_signmask(const v_uint64x2& a) +{ return v_signmask(v_reinterpret_as_s64(a)); } +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_s64(a)); } + +template +inline bool v_check_all(const _Tpvec& a) +{ return vec_all_lt(a.val, _Tpvec().val); } +inline bool v_check_all(const v_uint8x16& a) +{ return v_check_all(v_reinterpret_as_s8(a)); } +inline bool v_check_all(const v_uint16x8& a) +{ return v_check_all(v_reinterpret_as_s16(a)); } +inline bool v_check_all(const v_uint32x4& a) +{ return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_s64(a)); } + +template +inline bool v_check_any(const _Tpvec& a) +{ return vec_any_lt(a.val, _Tpvec().val); } +inline bool v_check_any(const v_uint8x16& a) +{ return v_check_any(v_reinterpret_as_s8(a)); } +inline bool v_check_any(const v_uint16x8& a) +{ return v_check_any(v_reinterpret_as_s16(a)); } +inline bool v_check_any(const v_uint32x4& a) +{ return v_check_any(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_s64(a)); } + +////////// Other math ///////// + +/** Some frequent operations **/ +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ return v_float32x4(vec_sqrt(x.val)); } +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ return v_float64x2(vec_sqrt(x.val)); } + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ return v_float32x4(vec_rsqrt(x.val)); } +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ return v_float64x2(vec_rsqrt(x.val)); } + +#define OPENCV_HAL_IMPL_VSX_MULADD(_Tpvec) \ +inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_sqrt(vec_madd(a.val, a.val, vec_mul(b.val, b.val)))); } \ +inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_madd(a.val, a.val, vec_mul(b.val, b.val))); } \ +inline _Tpvec v_fma(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ +{ return _Tpvec(vec_madd(a.val, b.val, c.val)); } \ +inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ +{ return _Tpvec(vec_madd(a.val, b.val, c.val)); } + +OPENCV_HAL_IMPL_VSX_MULADD(v_float32x4) +OPENCV_HAL_IMPL_VSX_MULADD(v_float64x2) + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ return a * b + c; } + +// TODO: exp, log, sin, cos + +/** Absolute values **/ +inline v_uint8x16 v_abs(const v_int8x16& x) +{ return v_uint8x16(vec_uchar16_c(vec_abs(x.val))); } + +inline v_uint16x8 v_abs(const v_int16x8& x) +{ return v_uint16x8(vec_ushort8_c(vec_abs(x.val))); } + +inline v_uint32x4 v_abs(const v_int32x4& x) +{ return v_uint32x4(vec_uint4_c(vec_abs(x.val))); } + +inline v_float32x4 v_abs(const v_float32x4& x) +{ return v_float32x4(vec_abs(x.val)); } + +inline v_float64x2 v_abs(const v_float64x2& x) +{ return v_float64x2(vec_abs(x.val)); } + +/** Absolute difference **/ +// unsigned +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_absdiff, vec_absd) + +inline v_uint8x16 v_absdiff(const v_int8x16& a, const v_int8x16& b) +{ return v_reinterpret_as_u8(v_sub_wrap(v_max(a, b), v_min(a, b))); } +inline v_uint16x8 v_absdiff(const v_int16x8& a, const v_int16x8& b) +{ return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); } +inline v_uint32x4 v_absdiff(const v_int32x4& a, const v_int32x4& b) +{ return v_reinterpret_as_u32(v_max(a, b) - v_min(a, b)); } + +inline v_float32x4 v_absdiff(const v_float32x4& a, const v_float32x4& b) +{ return v_abs(a - b); } +inline v_float64x2 v_absdiff(const v_float64x2& a, const v_float64x2& b) +{ return v_abs(a - b); } + +/** Absolute difference for signed integers **/ +inline v_int8x16 v_absdiffs(const v_int8x16& a, const v_int8x16& b) +{ return v_int8x16(vec_abss(vec_subs(a.val, b.val))); } +inline v_int16x8 v_absdiffs(const v_int16x8& a, const v_int16x8& b) +{ return v_int16x8(vec_abss(vec_subs(a.val, b.val))); } + +////////// Conversions ///////// + +/** Rounding **/ +inline v_int32x4 v_round(const v_float32x4& a) +{ return v_int32x4(vec_cts(vec_rint(a.val))); } + +inline v_int32x4 v_round(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_rint(a.val)), vec_int4_z)); } + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_rint(a.val)), vec_ctso(vec_rint(b.val)))); } + +inline v_int32x4 v_floor(const v_float32x4& a) +{ return v_int32x4(vec_cts(vec_floor(a.val))); } + +inline v_int32x4 v_floor(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_floor(a.val)), vec_int4_z)); } + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ return v_int32x4(vec_cts(vec_ceil(a.val))); } + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_ceil(a.val)), vec_int4_z)); } + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ return v_int32x4(vec_cts(a.val)); } + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(a.val), vec_int4_z)); } + +/** To float **/ +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ return v_float32x4(vec_ctf(a.val)); } + +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ return v_float32x4(vec_mergesqo(vec_cvfo(a.val), vec_float4_z)); } + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ return v_float32x4(vec_mergesqo(vec_cvfo(a.val), vec_cvfo(b.val))); } + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ return v_float64x2(vec_ctdo(vec_mergeh(a.val, a.val))); } + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ return v_float64x2(vec_ctdo(vec_mergel(a.val, a.val))); } + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ return v_float64x2(vec_cvfo(vec_mergeh(a.val, a.val))); } + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ return v_float64x2(vec_cvfo(vec_mergel(a.val, a.val))); } + +////////////// Lookup table access //////////////////// + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + return v_int32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + return v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + return v_float64x2(tab[idx[0]], tab[idx[1]]); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + x = v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); + y = v_float32x4(tab[idx[0]+1], tab[idx[1]+1], tab[idx[2]+1], tab[idx[3]+1]); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + x = v_float64x2(tab[idx[0]], tab[idx[1]]); + y = v_float64x2(tab[idx[0]+1], tab[idx[1]+1]); +} + +/////// FP16 support //////// + +// [TODO] implement these 2 using VSX or universal intrinsics (copy from intrin_sse.cpp and adopt) +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + return v_float32x4((float)ptr[0], (float)ptr[1], (float)ptr[2], (float)ptr[3]); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + float CV_DECL_ALIGNED(32) f[4]; + v_store_aligned(f, v); + ptr[0] = float16_t(f[0]); + ptr[1] = float16_t(f[1]); + ptr[2] = float16_t(f[2]); + ptr[3] = float16_t(f[3]); +} + +inline void v_cleanup() {} + + +/** Reinterpret **/ +/** its up there with load and store operations **/ + +////////// Matrix operations ///////// + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ return v_int32x4(vec_msum(a.val, b.val, vec_int4_z)); } + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_int32x4(vec_msum(a.val, b.val, c.val)); } + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + const vec_float4 v0 = vec_splat(v.val, 0); + const vec_float4 v1 = vec_splat(v.val, 1); + const vec_float4 v2 = vec_splat(v.val, 2); + VSX_UNUSED(const vec_float4) v3 = vec_splat(v.val, 3); + return v_float32x4(vec_madd(v0, m0.val, vec_madd(v1, m1.val, vec_madd(v2, m2.val, vec_mul(v3, m3.val))))); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + const vec_float4 v0 = vec_splat(v.val, 0); + const vec_float4 v1 = vec_splat(v.val, 1); + const vec_float4 v2 = vec_splat(v.val, 2); + return v_float32x4(vec_madd(v0, m0.val, vec_madd(v1, m1.val, vec_madd(v2, m2.val, a.val)))); +} + +#define OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(_Tpvec, _Tpvec2) \ +inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, _Tpvec& b2, _Tpvec& b3) \ +{ \ + _Tpvec2 a02 = vec_mergeh(a0.val, a2.val); \ + _Tpvec2 a13 = vec_mergeh(a1.val, a3.val); \ + b0.val = vec_mergeh(a02, a13); \ + b1.val = vec_mergel(a02, a13); \ + a02 = vec_mergel(a0.val, a2.val); \ + a13 = vec_mergel(a1.val, a3.val); \ + b2.val = vec_mergeh(a02, a13); \ + b3.val = vec_mergel(a02, a13); \ +} +OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_uint32x4, vec_uint4) +OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_int32x4, vec_int4) +OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_float32x4, vec_float4) + +//! @name Check SIMD support +//! @{ +//! @brief Check CPU capability of SIMD operation +static inline bool hasSIMD128() +{ + return (CV_CPU_HAS_SUPPORT_VSX) ? true : false; +} + +//! @} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif // OPENCV_HAL_VSX_HPP diff --git a/include/opencv2/core/ippasync.hpp b/include/opencv2/core/ippasync.hpp index 4de8611..c35d8d8 100644 --- a/include/opencv2/core/ippasync.hpp +++ b/include/opencv2/core/ippasync.hpp @@ -42,10 +42,10 @@ // //M*/ -#ifndef __OPENCV_CORE_IPPASYNC_HPP__ -#define __OPENCV_CORE_IPPASYNC_HPP__ +#ifndef OPENCV_CORE_IPPASYNC_HPP +#define OPENCV_CORE_IPPASYNC_HPP -#ifdef HAVE_IPP_A +#ifdef HAVE_IPP_A // this file will be removed in OpenCV 4.0 #include "opencv2/core.hpp" #include diff --git a/include/opencv2/core/mat.hpp b/include/opencv2/core/mat.hpp index 45f3cef..c0893b3 100644 --- a/include/opencv2/core/mat.hpp +++ b/include/opencv2/core/mat.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CORE_MAT_HPP__ -#define __OPENCV_CORE_MAT_HPP__ +#ifndef OPENCV_CORE_MAT_HPP +#define OPENCV_CORE_MAT_HPP #ifndef __cplusplus # error mat.hpp header must be compiled as C++ @@ -53,6 +53,10 @@ #include "opencv2/core/bufferpool.hpp" +#ifdef CV_CXX11 +#include +#endif + namespace cv { @@ -62,6 +66,8 @@ namespace cv enum { ACCESS_READ=1<<24, ACCESS_WRITE=1<<25, ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26 }; +CV__DEBUG_NS_BEGIN + class CV_EXPORTS _OutputArray; //////////////////////// Input/Output Array Arguments ///////////////////////////////// @@ -73,8 +79,8 @@ It is defined as: typedef const _InputArray& InputArray; @endcode where _InputArray is a class that can be constructed from `Mat`, `Mat_`, `Matx`, -`std::vector`, `std::vector >` or `std::vector`. It can also be constructed -from a matrix expression. +`std::vector`, `std::vector >`, `std::vector`, `std::vector >`, +`UMat`, `std::vector` or `double`. It can also be constructed from a matrix expression. Since this is mostly implementation-level class, and its interface may change in future versions, we do not describe it in details. There are a few key things, though, that should be kept in mind: @@ -142,6 +148,12 @@ synonym is needed to generate Python/Java etc. wrappers properly. At the functio level their use is similar, but _InputArray::getMat(idx) should be used to get header for the idx-th component of the outer vector and _InputArray::size().area() should be used to find the number of components (vectors/matrices) of the outer vector. + +In general, type support is limited to cv::Mat types. Other types are forbidden. +But in some cases we need to support passing of custom non-general Mat types, like arrays of cv::KeyPoint, cv::DMatch, etc. +This data is not intented to be interpreted as an image data, or processed somehow like regular cv::Mat. +To pass such custom type use rawIn() / rawOut() / rawInOut() wrappers. +Custom type is wrapped as Mat-compatible `CV_8UC` values (N = sizeof(T), N <= CV_CN_MAX). */ class CV_EXPORTS _InputArray { @@ -164,7 +176,10 @@ public: CUDA_GPU_MAT = 9 << KIND_SHIFT, UMAT =10 << KIND_SHIFT, STD_VECTOR_UMAT =11 << KIND_SHIFT, - STD_BOOL_VECTOR =12 << KIND_SHIFT + STD_BOOL_VECTOR =12 << KIND_SHIFT, + STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT, + STD_ARRAY =14 << KIND_SHIFT, + STD_ARRAY_MAT =15 << KIND_SHIFT }; _InputArray(); @@ -176,22 +191,35 @@ public: template _InputArray(const std::vector<_Tp>& vec); _InputArray(const std::vector& vec); template _InputArray(const std::vector >& vec); + _InputArray(const std::vector >&); template _InputArray(const std::vector >& vec); template _InputArray(const _Tp* vec, int n); template _InputArray(const Matx<_Tp, m, n>& matx); _InputArray(const double& val); _InputArray(const cuda::GpuMat& d_mat); + _InputArray(const std::vector& d_mat_array); _InputArray(const ogl::Buffer& buf); _InputArray(const cuda::HostMem& cuda_mem); template _InputArray(const cudev::GpuMat_<_Tp>& m); _InputArray(const UMat& um); _InputArray(const std::vector& umv); +#ifdef CV_CXX_STD_ARRAY + template _InputArray(const std::array<_Tp, _Nm>& arr); + template _InputArray(const std::array& arr); +#endif + + template static _InputArray rawIn(const std::vector<_Tp>& vec); +#ifdef CV_CXX_STD_ARRAY + template static _InputArray rawIn(const std::array<_Tp, _Nm>& arr); +#endif + Mat getMat(int idx=-1) const; Mat getMat_(int idx=-1) const; UMat getUMat(int idx=-1) const; void getMatVector(std::vector& mv) const; void getUMatVector(std::vector& umv) const; + void getGpuMatVector(std::vector& gpumv) const; cuda::GpuMat getGpuMat() const; ogl::Buffer getOGlBuffer() const; @@ -222,7 +250,9 @@ public: bool isMatVector() const; bool isUMatVector() const; bool isMatx() const; - + bool isVector() const; + bool isGpuMat() const; + bool isGpuMatVector() const; ~_InputArray(); protected: @@ -282,12 +312,14 @@ public: _OutputArray(Mat& m); _OutputArray(std::vector& vec); _OutputArray(cuda::GpuMat& d_mat); + _OutputArray(std::vector& d_mat); _OutputArray(ogl::Buffer& buf); _OutputArray(cuda::HostMem& cuda_mem); template _OutputArray(cudev::GpuMat_<_Tp>& m); template _OutputArray(std::vector<_Tp>& vec); _OutputArray(std::vector& vec); template _OutputArray(std::vector >& vec); + _OutputArray(std::vector >&); template _OutputArray(std::vector >& vec); template _OutputArray(Mat_<_Tp>& m); template _OutputArray(_Tp* vec, int n); @@ -298,6 +330,7 @@ public: _OutputArray(const Mat& m); _OutputArray(const std::vector& vec); _OutputArray(const cuda::GpuMat& d_mat); + _OutputArray(const std::vector& d_mat); _OutputArray(const ogl::Buffer& buf); _OutputArray(const cuda::HostMem& cuda_mem); template _OutputArray(const cudev::GpuMat_<_Tp>& m); @@ -310,12 +343,25 @@ public: _OutputArray(const UMat& m); _OutputArray(const std::vector& vec); +#ifdef CV_CXX_STD_ARRAY + template _OutputArray(std::array<_Tp, _Nm>& arr); + template _OutputArray(const std::array<_Tp, _Nm>& arr); + template _OutputArray(std::array& arr); + template _OutputArray(const std::array& arr); +#endif + + template static _OutputArray rawOut(std::vector<_Tp>& vec); +#ifdef CV_CXX_STD_ARRAY + template static _OutputArray rawOut(std::array<_Tp, _Nm>& arr); +#endif + bool fixedSize() const; bool fixedType() const; bool needed() const; Mat& getMatRef(int i=-1) const; UMat& getUMatRef(int i=-1) const; cuda::GpuMat& getGpuMatRef() const; + std::vector& getGpuMatVecRef() const; ogl::Buffer& getOGlBufferRef() const; cuda::HostMem& getHostMemRef() const; void create(Size sz, int type, int i=-1, bool allowTransposed=false, int fixedDepthMask=0) const; @@ -328,6 +374,9 @@ public: void assign(const UMat& u) const; void assign(const Mat& m) const; + + void assign(const std::vector& v) const; + void assign(const std::vector& v) const; }; @@ -355,6 +404,7 @@ public: _InputOutputArray(const Mat& m); _InputOutputArray(const std::vector& vec); _InputOutputArray(const cuda::GpuMat& d_mat); + _InputOutputArray(const std::vector& d_mat); _InputOutputArray(const ogl::Buffer& buf); _InputOutputArray(const cuda::HostMem& cuda_mem); template _InputOutputArray(const cudev::GpuMat_<_Tp>& m); @@ -366,8 +416,30 @@ public: template _InputOutputArray(const Matx<_Tp, m, n>& matx); _InputOutputArray(const UMat& m); _InputOutputArray(const std::vector& vec); + +#ifdef CV_CXX_STD_ARRAY + template _InputOutputArray(std::array<_Tp, _Nm>& arr); + template _InputOutputArray(const std::array<_Tp, _Nm>& arr); + template _InputOutputArray(std::array& arr); + template _InputOutputArray(const std::array& arr); +#endif + + template static _InputOutputArray rawInOut(std::vector<_Tp>& vec); +#ifdef CV_CXX_STD_ARRAY + template _InputOutputArray rawInOut(std::array<_Tp, _Nm>& arr); +#endif + }; +/** Helper to wrap custom types. @see InputArray */ +template static inline _InputArray rawIn(_Tp& v); +/** Helper to wrap custom types. @see InputArray */ +template static inline _OutputArray rawOut(_Tp& v); +/** Helper to wrap custom types. @see InputArray */ +template static inline _InputOutputArray rawInOut(_Tp& v); + +CV__DEBUG_NS_END + typedef const _InputArray& InputArray; typedef InputArray InputArrayOfArrays; typedef const _OutputArray& OutputArray; @@ -465,7 +537,9 @@ struct CV_EXPORTS UMatData { enum { COPY_ON_MAP=1, HOST_COPY_OBSOLETE=2, DEVICE_COPY_OBSOLETE=4, TEMP_UMAT=8, TEMP_COPIED_UMAT=24, - USER_ALLOCATED=32, DEVICE_MEM_MAPPED=64}; + USER_ALLOCATED=32, DEVICE_MEM_MAPPED=64, + ASYNC_CLEANUP=128 + }; UMatData(const MatAllocator* allocator); ~UMatData(); @@ -495,24 +569,19 @@ struct CV_EXPORTS UMatData void* handle; void* userdata; int allocatorFlags_; -}; - - -struct CV_EXPORTS UMatDataAutoLock -{ - explicit UMatDataAutoLock(UMatData* u); - ~UMatDataAutoLock(); - UMatData* u; + int mapcount; + UMatData* originalUMatData; }; struct CV_EXPORTS MatSize { explicit MatSize(int* _p); + int dims() const; Size operator()() const; const int& operator[](int i) const; int& operator[](int i); - operator const int*() const; + operator const int*() const; // TODO OpenCV 4.0: drop this bool operator == (const MatSize& sz) const; bool operator != (const MatSize& sz) const; @@ -534,11 +603,11 @@ protected: MatStep& operator = (const MatStep&); }; -/** @example cout_mat.cpp +/** @example samples/cpp/cout_mat.cpp An example demonstrating the serial out capabilities of cv::Mat */ - /** @brief n-dimensional dense array class + /** @brief n-dimensional dense array class \anchor CVMat_Details The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel @@ -650,7 +719,7 @@ sub-matrices. - Use MATLAB-style array initializers, zeros(), ones(), eye(), for example: @code - // create a double-precision identity martix and add it to M. + // create a double-precision identity matrix and add it to M. M += Mat::eye(M.rows, M.cols, CV_64F); @endcode @@ -683,7 +752,7 @@ If you need to process a whole row of a 2D array, the most efficient way is to g the row first, and then just use the plain C operator [] : @code // compute sum of positive matrix elements - // (assuming that M isa double-precision matrix) + // (assuming that M is a double-precision matrix) double sum=0; for(int i = 0; i < M.rows; i++) { @@ -726,6 +795,8 @@ Finally, there are STL-style iterators that are smart enough to skip gaps betwee @endcode The matrix iterators are random-access iterators, so they can be passed to any STL algorithm, including std::sort(). + +@note Matrix Expressions and arithmetic see MatExpr */ class CV_EXPORTS Mat { @@ -784,6 +855,13 @@ public: */ Mat(int ndims, const int* sizes, int type); + /** @overload + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + */ + Mat(const std::vector& sizes, int type); + /** @overload @param ndims Array dimensionality. @param sizes Array of integers specifying an n-dimensional array shape. @@ -795,6 +873,17 @@ public: */ Mat(int ndims, const int* sizes, int type, const Scalar& s); + /** @overload + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param s An optional value to initialize each matrix element with. To set all the matrix elements to + the particular value after the construction, use the assignment operator + Mat::operator=(const Scalar& value) . + */ + Mat(const std::vector& sizes, int type, const Scalar& s); + + /** @overload @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead, the header pointing to m data or its sub-array is constructed and @@ -851,6 +940,20 @@ public: */ Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0); + /** @overload + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param data Pointer to the user data. Matrix constructors that take data and step parameters do not + allocate matrix data. Instead, they just initialize the matrix header that points to the specified + data, which means that no data is copied. This operation is very efficient and can be used to + process external data using OpenCV functions. The external data is not automatically deallocated, so + you should take care of it. + @param steps Array of ndims-1 steps in case of a multi-dimensional array (the last step is always + set to the element size). If not specified, the matrix is assumed to be continuous. + */ + Mat(const std::vector& sizes, int type, void* data, const size_t* steps=0); + /** @overload @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead, the header pointing to m data or its sub-array is constructed and @@ -883,6 +986,16 @@ public: */ Mat(const Mat& m, const Range* ranges); + /** @overload + @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied + by these constructors. Instead, the header pointing to m data or its sub-array is constructed and + associated with it. The reference counter, if any, is incremented. So, when you modify the matrix + formed using such a constructor, you also modify the corresponding elements of m . If you want to + have an independent copy of the sub-array, use Mat::clone() . + @param ranges Array of selected ranges of m along each dimensionality. + */ + Mat(const Mat& m, const std::vector& ranges); + /** @overload @param vec STL vector whose elements form the matrix. The matrix has a single column and the number of rows equal to the number of vector elements. Type of the matrix matches the type of vector @@ -901,6 +1014,23 @@ public: */ template explicit Mat(const std::vector<_Tp>& vec, bool copyData=false); +#ifdef CV_CXX11 + /** @overload + */ + template::value>::type> + explicit Mat(const std::initializer_list<_Tp> list); + + /** @overload + */ + template explicit Mat(const std::initializer_list sizes, const std::initializer_list<_Tp> list); +#endif + +#ifdef CV_CXX_STD_ARRAY + /** @overload + */ + template explicit Mat(const std::array<_Tp, _Nm>& arr, bool copyData=false); +#endif + /** @overload */ template explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true); @@ -1027,18 +1157,40 @@ public: single-column matrix. Similarly to Mat::row and Mat::col, this is an O(1) operation. @param d index of the diagonal, with the following values: - `d=0` is the main diagonal. - - `d>0` is a diagonal from the lower half. For example, d=1 means the diagonal is set + - `d<0` is a diagonal from the lower half. For example, d=-1 means the diagonal is set immediately below the main one. - - `d<0` is a diagonal from the upper half. For example, d=-1 means the diagonal is set + - `d>0` is a diagonal from the upper half. For example, d=1 means the diagonal is set immediately above the main one. + For example: + @code + Mat m = (Mat_(3,3) << + 1,2,3, + 4,5,6, + 7,8,9); + Mat d0 = m.diag(0); + Mat d1 = m.diag(1); + Mat d_1 = m.diag(-1); + @endcode + The resulting matrices are + @code + d0 = + [1; + 5; + 9] + d1 = + [2; + 6] + d_1 = + [4; + 8] + @endcode */ Mat diag(int d=0) const; /** @brief creates a diagonal matrix - The method makes a new header for the specified matrix diagonal. The new matrix is represented as a - single-column matrix. Similarly to Mat::row and Mat::col, this is an O(1) operation. - @param d Single-column matrix that forms a diagonal matrix + The method creates a square diagonal matrix from specified main diagonal. + @param d One-dimensional matrix that represents the main diagonal. */ static Mat diag(const Mat& d); @@ -1047,7 +1199,7 @@ public: The method creates a full copy of the array. The original step[] is not taken into account. So, the array copy is a continuous array occupying total()*elemSize() bytes. */ - Mat clone() const; + Mat clone() const CV_NODISCARD; /** @brief Copies the matrix to another one. @@ -1069,7 +1221,8 @@ public: /** @overload @param m Destination matrix. If it does not have a proper size or type before the operation, it is reallocated. - @param mask Operation mask. Its non-zero elements indicate which matrix elements need to be copied. + @param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix + elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels. */ void copyTo( OutputArray m, InputArray mask ) const; @@ -1105,7 +1258,8 @@ public: This is an advanced variant of the Mat::operator=(const Scalar& s) operator. @param value Assigned scalar converted to the actual array type. - @param mask Operation mask of the same size as \*this. + @param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix + elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels */ Mat& setTo(InputArray value, InputArray mask=noArray()); @@ -1138,6 +1292,9 @@ public: /** @overload */ Mat reshape(int cn, int newndims, const int* newsz) const; + /** @overload */ + Mat reshape(int cn, const std::vector& newshape) const; + /** @brief Transposes a matrix. The method performs matrix transposition by means of matrix expressions. It does not perform the @@ -1195,7 +1352,7 @@ public: /** @brief Returns a zero array of the specified size and type. The method returns a Matlab-style zero array initializer. It can be used to quickly form a constant - array as a function parameter, part of a matrix expression, or as a matrix initializer. : + array as a function parameter, part of a matrix expression, or as a matrix initializer: @code Mat A; A = Mat::zeros(3, 3, CV_32F); @@ -1231,6 +1388,8 @@ public: The above operation does not form a 100x100 matrix of 1's and then multiply it by 3. Instead, it just remembers the scale factor (3 in this case) and use it when actually invoking the matrix initializer. + @note In case of multi-channels type, only the first channel will be initialized with 1's, the + others will be set to 0's. @param rows Number of rows. @param cols Number of columns. @param type Created matrix type. @@ -1258,6 +1417,8 @@ public: // make a 4x4 diagonal matrix with 0.1's on the diagonal. Mat A = Mat::eye(4, 4, CV_32F)*0.1; @endcode + @note In case of multi-channels type, identity matrix will be initialized only for the first channel, + the others will be set to 0's @param rows Number of rows. @param cols Number of columns. @param type Created matrix type. @@ -1318,6 +1479,12 @@ public: */ void create(int ndims, const int* sizes, int type); + /** @overload + @param sizes Array of integers specifying a new array shape. + @param type New matrix type. + */ + void create(const std::vector& sizes, int type); + /** @brief Increments the reference counter. The method increments the reference counter associated with the matrix data. If the matrix header @@ -1344,7 +1511,7 @@ public: */ void release(); - //! deallocates the matrix data + //! internal use function, consider to use 'release' method instead; deallocates the matrix data void deallocate(); //! internal use function; properly re-allocates _size, _step arrays void copySize(const Mat& m); @@ -1358,6 +1525,14 @@ public: */ void reserve(size_t sz); + /** @brief Reserves space for the certain number of bytes. + + The method reserves space for sz bytes. If the matrix already has enough space to store sz bytes, + nothing happens. If matrix has to be reallocated its previous content could be lost. + @param sz Number of bytes. + */ + void reserveBuffer(size_t sz); + /** @brief Changes the number of matrix rows. The methods change the number of matrix rows. If the matrix is reallocated, the first @@ -1390,6 +1565,11 @@ public: */ template void push_back(const Mat_<_Tp>& elem); + /** @overload + @param elem Added element(s). + */ + template void push_back(const std::vector<_Tp>& elem); + /** @overload @param m Added line(s). */ @@ -1468,6 +1648,11 @@ public: */ Mat operator()( const Range* ranges ) const; + /** @overload + @param ranges Array of selected ranges along each array dimension. + */ + Mat operator()(const std::vector& ranges) const; + // //! converts header to CvMat; no data is copied // operator CvMat() const; // //! converts header to CvMatND; no data is copied @@ -1479,6 +1664,10 @@ public: template operator Vec<_Tp, n>() const; template operator Matx<_Tp, m, n>() const; +#ifdef CV_CXX_STD_ARRAY + template operator std::array<_Tp, _Nm>() const; +#endif + /** @brief Reports whether the matrix is continuous or not. The method returns true if the matrix elements are stored continuously without gaps at the end of @@ -1511,7 +1700,7 @@ public: inv_scale = 1.f/alpha_scale; CV_Assert( src1.type() == src2.type() && - src1.type() == CV_MAKETYPE(DataType::depth, 4) && + src1.type() == CV_MAKETYPE(traits::Depth::value, 4) && src1.size() == src2.size()); Size size = src1.size(); dst.create(size, src1.type()); @@ -1621,7 +1810,33 @@ public: */ size_t total() const; - //! returns N if the matrix is 1-channel (N x ptdim) or ptdim-channel (1 x N) or (N x 1); negative number otherwise + /** @brief Returns the total number of array elements. + + The method returns the number of elements within a certain sub-array slice with startDim <= dim < endDim + */ + size_t total(int startDim, int endDim=INT_MAX) const; + + /** + * @param elemChannels Number of channels or number of columns the matrix should have. + * For a 2-D matrix, when the matrix has only 1 column, then it should have + * elemChannels channels; When the matrix has only 1 channel, + * then it should have elemChannels columns. + * For a 3-D matrix, it should have only one channel. Furthermore, + * if the number of planes is not one, then the number of rows + * within every plane has to be 1; if the number of rows within + * every plane is not 1, then the number of planes has to be 1. + * @param depth The depth the matrix should have. Set it to -1 when any depth is fine. + * @param requireContinuous Set it to true to require the matrix to be continuous + * @return -1 if the requirement is not satisfied. + * Otherwise, it returns the number of elements in the matrix. Note + * that an element may have multiple channels. + * + * The following code demonstrates its usage for a 2-d matrix: + * @snippet snippets/core_mat_checkVector.cpp example-2d + * + * The following code demonstrates its usage for a 3-d matrix: + * @snippet snippets/core_mat_checkVector.cpp example-3d + */ int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const; /** @brief Returns a pointer to the specified matrix row. @@ -1634,10 +1849,16 @@ public: /** @overload */ const uchar* ptr(int i0=0) const; - /** @overload */ - uchar* ptr(int i0, int i1); - /** @overload */ - const uchar* ptr(int i0, int i1) const; + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + uchar* ptr(int row, int col); + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + const uchar* ptr(int row, int col) const; /** @overload */ uchar* ptr(int i0, int i1, int i2); @@ -1657,10 +1878,16 @@ public: template _Tp* ptr(int i0=0); /** @overload */ template const _Tp* ptr(int i0=0) const; - /** @overload */ - template _Tp* ptr(int i0, int i1); - /** @overload */ - template const _Tp* ptr(int i0, int i1) const; + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + template _Tp* ptr(int row, int col); + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + template const _Tp* ptr(int row, int col) const; /** @overload */ template _Tp* ptr(int i0, int i1, int i2); /** @overload */ @@ -1691,6 +1918,17 @@ public: for(int j = 0; j < H.cols; j++) H.at(i,j)=1./(i+j+1); @endcode + + Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends + on the image from which you are trying to retrieve the data. The table below gives a better insight in this: + - If matrix is of type `CV_8U` then use `Mat.at(y,x)`. + - If matrix is of type `CV_8S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_16U` then use `Mat.at(y,x)`. + - If matrix is of type `CV_16S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_32S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_32F` then use `Mat.at(y,x)`. + - If matrix is of type `CV_64F` then use `Mat.at(y,x)`. + @param i0 Index along the dimension 0 */ template _Tp& at(int i0=0); @@ -1699,15 +1937,15 @@ public: */ template const _Tp& at(int i0=0) const; /** @overload - @param i0 Index along the dimension 0 - @param i1 Index along the dimension 1 + @param row Index along the dimension 0 + @param col Index along the dimension 1 */ - template _Tp& at(int i0, int i1); + template _Tp& at(int row, int col); /** @overload - @param i0 Index along the dimension 0 - @param i1 Index along the dimension 1 + @param row Index along the dimension 0 + @param col Index along the dimension 1 */ - template const _Tp& at(int i0, int i1) const; + template const _Tp& at(int row, int col) const; /** @overload @param i0 Index along the dimension 0 @@ -1762,7 +2000,7 @@ public: inv_scale = 1.f/alpha_scale; CV_Assert( src1.type() == src2.type() && - src1.type() == DataType::type && + src1.type() == traits::Type::value && src1.size() == src2.size()); Size size = src1.size(); dst.create(size, src1.type()); @@ -1794,19 +2032,18 @@ public: template MatIterator_<_Tp> end(); template MatConstIterator_<_Tp> end() const; - /** @brief Invoke with arguments functor, and runs the functor over all matrix element. + /** @brief Runs the given functor over all matrix elements in parallel. - The methos runs operation in parallel. Operation is passed by arguments. Operation have to be a - function pointer, a function object or a lambda(C++11). + The operation passed as argument has to be a function pointer, a function object or a lambda(C++11). - All of below operation is equal. Put 0xFF to first channel of all matrix elements: + Example 1. All of the operations below put 0xFF the first channel of all matrix elements: @code Mat image(1920, 1080, CV_8UC3); typedef cv::Point3_ Pixel; // first. raw pointer access. for (int r = 0; r < image.rows; ++r) { - Pixel* ptr = image.ptr(0, r); + Pixel* ptr = image.ptr(r, 0); const Pixel* ptr_end = ptr + image.cols; for (; ptr != ptr_end; ++ptr) { ptr->x = 255; @@ -1831,18 +2068,18 @@ public: p.x = 255; }); @endcode - position parameter is index of current pixel: + Example 2. Using the pixel's position: @code - // Creating 3D matrix (255 x 255 x 255) typed uint8_t, - // and initialize all elements by the value which equals elements position. - // i.e. pixels (x,y,z) = (1,2,3) is (b,g,r) = (1,2,3). + // Creating 3D matrix (255 x 255 x 255) typed uint8_t + // and initialize all elements by the value which equals elements position. + // i.e. pixels (x,y,z) = (1,2,3) is (b,g,r) = (1,2,3). int sizes[] = { 255, 255, 255 }; typedef cv::Point3_ Pixel; Mat_ image = Mat::zeros(3, sizes, CV_8UC3); - image.forEachWithPosition([&](Pixel& pixel, const int position[]) -> void{ + image.forEach([&](Pixel& pixel, const int position[]) -> void { pixel.x = position[0]; pixel.y = position[1]; pixel.z = position[2]; @@ -1853,6 +2090,11 @@ public: /** @overload */ template void forEach(const Functor& operation) const; +#ifdef CV_CXX_MOVE_SEMANTICS + Mat(Mat&& m); + Mat& operator = (Mat&& m); +#endif + enum { MAGIC_VAL = 0x42FF0000, AUTO_STEP = 0, CONTINUOUS_FLAG = CV_MAT_CONT_FLAG, SUBMATRIX_FLAG = CV_SUBMAT_FLAG }; enum { MAGIC_MASK = 0xFFFF0000, TYPE_MASK = 0x00000FFF, DEPTH_MASK = 7 }; @@ -1879,6 +2121,11 @@ public: MatAllocator* allocator; //! and the standard allocator static MatAllocator* getStdAllocator(); + static MatAllocator* getDefaultAllocator(); + static void setDefaultAllocator(MatAllocator* allocator); + + //! internal use method: updates the continuity flag + void updateContinuityFlag(); //! interaction with UMat UMatData* u; @@ -1895,7 +2142,7 @@ protected: /** @brief Template matrix class derived from Mat -@code +@code{.cpp} template class Mat_ : public Mat { public: @@ -1907,7 +2154,7 @@ protected: The class `Mat_<_Tp>` is a *thin* template wrapper on top of the Mat class. It does not have any extra data fields. Nor this class nor Mat has any virtual methods. Thus, references or pointers to these two classes can be freely but carefully converted one to another. For example: -@code +@code{.cpp} // create a 100x100 8-bit matrix Mat M(100,100,CV_8U); // this will be compiled fine. no any data conversion will be done. @@ -1919,7 +2166,7 @@ While Mat is sufficient in most cases, Mat_ can be more convenient if you use a access operations and if you know matrix type at the compilation time. Note that `Mat::at(int y,int x)` and `Mat_::operator()(int y,int x)` do absolutely the same and run at the same speed, but the latter is certainly shorter: -@code +@code{.cpp} Mat_ M(20,20); for(int i = 0; i < M.rows; i++) for(int j = 0; j < M.cols; j++) @@ -1929,7 +2176,7 @@ and run at the same speed, but the latter is certainly shorter: cout << E.at(0,0)/E.at(M.rows-1,0); @endcode To use Mat_ for multi-channel images/matrices, pass Vec as a Mat_ parameter: -@code +@code{.cpp} // allocate a 320x240 color image and fill it with green (in RGB space) Mat_ img(240, 320, Vec3b(0,255,0)); // now draw a diagonal white line @@ -1939,6 +2186,17 @@ To use Mat_ for multi-channel images/matrices, pass Vec as a Mat_ parameter: for(int i = 0; i < img.rows; i++) for(int j = 0; j < img.cols; j++) img(i,j)[2] ^= (uchar)(i ^ j); +@endcode +Mat_ is fully compatible with C++11 range-based for loop. For example such loop +can be used to safely apply look-up table: +@code{.cpp} +void applyTable(Mat_& I, const uchar* const table) +{ + for(auto& pixel : I) + { + pixel = table[pixel]; + } +} @endcode */ template class Mat_ : public Mat @@ -1963,7 +2221,7 @@ public: Mat_(int _ndims, const int* _sizes); //! n-dim array constructor that sets each matrix element to specified value Mat_(int _ndims, const int* _sizes, const _Tp& value); - //! copy/conversion contructor. If m is of different type, it's converted + //! copy/conversion constructor. If m is of different type, it's converted Mat_(const Mat& m); //! copy constructor Mat_(const Mat_& m); @@ -1977,6 +2235,8 @@ public: Mat_(const Mat_& m, const Rect& roi); //! selects a submatrix, n-dim version Mat_(const Mat_& m, const Range* ranges); + //! selects a submatrix, n-dim version + Mat_(const Mat_& m, const std::vector& ranges); //! from a matrix expression explicit Mat_(const MatExpr& e); //! makes a matrix out of Vec, std::vector, Point_ or Point3_. The matrix will have a single column @@ -1987,6 +2247,15 @@ public: explicit Mat_(const Point3_::channel_type>& pt, bool copyData=true); explicit Mat_(const MatCommaInitializer_<_Tp>& commaInitializer); +#ifdef CV_CXX11 + Mat_(std::initializer_list<_Tp> values); + explicit Mat_(const std::initializer_list sizes, const std::initializer_list<_Tp> values); +#endif + +#ifdef CV_CXX_STD_ARRAY + template explicit Mat_(const std::array<_Tp, _Nm>& arr, bool copyData=false); +#endif + Mat_& operator = (const Mat& m); Mat_& operator = (const Mat_& m); //! set all the elements to s. @@ -2011,6 +2280,8 @@ public: void create(Size _size); //! equivalent to Mat::create(_ndims, _sizes, DatType<_Tp>::type) void create(int _ndims, const int* _sizes); + //! equivalent to Mat::release() + void release(); //! cross-product Mat_ cross(const Mat_& m) const; //! data type conversion @@ -2019,7 +2290,7 @@ public: Mat_ row(int y) const; Mat_ col(int x) const; Mat_ diag(int d=0) const; - Mat_ clone() const; + Mat_ clone() const CV_NODISCARD; //! overridden forms of Mat::elemSize() etc. size_t elemSize() const; @@ -2041,11 +2312,12 @@ public: static MatExpr eye(int rows, int cols); static MatExpr eye(Size size); - //! some more overriden methods + //! some more overridden methods Mat_& adjustROI( int dtop, int dbottom, int dleft, int dright ); Mat_ operator()( const Range& rowRange, const Range& colRange ) const; Mat_ operator()( const Rect& roi ) const; Mat_ operator()( const Range* ranges ) const; + Mat_ operator()(const std::vector& ranges) const; //! more convenient forms of row and element access operators _Tp* operator [](int y); @@ -2066,9 +2338,9 @@ public: //! returns read-only reference to the specified element (1D case) const _Tp& operator ()(int idx0) const; //! returns reference to the specified element (2D case) - _Tp& operator ()(int idx0, int idx1); + _Tp& operator ()(int row, int col); //! returns read-only reference to the specified element (2D case) - const _Tp& operator ()(int idx0, int idx1) const; + const _Tp& operator ()(int row, int col) const; //! returns reference to the specified element (3D case) _Tp& operator ()(int idx0, int idx1, int idx2); //! returns read-only reference to the specified element (3D case) @@ -2079,10 +2351,26 @@ public: //! conversion to vector. operator std::vector<_Tp>() const; + +#ifdef CV_CXX_STD_ARRAY + //! conversion to array. + template operator std::array<_Tp, _Nm>() const; +#endif + //! conversion to Vec template operator Vec::channel_type, n>() const; //! conversion to Matx template operator Matx::channel_type, m, n>() const; + +#ifdef CV_CXX_MOVE_SEMANTICS + Mat_(Mat_&& m); + Mat_& operator = (Mat_&& m); + + Mat_(Mat&& m); + Mat_& operator = (Mat&& m); + + Mat_(MatExpr&& e); +#endif }; typedef Mat_ Mat1b; @@ -2140,8 +2428,10 @@ public: UMat(const UMat& m, const Range& rowRange, const Range& colRange=Range::all()); UMat(const UMat& m, const Rect& roi); UMat(const UMat& m, const Range* ranges); + UMat(const UMat& m, const std::vector& ranges); //! builds matrix from std::vector with or without copying the data template explicit UMat(const std::vector<_Tp>& vec, bool copyData=false); + //! builds matrix from cv::Vec; the data is copied by default template explicit UMat(const Vec<_Tp, n>& vec, bool copyData=true); //! builds matrix from cv::Matx; the data is copied by default @@ -2171,21 +2461,21 @@ public: UMat colRange(int startcol, int endcol) const; UMat colRange(const Range& r) const; //! ... for the specified diagonal - // (d=0 - the main diagonal, - // >0 - a diagonal from the lower half, - // <0 - a diagonal from the upper half) + //! (d=0 - the main diagonal, + //! >0 - a diagonal from the upper half, + //! <0 - a diagonal from the lower half) UMat diag(int d=0) const; //! constructs a square diagonal matrix which main diagonal is vector "d" static UMat diag(const UMat& d); //! returns deep copy of the matrix, i.e. the data is copied - UMat clone() const; + UMat clone() const CV_NODISCARD; //! copies the matrix content to "m". // It calls m.create(this->size(), this->type()). void copyTo( OutputArray m ) const; //! copies those matrix elements to "m" that are marked with non-zero mask elements. void copyTo( OutputArray m, InputArray mask ) const; - //! converts matrix to another datatype with optional scalng. See cvConvertScale. + //! converts matrix to another datatype with optional scaling. See cvConvertScale. void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const; void assignTo( UMat& m, int type=-1 ) const; @@ -2224,6 +2514,7 @@ public: void create(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); void create(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); void create(int ndims, const int* sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + void create(const std::vector& sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); //! increases the reference counter; use with care to avoid memleaks void addref(); @@ -2245,6 +2536,7 @@ public: UMat operator()( Range rowRange, Range colRange ) const; UMat operator()( const Rect& roi ) const; UMat operator()( const Range* ranges ) const; + UMat operator()(const std::vector& ranges) const; //! returns true iff the matrix data is continuous // (i.e. when there are no gaps between successive rows). @@ -2275,6 +2567,15 @@ public: //! returns N if the matrix is 1-channel (N x ptdim) or ptdim-channel (1 x N) or (N x 1); negative number otherwise int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const; +#ifdef CV_CXX_MOVE_SEMANTICS + UMat(UMat&& m); + UMat& operator = (UMat&& m); +#endif + + /*! Returns the OpenCL buffer handle on which UMat operates on. + The UMat instance should be kept alive during the use of the handle to prevent the buffer to be + returned to the OpenCV buffer pool. + */ void* handle(int accessFlags) const; void ndoffset(size_t* ofs) const; @@ -2299,6 +2600,9 @@ public: //! and the standard allocator static MatAllocator* getStdAllocator(); + //! internal use method: updates the continuity flag + void updateContinuityFlag(); + // black-box container of UMat data UMatData* u; @@ -2326,15 +2630,16 @@ Elements can be accessed using the following methods: SparseMat::find), for example: @code const int dims = 5; - int size[] = {10, 10, 10, 10, 10}; + int size[5] = {10, 10, 10, 10, 10}; SparseMat sparse_mat(dims, size, CV_32F); for(int i = 0; i < 1000; i++) { int idx[dims]; for(int k = 0; k < dims; k++) - idx[k] = rand() + idx[k] = rand() % size[k]; sparse_mat.ref(idx) += 1.f; } + cout << "nnz = " << sparse_mat.nzcount() << endl; @endcode - Sparse matrix iterators. They are similar to MatIterator but different from NAryMatIterator. That is, the iteration loop is familiar to STL users: @@ -2459,7 +2764,7 @@ public: SparseMat& operator = (const Mat& m); //! creates full copy of the matrix - SparseMat clone() const; + SparseMat clone() const CV_NODISCARD; //! copies all the data to the destination matrix. All the previous content of m is erased void copyTo( SparseMat& m ) const; @@ -2471,11 +2776,11 @@ public: /*! @param [out] m - output matrix; if it does not have a proper size or type before the operation, it is reallocated - @param [in] rtype – desired output matrix type or, rather, the depth since the number of channels + @param [in] rtype - desired output matrix type or, rather, the depth since the number of channels are the same as the input has; if rtype is negative, the output matrix will have the same type as the input. - @param [in] alpha – optional scale factor - @param [in] beta – optional delta added to the scaled values + @param [in] alpha - optional scale factor + @param [in] beta - optional delta added to the scaled values */ void convertTo( Mat& m, int rtype, double alpha=1, double beta=0 ) const; @@ -2678,7 +2983,7 @@ public: //! the default constructor SparseMat_(); - //! the full constructor equivelent to SparseMat(dims, _sizes, DataType<_Tp>::type) + //! the full constructor equivalent to SparseMat(dims, _sizes, DataType<_Tp>::type) SparseMat_(int dims, const int* _sizes); //! the copy constructor. If DataType<_Tp>.type != m.type(), the m elements are converted SparseMat_(const SparseMat& m); @@ -2696,7 +3001,7 @@ public: SparseMat_& operator = (const Mat& m); //! makes full copy of the matrix. All the elements are duplicated - SparseMat_ clone() const; + SparseMat_ clone() const CV_NODISCARD; //! equivalent to cv::SparseMat::create(dims, _sizes, DataType<_Tp>::type) void create(int dims, const int* _sizes); //! converts sparse matrix to the old-style CvSparseMat. All the elements are copied @@ -2749,9 +3054,7 @@ public: typedef const uchar** pointer; typedef uchar* reference; -#ifndef OPENCV_NOSTL typedef std::random_access_iterator_tag iterator_category; -#endif //! default constructor MatConstIterator(); @@ -2816,9 +3119,7 @@ public: typedef const _Tp* pointer; typedef const _Tp& reference; -#ifndef OPENCV_NOSTL typedef std::random_access_iterator_tag iterator_category; -#endif //! default constructor MatConstIterator_(); @@ -2836,9 +3137,9 @@ public: //! copy operator MatConstIterator_& operator = (const MatConstIterator_& it); //! returns the current matrix element - _Tp operator *() const; + const _Tp& operator *() const; //! returns the i-th matrix element, relative to the current - _Tp operator [](ptrdiff_t i) const; + const _Tp& operator [](ptrdiff_t i) const; //! shifts the iterator forward by the specified number of elements MatConstIterator_& operator += (ptrdiff_t ofs); @@ -2869,9 +3170,7 @@ public: typedef _Tp* pointer; typedef _Tp& reference; -#ifndef OPENCV_NOSTL typedef std::random_access_iterator_tag iterator_category; -#endif //! the default constructor MatIterator_(); @@ -3005,9 +3304,7 @@ template class SparseMatConstIterator_ : public SparseMatConstIter { public: -#ifndef OPENCV_NOSTL typedef std::forward_iterator_tag iterator_category; -#endif //! the default constructor SparseMatConstIterator_(); @@ -3041,9 +3338,7 @@ template class SparseMatIterator_ : public SparseMatConstIterator_ { public: -#ifndef OPENCV_NOSTL typedef std::forward_iterator_tag iterator_category; -#endif //! the default constructor SparseMatIterator_(); @@ -3102,21 +3397,29 @@ The example below illustrates how you can compute a normalized and threshold 3D } minProb *= image.rows*image.cols; - Mat plane; - NAryMatIterator it(&hist, &plane, 1); + + // initialize iterator (the style is different from STL). + // after initialization the iterator will contain + // the number of slices or planes the iterator will go through. + // it simultaneously increments iterators for several matrices + // supplied as a null terminated list of pointers + const Mat* arrays[] = {&hist, 0}; + Mat planes[1]; + NAryMatIterator itNAry(arrays, planes, 1); double s = 0; // iterate through the matrix. on each iteration - // it.planes[*] (of type Mat) will be set to the current plane. - for(int p = 0; p < it.nplanes; p++, ++it) + // itNAry.planes[i] (of type Mat) will be set to the current plane + // of the i-th n-dim matrix passed to the iterator constructor. + for(int p = 0; p < itNAry.nplanes; p++, ++itNAry) { - threshold(it.planes[0], it.planes[0], minProb, 0, THRESH_TOZERO); - s += sum(it.planes[0])[0]; + threshold(itNAry.planes[0], itNAry.planes[0], minProb, 0, THRESH_TOZERO); + s += sum(itNAry.planes[0])[0]; } s = 1./s; - it = NAryMatIterator(&hist, &plane, 1); - for(int p = 0; p < it.nplanes; p++, ++it) - it.planes[0] *= s; + itNAry = NAryMatIterator(arrays, planes, 1); + for(int p = 0; p < itNAry.nplanes; p++, ++itNAry) + itNAry.planes[0] *= s; } @endcode */ @@ -3240,7 +3543,7 @@ Here are examples of matrix expressions: // sharpen image using "unsharp mask" algorithm Mat blurred; double sigma = 1, threshold = 5, amount = 1; GaussianBlur(img, blurred, Size(), sigma, sigma); - Mat lowConstrastMask = abs(img - blurred) < threshold; + Mat lowContrastMask = abs(img - blurred) < threshold; Mat sharpened = img*(1+amount) + blurred*(-amount); img.copyTo(sharpened, lowContrastMask); @endcode @@ -3395,4 +3698,4 @@ CV_EXPORTS MatExpr abs(const MatExpr& e); #include "opencv2/core/mat.inl.hpp" -#endif // __OPENCV_CORE_MAT_HPP__ +#endif // OPENCV_CORE_MAT_HPP diff --git a/include/opencv2/core/mat.inl.hpp b/include/opencv2/core/mat.inl.hpp index 3779b83..a2e7923 100644 --- a/include/opencv2/core/mat.inl.hpp +++ b/include/opencv2/core/mat.inl.hpp @@ -42,18 +42,35 @@ // //M*/ -#ifndef __OPENCV_CORE_MATRIX_OPERATIONS_HPP__ -#define __OPENCV_CORE_MATRIX_OPERATIONS_HPP__ +#ifndef OPENCV_CORE_MATRIX_OPERATIONS_HPP +#define OPENCV_CORE_MATRIX_OPERATIONS_HPP #ifndef __cplusplus # error mat.inl.hpp header must be compiled as C++ #endif +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable: 4127 ) +#endif + namespace cv { +CV__DEBUG_NS_BEGIN + //! @cond IGNORED +////////////////////////// Custom (raw) type wrapper ////////////////////////// + +template static inline +int rawType() +{ + CV_StaticAssert(sizeof(_Tp) <= CV_CN_MAX, "sizeof(_Tp) is too large"); + const int elemSize = sizeof(_Tp); + return (int)CV_MAKETYPE(CV_8U, elemSize); +} + //////////////////////// Input/Output Arrays //////////////////////// inline void _InputArray::init(int _flags, const void* _obj) @@ -75,31 +92,45 @@ inline _InputArray::_InputArray(const std::vector& vec) { init(STD_VECTOR_ template inline _InputArray::_InputArray(const std::vector<_Tp>& vec) -{ init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); } +{ init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_READ, &vec); } + +#ifdef CV_CXX_STD_ARRAY +template inline +_InputArray::_InputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_READ, arr.data(), Size(1, _Nm)); } + +template inline +_InputArray::_InputArray(const std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_READ, arr.data(), Size(1, _Nm)); } +#endif inline _InputArray::_InputArray(const std::vector& vec) -{ init(FIXED_TYPE + STD_BOOL_VECTOR + DataType::type + ACCESS_READ, &vec); } +{ init(FIXED_TYPE + STD_BOOL_VECTOR + traits::Type::value + ACCESS_READ, &vec); } template inline _InputArray::_InputArray(const std::vector >& vec) -{ init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); } +{ init(FIXED_TYPE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_READ, &vec); } + +inline +_InputArray::_InputArray(const std::vector >&) +{ CV_Error(Error::StsUnsupportedFormat, "std::vector > is not supported!\n"); } template inline _InputArray::_InputArray(const std::vector >& vec) -{ init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_READ, &vec); } +{ init(FIXED_TYPE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_READ, &vec); } template inline _InputArray::_InputArray(const Matx<_Tp, m, n>& mtx) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_READ, &mtx, Size(n, m)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ, &mtx, Size(n, m)); } template inline _InputArray::_InputArray(const _Tp* vec, int n) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_READ, vec, Size(n, 1)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ, vec, Size(n, 1)); } template inline _InputArray::_InputArray(const Mat_<_Tp>& m) -{ init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_READ, &m); } +{ init(FIXED_TYPE + MAT + traits::Type<_Tp>::value + ACCESS_READ, &m); } inline _InputArray::_InputArray(const double& val) { init(FIXED_TYPE + FIXED_SIZE + MATX + CV_64F + ACCESS_READ, &val, Size(1,1)); } @@ -110,12 +141,36 @@ inline _InputArray::_InputArray(const MatExpr& expr) inline _InputArray::_InputArray(const cuda::GpuMat& d_mat) { init(CUDA_GPU_MAT + ACCESS_READ, &d_mat); } +inline _InputArray::_InputArray(const std::vector& d_mat) +{ init(STD_VECTOR_CUDA_GPU_MAT + ACCESS_READ, &d_mat);} + inline _InputArray::_InputArray(const ogl::Buffer& buf) { init(OPENGL_BUFFER + ACCESS_READ, &buf); } inline _InputArray::_InputArray(const cuda::HostMem& cuda_mem) { init(CUDA_HOST_MEM + ACCESS_READ, &cuda_mem); } +template inline +_InputArray _InputArray::rawIn(const std::vector<_Tp>& vec) +{ + _InputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_READ; + v.obj = (void*)&vec; + return v; +} + +#ifdef CV_CXX_STD_ARRAY +template inline +_InputArray _InputArray::rawIn(const std::array<_Tp, _Nm>& arr) +{ + _InputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_READ; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} +#endif + inline _InputArray::~_InputArray() {} inline Mat _InputArray::getMat(int i) const @@ -130,6 +185,11 @@ inline bool _InputArray::isUMat() const { return kind() == _InputArray::UMAT; } inline bool _InputArray::isMatVector() const { return kind() == _InputArray::STD_VECTOR_MAT; } inline bool _InputArray::isUMatVector() const { return kind() == _InputArray::STD_VECTOR_UMAT; } inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; } +inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VECTOR || + kind() == _InputArray::STD_BOOL_VECTOR || + kind() == _InputArray::STD_ARRAY; } +inline bool _InputArray::isGpuMat() const { return kind() == _InputArray::CUDA_GPU_MAT; } +inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; } //////////////////////////////////////////////////////////////////////////////////////// @@ -142,7 +202,17 @@ inline _OutputArray::_OutputArray(std::vector& vec) { init(STD_VECTOR_UMAT template inline _OutputArray::_OutputArray(std::vector<_Tp>& vec) -{ init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +{ init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +#ifdef CV_CXX_STD_ARRAY +template inline +_OutputArray::_OutputArray(std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } + +template inline +_OutputArray::_OutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } +#endif inline _OutputArray::_OutputArray(std::vector&) @@ -150,51 +220,68 @@ _OutputArray::_OutputArray(std::vector&) template inline _OutputArray::_OutputArray(std::vector >& vec) -{ init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +{ init(FIXED_TYPE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +inline +_OutputArray::_OutputArray(std::vector >&) +{ CV_Error(Error::StsUnsupportedFormat, "std::vector > cannot be an output array\n"); } template inline _OutputArray::_OutputArray(std::vector >& vec) -{ init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +{ init(FIXED_TYPE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } template inline _OutputArray::_OutputArray(Mat_<_Tp>& m) -{ init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_WRITE, &m); } +{ init(FIXED_TYPE + MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &m); } template inline _OutputArray::_OutputArray(Matx<_Tp, m, n>& mtx) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, &mtx, Size(n, m)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, &mtx, Size(n, m)); } template inline _OutputArray::_OutputArray(_Tp* vec, int n) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, vec, Size(n, 1)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, vec, Size(n, 1)); } template inline _OutputArray::_OutputArray(const std::vector<_Tp>& vec) -{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +#ifdef CV_CXX_STD_ARRAY +template inline +_OutputArray::_OutputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } + +template inline +_OutputArray::_OutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } +#endif template inline _OutputArray::_OutputArray(const std::vector >& vec) -{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } template inline _OutputArray::_OutputArray(const std::vector >& vec) -{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } template inline _OutputArray::_OutputArray(const Mat_<_Tp>& m) -{ init(FIXED_TYPE + FIXED_SIZE + MAT + DataType<_Tp>::type + ACCESS_WRITE, &m); } +{ init(FIXED_TYPE + FIXED_SIZE + MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &m); } template inline _OutputArray::_OutputArray(const Matx<_Tp, m, n>& mtx) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, &mtx, Size(n, m)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, &mtx, Size(n, m)); } template inline _OutputArray::_OutputArray(const _Tp* vec, int n) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, vec, Size(n, 1)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, vec, Size(n, 1)); } inline _OutputArray::_OutputArray(cuda::GpuMat& d_mat) { init(CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); } +inline _OutputArray::_OutputArray(std::vector& d_mat) +{ init(STD_VECTOR_CUDA_GPU_MAT + ACCESS_WRITE, &d_mat);} + inline _OutputArray::_OutputArray(ogl::Buffer& buf) { init(OPENGL_BUFFER + ACCESS_WRITE, &buf); } @@ -216,12 +303,34 @@ inline _OutputArray::_OutputArray(const std::vector& vec) inline _OutputArray::_OutputArray(const cuda::GpuMat& d_mat) { init(FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); } + inline _OutputArray::_OutputArray(const ogl::Buffer& buf) { init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_WRITE, &buf); } inline _OutputArray::_OutputArray(const cuda::HostMem& cuda_mem) { init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_WRITE, &cuda_mem); } +template inline +_OutputArray _OutputArray::rawOut(std::vector<_Tp>& vec) +{ + _OutputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_WRITE; + v.obj = (void*)&vec; + return v; +} + +#ifdef CV_CXX_STD_ARRAY +template inline +_OutputArray _OutputArray::rawOut(std::array<_Tp, _Nm>& arr) +{ + _OutputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} +#endif + /////////////////////////////////////////////////////////////////////////////////////////// inline _InputOutputArray::_InputOutputArray() { init(ACCESS_RW, 0); } @@ -233,54 +342,74 @@ inline _InputOutputArray::_InputOutputArray(std::vector& vec) { init(STD_V template inline _InputOutputArray::_InputOutputArray(std::vector<_Tp>& vec) -{ init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } +{ init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +#ifdef CV_CXX_STD_ARRAY +template inline +_InputOutputArray::_InputOutputArray(std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); } + +template inline +_InputOutputArray::_InputOutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _Nm)); } +#endif inline _InputOutputArray::_InputOutputArray(std::vector&) { CV_Error(Error::StsUnsupportedFormat, "std::vector cannot be an input/output array\n"); } template inline _InputOutputArray::_InputOutputArray(std::vector >& vec) -{ init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } +{ init(FIXED_TYPE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } template inline _InputOutputArray::_InputOutputArray(std::vector >& vec) -{ init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_RW, &vec); } +{ init(FIXED_TYPE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_RW, &vec); } template inline _InputOutputArray::_InputOutputArray(Mat_<_Tp>& m) -{ init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_RW, &m); } +{ init(FIXED_TYPE + MAT + traits::Type<_Tp>::value + ACCESS_RW, &m); } template inline _InputOutputArray::_InputOutputArray(Matx<_Tp, m, n>& mtx) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, &mtx, Size(n, m)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, &mtx, Size(n, m)); } template inline _InputOutputArray::_InputOutputArray(_Tp* vec, int n) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, vec, Size(n, 1)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, vec, Size(n, 1)); } template inline _InputOutputArray::_InputOutputArray(const std::vector<_Tp>& vec) -{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +#ifdef CV_CXX_STD_ARRAY +template inline +_InputOutputArray::_InputOutputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); } + +template inline +_InputOutputArray::_InputOutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _Nm)); } +#endif template inline _InputOutputArray::_InputOutputArray(const std::vector >& vec) -{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } template inline _InputOutputArray::_InputOutputArray(const std::vector >& vec) -{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_RW, &vec); } +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_RW, &vec); } template inline _InputOutputArray::_InputOutputArray(const Mat_<_Tp>& m) -{ init(FIXED_TYPE + FIXED_SIZE + MAT + DataType<_Tp>::type + ACCESS_RW, &m); } +{ init(FIXED_TYPE + FIXED_SIZE + MAT + traits::Type<_Tp>::value + ACCESS_RW, &m); } template inline _InputOutputArray::_InputOutputArray(const Matx<_Tp, m, n>& mtx) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, &mtx, Size(n, m)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, &mtx, Size(n, m)); } template inline _InputOutputArray::_InputOutputArray(const _Tp* vec, int n) -{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, vec, Size(n, 1)); } +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, vec, Size(n, 1)); } inline _InputOutputArray::_InputOutputArray(cuda::GpuMat& d_mat) { init(CUDA_GPU_MAT + ACCESS_RW, &d_mat); } @@ -306,24 +435,58 @@ inline _InputOutputArray::_InputOutputArray(const std::vector& vec) inline _InputOutputArray::_InputOutputArray(const cuda::GpuMat& d_mat) { init(FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MAT + ACCESS_RW, &d_mat); } +inline _InputOutputArray::_InputOutputArray(const std::vector& d_mat) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);} + +template<> inline _InputOutputArray::_InputOutputArray(std::vector& d_mat) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);} + inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf) { init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_RW, &buf); } inline _InputOutputArray::_InputOutputArray(const cuda::HostMem& cuda_mem) { init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_RW, &cuda_mem); } +template inline +_InputOutputArray _InputOutputArray::rawInOut(std::vector<_Tp>& vec) +{ + _InputOutputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_RW; + v.obj = (void*)&vec; + return v; +} + +#ifdef CV_CXX_STD_ARRAY +template inline +_InputOutputArray _InputOutputArray::rawInOut(std::array<_Tp, _Nm>& arr) +{ + _InputOutputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} +#endif + + +template static inline _InputArray rawIn(_Tp& v) { return _InputArray::rawIn(v); } +template static inline _OutputArray rawOut(_Tp& v) { return _OutputArray::rawOut(v); } +template static inline _InputOutputArray rawInOut(_Tp& v) { return _InputOutputArray::rawInOut(v); } + +CV__DEBUG_NS_END + //////////////////////////////////////////// Mat ////////////////////////////////////////// inline Mat::Mat() : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), - datalimit(0), allocator(0), u(0), size(&rows) + datalimit(0), allocator(0), u(0), size(&rows), step(0) {} inline Mat::Mat(int _rows, int _cols, int _type) : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), - datalimit(0), allocator(0), u(0), size(&rows) + datalimit(0), allocator(0), u(0), size(&rows), step(0) { create(_rows, _cols, _type); } @@ -331,7 +494,7 @@ Mat::Mat(int _rows, int _cols, int _type) inline Mat::Mat(int _rows, int _cols, int _type, const Scalar& _s) : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), - datalimit(0), allocator(0), u(0), size(&rows) + datalimit(0), allocator(0), u(0), size(&rows), step(0) { create(_rows, _cols, _type); *this = _s; @@ -340,7 +503,7 @@ Mat::Mat(int _rows, int _cols, int _type, const Scalar& _s) inline Mat::Mat(Size _sz, int _type) : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), - datalimit(0), allocator(0), u(0), size(&rows) + datalimit(0), allocator(0), u(0), size(&rows), step(0) { create( _sz.height, _sz.width, _type ); } @@ -348,7 +511,7 @@ Mat::Mat(Size _sz, int _type) inline Mat::Mat(Size _sz, int _type, const Scalar& _s) : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), - datalimit(0), allocator(0), u(0), size(&rows) + datalimit(0), allocator(0), u(0), size(&rows), step(0) { create(_sz.height, _sz.width, _type); *this = _s; @@ -357,7 +520,7 @@ Mat::Mat(Size _sz, int _type, const Scalar& _s) inline Mat::Mat(int _dims, const int* _sz, int _type) : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), - datalimit(0), allocator(0), u(0), size(&rows) + datalimit(0), allocator(0), u(0), size(&rows), step(0) { create(_dims, _sz, _type); } @@ -365,17 +528,34 @@ Mat::Mat(int _dims, const int* _sz, int _type) inline Mat::Mat(int _dims, const int* _sz, int _type, const Scalar& _s) : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), - datalimit(0), allocator(0), u(0), size(&rows) + datalimit(0), allocator(0), u(0), size(&rows), step(0) { create(_dims, _sz, _type); *this = _s; } +inline +Mat::Mat(const std::vector& _sz, int _type) + : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), + datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + create(_sz, _type); +} + +inline +Mat::Mat(const std::vector& _sz, int _type, const Scalar& _s) + : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), + datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + create(_sz, _type); + *this = _s; +} + inline Mat::Mat(const Mat& m) : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data), datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator), - u(m.u), size(&rows) + u(m.u), size(&rows), step(0) { if( u ) CV_XADD(&u->refcount, 1); @@ -396,29 +576,27 @@ Mat::Mat(int _rows, int _cols, int _type, void* _data, size_t _step) data((uchar*)_data), datastart((uchar*)_data), dataend(0), datalimit(0), allocator(0), u(0), size(&rows) { + CV_Assert(total() == 0 || data != NULL); + size_t esz = CV_ELEM_SIZE(_type), esz1 = CV_ELEM_SIZE1(_type); size_t minstep = cols * esz; if( _step == AUTO_STEP ) { _step = minstep; - flags |= CONTINUOUS_FLAG; } else { - if( rows == 1 ) _step = minstep; CV_DbgAssert( _step >= minstep ); - if (_step % esz1 != 0) { CV_Error(Error::BadStep, "Step must be a multiple of esz1"); } - - flags |= _step == minstep ? CONTINUOUS_FLAG : 0; } step[0] = _step; step[1] = esz; datalimit = datastart + _step * rows; dataend = datalimit - _step + minstep; + updateContinuityFlag(); } inline @@ -427,35 +605,34 @@ Mat::Mat(Size _sz, int _type, void* _data, size_t _step) data((uchar*)_data), datastart((uchar*)_data), dataend(0), datalimit(0), allocator(0), u(0), size(&rows) { + CV_Assert(total() == 0 || data != NULL); + size_t esz = CV_ELEM_SIZE(_type), esz1 = CV_ELEM_SIZE1(_type); size_t minstep = cols*esz; if( _step == AUTO_STEP ) { _step = minstep; - flags |= CONTINUOUS_FLAG; } else { - if( rows == 1 ) _step = minstep; CV_DbgAssert( _step >= minstep ); if (_step % esz1 != 0) { CV_Error(Error::BadStep, "Step must be a multiple of esz1"); } - - flags |= _step == minstep ? CONTINUOUS_FLAG : 0; } step[0] = _step; step[1] = esz; datalimit = datastart + _step*rows; dataend = datalimit - _step + minstep; + updateContinuityFlag(); } template inline Mat::Mat(const std::vector<_Tp>& vec, bool copyData) - : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()), - cols(1), data(0), datastart(0), dataend(0), allocator(0), u(0), size(&rows) + : flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()), + cols(1), data(0), datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) { if(vec.empty()) return; @@ -466,13 +643,54 @@ Mat::Mat(const std::vector<_Tp>& vec, bool copyData) datalimit = dataend = datastart + rows * step[0]; } else - Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this); + Mat((int)vec.size(), 1, traits::Type<_Tp>::value, (uchar*)&vec[0]).copyTo(*this); } +#ifdef CV_CXX11 +template inline +Mat::Mat(const std::initializer_list<_Tp> list) + : Mat() +{ + CV_Assert(list.size() != 0); + Mat((int)list.size(), 1, traits::Type<_Tp>::value, (uchar*)list.begin()).copyTo(*this); +} + +template inline +Mat::Mat(const std::initializer_list sizes, const std::initializer_list<_Tp> list) + : Mat() +{ + size_t size_total = 1; + for(auto s : sizes) + size_total *= s; + CV_Assert(list.size() != 0); + CV_Assert(size_total == list.size()); + Mat((int)sizes.size(), (int*)sizes.begin(), traits::Type<_Tp>::value, (uchar*)list.begin()).copyTo(*this); +} +#endif + +#ifdef CV_CXX_STD_ARRAY +template inline +Mat::Mat(const std::array<_Tp, _Nm>& arr, bool copyData) + : flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows((int)arr.size()), + cols(1), data(0), datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if(arr.empty()) + return; + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + datastart = data = (uchar*)arr.data(); + datalimit = dataend = datastart + rows * step[0]; + } + else + Mat((int)arr.size(), 1, traits::Type<_Tp>::value, (uchar*)arr.data()).copyTo(*this); +} +#endif + template inline Mat::Mat(const Vec<_Tp, n>& vec, bool copyData) - : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(n), cols(1), data(0), - datastart(0), dataend(0), allocator(0), u(0), size(&rows) + : flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows(n), cols(1), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) { if( !copyData ) { @@ -481,14 +699,14 @@ Mat::Mat(const Vec<_Tp, n>& vec, bool copyData) datalimit = dataend = datastart + rows * step[0]; } else - Mat(n, 1, DataType<_Tp>::type, (void*)vec.val).copyTo(*this); + Mat(n, 1, traits::Type<_Tp>::value, (void*)vec.val).copyTo(*this); } template inline Mat::Mat(const Matx<_Tp,m,n>& M, bool copyData) - : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(m), cols(n), data(0), - datastart(0), dataend(0), allocator(0), u(0), size(&rows) + : flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows(m), cols(n), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) { if( !copyData ) { @@ -498,13 +716,13 @@ Mat::Mat(const Matx<_Tp,m,n>& M, bool copyData) datalimit = dataend = datastart + rows * step[0]; } else - Mat(m, n, DataType<_Tp>::type, (uchar*)M.val).copyTo(*this); + Mat(m, n, traits::Type<_Tp>::value, (uchar*)M.val).copyTo(*this); } template inline Mat::Mat(const Point_<_Tp>& pt, bool copyData) - : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(2), cols(1), data(0), - datastart(0), dataend(0), allocator(0), u(0), size(&rows) + : flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows(2), cols(1), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) { if( !copyData ) { @@ -514,7 +732,7 @@ Mat::Mat(const Point_<_Tp>& pt, bool copyData) } else { - create(2, 1, DataType<_Tp>::type); + create(2, 1, traits::Type<_Tp>::value); ((_Tp*)data)[0] = pt.x; ((_Tp*)data)[1] = pt.y; } @@ -522,8 +740,8 @@ Mat::Mat(const Point_<_Tp>& pt, bool copyData) template inline Mat::Mat(const Point3_<_Tp>& pt, bool copyData) - : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(3), cols(1), data(0), - datastart(0), dataend(0), allocator(0), u(0), size(&rows) + : flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows(3), cols(1), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) { if( !copyData ) { @@ -533,7 +751,7 @@ Mat::Mat(const Point3_<_Tp>& pt, bool copyData) } else { - create(3, 1, DataType<_Tp>::type); + create(3, 1, traits::Type<_Tp>::value); ((_Tp*)data)[0] = pt.x; ((_Tp*)data)[1] = pt.y; ((_Tp*)data)[2] = pt.z; @@ -542,7 +760,7 @@ Mat::Mat(const Point3_<_Tp>& pt, bool copyData) template inline Mat::Mat(const MatCommaInitializer_<_Tp>& commaInitializer) - : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(0), rows(0), cols(0), data(0), + : flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), allocator(0), u(0), size(&rows) { *this = commaInitializer.operator Mat_<_Tp>(); @@ -661,7 +879,8 @@ void Mat::addref() CV_XADD(&u->refcount, 1); } -inline void Mat::release() +inline +void Mat::release() { if( u && CV_XADD(&u->refcount, -1) == 1 ) deallocate(); @@ -669,6 +888,16 @@ inline void Mat::release() datastart = dataend = datalimit = data = 0; for(int i = 0; i < dims; i++) size.p[i] = 0; +#ifdef _DEBUG + flags = MAGIC_VAL; + dims = rows = cols = 0; + if(step.p != step.buf) + { + fastFree(step.p); + step.p = step.buf; + size.p = &rows; + } +#endif } inline @@ -689,6 +918,12 @@ Mat Mat::operator()(const Range* ranges) const return Mat(*this, ranges); } +inline +Mat Mat::operator()(const std::vector& ranges) const +{ + return Mat(*this, ranges); +} + inline bool Mat::isContinuous() const { @@ -704,7 +939,9 @@ bool Mat::isSubmatrix() const inline size_t Mat::elemSize() const { - return dims > 0 ? step.p[dims - 1] : 0; + size_t res = dims > 0 ? step.p[dims - 1] : 0; + CV_DbgAssert(res != 0); + return res; } inline @@ -740,7 +977,7 @@ size_t Mat::step1(int i) const inline bool Mat::empty() const { - return data == 0 || total() == 0; + return data == 0 || total() == 0 || dims == 0; } inline @@ -754,6 +991,17 @@ size_t Mat::total() const return p; } +inline +size_t Mat::total(int startDim, int endDim) const +{ + CV_Assert( 0 <= startDim && startDim <= endDim); + size_t p = 1; + int endDim_ = endDim <= dims ? endDim : dims; + for( int i = startDim; i < endDim_; i++ ) + p *= size[i]; + return p; +} + inline uchar* Mat::ptr(int y) { @@ -778,83 +1026,91 @@ _Tp* Mat::ptr(int y) template inline const _Tp* Mat::ptr(int y) const { - CV_DbgAssert( y == 0 || (data && dims >= 1 && data && (unsigned)y < (unsigned)size.p[0]) ); + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); return (const _Tp*)(data + step.p[0] * y); } inline uchar* Mat::ptr(int i0, int i1) { - CV_DbgAssert( dims >= 2 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] ); + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); return data + i0 * step.p[0] + i1 * step.p[1]; } inline const uchar* Mat::ptr(int i0, int i1) const { - CV_DbgAssert( dims >= 2 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] ); + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); return data + i0 * step.p[0] + i1 * step.p[1]; } template inline _Tp* Mat::ptr(int i0, int i1) { - CV_DbgAssert( dims >= 2 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] ); + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); return (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1]); } template inline const _Tp* Mat::ptr(int i0, int i1) const { - CV_DbgAssert( dims >= 2 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] ); + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); return (const _Tp*)(data + i0 * step.p[0] + i1 * step.p[1]); } inline uchar* Mat::ptr(int i0, int i1, int i2) { - CV_DbgAssert( dims >= 3 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] && - (unsigned)i2 < (unsigned)size.p[2] ); + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); return data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]; } inline const uchar* Mat::ptr(int i0, int i1, int i2) const { - CV_DbgAssert( dims >= 3 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] && - (unsigned)i2 < (unsigned)size.p[2] ); + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); return data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]; } template inline _Tp* Mat::ptr(int i0, int i1, int i2) { - CV_DbgAssert( dims >= 3 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] && - (unsigned)i2 < (unsigned)size.p[2] ); + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); return (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]); } template inline const _Tp* Mat::ptr(int i0, int i1, int i2) const { - CV_DbgAssert( dims >= 3 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] && - (unsigned)i2 < (unsigned)size.p[2] ); + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); return (const _Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]); } @@ -886,48 +1142,85 @@ const uchar* Mat::ptr(const int* idx) const return p; } +template inline +_Tp* Mat::ptr(const int* idx) +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i] * step.p[i]; + } + return (_Tp*)p; +} + +template inline +const _Tp* Mat::ptr(const int* idx) const +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i] * step.p[i]; + } + return (const _Tp*)p; +} + template inline _Tp& Mat::at(int i0, int i1) { - CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) && - CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); return ((_Tp*)(data + step.p[0] * i0))[i1]; } template inline const _Tp& Mat::at(int i0, int i1) const { - CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) && - CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); return ((const _Tp*)(data + step.p[0] * i0))[i1]; } template inline _Tp& Mat::at(Point pt) { - CV_DbgAssert( dims <= 2 && data && (unsigned)pt.y < (unsigned)size.p[0] && - (unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) && - CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); return ((_Tp*)(data + step.p[0] * pt.y))[pt.x]; } template inline const _Tp& Mat::at(Point pt) const { - CV_DbgAssert( dims <= 2 && data && (unsigned)pt.y < (unsigned)size.p[0] && - (unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) && - CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); return ((const _Tp*)(data + step.p[0] * pt.y))[pt.x]; } template inline _Tp& Mat::at(int i0) { - CV_DbgAssert( dims <= 2 && data && - (unsigned)i0 < (unsigned)(size.p[0] * size.p[1]) && - elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)(size.p[0] * size.p[1])); + CV_DbgAssert(elemSize() == sizeof(_Tp)); if( isContinuous() || size.p[0] == 1 ) return ((_Tp*)data)[i0]; if( size.p[1] == 1 ) @@ -939,9 +1232,10 @@ _Tp& Mat::at(int i0) template inline const _Tp& Mat::at(int i0) const { - CV_DbgAssert( dims <= 2 && data && - (unsigned)i0 < (unsigned)(size.p[0] * size.p[1]) && - elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)(size.p[0] * size.p[1])); + CV_DbgAssert(elemSize() == sizeof(_Tp)); if( isContinuous() || size.p[0] == 1 ) return ((const _Tp*)data)[i0]; if( size.p[1] == 1 ) @@ -953,42 +1247,42 @@ const _Tp& Mat::at(int i0) const template inline _Tp& Mat::at(int i0, int i1, int i2) { - CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); return *(_Tp*)ptr(i0, i1, i2); } template inline const _Tp& Mat::at(int i0, int i1, int i2) const { - CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); return *(const _Tp*)ptr(i0, i1, i2); } template inline _Tp& Mat::at(const int* idx) { - CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); return *(_Tp*)ptr(idx); } template inline const _Tp& Mat::at(const int* idx) const { - CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); return *(const _Tp*)ptr(idx); } template inline _Tp& Mat::at(const Vec& idx) { - CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); return *(_Tp*)ptr(idx.val); } template inline const _Tp& Mat::at(const Vec& idx) const { - CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); return *(const _Tp*)ptr(idx.val); } @@ -1032,7 +1326,7 @@ void Mat::forEach(const Functor& operation) { template inline void Mat::forEach(const Functor& operation) const { // call as not const - (const_cast(this))->forEach(operation); + (const_cast(this))->forEach<_Tp>(operation); } template inline @@ -1043,16 +1337,26 @@ Mat::operator std::vector<_Tp>() const return v; } +#ifdef CV_CXX_STD_ARRAY +template inline +Mat::operator std::array<_Tp, _Nm>() const +{ + std::array<_Tp, _Nm> v; + copyTo(v); + return v; +} +#endif + template inline Mat::operator Vec<_Tp, n>() const { CV_Assert( data && dims <= 2 && (rows == 1 || cols == 1) && rows + cols - 1 == n && channels() == 1 ); - if( isContinuous() && type() == DataType<_Tp>::type ) + if( isContinuous() && type() == traits::Type<_Tp>::value ) return Vec<_Tp, n>((_Tp*)data); Vec<_Tp, n> v; - Mat tmp(rows, cols, DataType<_Tp>::type, v.val); + Mat tmp(rows, cols, traits::Type<_Tp>::value, v.val); convertTo(tmp, tmp.type()); return v; } @@ -1062,10 +1366,10 @@ Mat::operator Matx<_Tp, m, n>() const { CV_Assert( data && dims <= 2 && rows == m && cols == n && channels() == 1 ); - if( isContinuous() && type() == DataType<_Tp>::type ) + if( isContinuous() && type() == traits::Type<_Tp>::value ) return Matx<_Tp, m, n>((_Tp*)data); Matx<_Tp, m, n> mtx; - Mat tmp(rows, cols, DataType<_Tp>::type, mtx.val); + Mat tmp(rows, cols, traits::Type<_Tp>::value, mtx.val); convertTo(tmp, tmp.type()); return mtx; } @@ -1075,10 +1379,10 @@ void Mat::push_back(const _Tp& elem) { if( !data ) { - *this = Mat(1, 1, DataType<_Tp>::type, (void*)&elem).clone(); + *this = Mat(1, 1, traits::Type<_Tp>::value, (void*)&elem).clone(); return; } - CV_Assert(DataType<_Tp>::type == type() && cols == 1 + CV_Assert(traits::Type<_Tp>::value == type() && cols == 1 /* && dims == 2 (cols == 1 implies dims == 2) */); const uchar* tmp = dataend + step[0]; if( !isSubmatrix() && isContinuous() && tmp <= datalimit ) @@ -1096,28 +1400,121 @@ void Mat::push_back(const Mat_<_Tp>& m) push_back((const Mat&)m); } +template<> inline +void Mat::push_back(const MatExpr& expr) +{ + push_back(static_cast(expr)); +} + + +template inline +void Mat::push_back(const std::vector<_Tp>& v) +{ + push_back(Mat(v)); +} + +#ifdef CV_CXX_MOVE_SEMANTICS + +inline +Mat::Mat(Mat&& m) + : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data), + datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator), + u(m.u), size(&rows) +{ + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.data = NULL; m.datastart = NULL; m.dataend = NULL; m.datalimit = NULL; + m.allocator = NULL; + m.u = NULL; +} + +inline +Mat& Mat::operator = (Mat&& m) +{ + if (this == &m) + return *this; + + release(); + flags = m.flags; dims = m.dims; rows = m.rows; cols = m.cols; data = m.data; + datastart = m.datastart; dataend = m.dataend; datalimit = m.datalimit; allocator = m.allocator; + u = m.u; + if (step.p != step.buf) // release self step/size + { + fastFree(step.p); + step.p = step.buf; + size.p = &rows; + } + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.data = NULL; m.datastart = NULL; m.dataend = NULL; m.datalimit = NULL; + m.allocator = NULL; + m.u = NULL; + return *this; +} + +#endif + + ///////////////////////////// MatSize //////////////////////////// inline MatSize::MatSize(int* _p) : p(_p) {} +inline +int MatSize::dims() const +{ + return (p - 1)[0]; +} + inline Size MatSize::operator()() const { - CV_DbgAssert(p[-1] <= 2); + CV_DbgAssert(dims() <= 2); return Size(p[1], p[0]); } inline const int& MatSize::operator[](int i) const { + CV_DbgAssert(i < dims()); +#ifdef __OPENCV_BUILD + CV_DbgAssert(i >= 0); +#endif return p[i]; } inline int& MatSize::operator[](int i) { + CV_DbgAssert(i < dims()); +#ifdef __OPENCV_BUILD + CV_DbgAssert(i >= 0); +#endif return p[i]; } @@ -1130,8 +1527,8 @@ MatSize::operator const int*() const inline bool MatSize::operator == (const MatSize& sz) const { - int d = p[-1]; - int dsz = sz.p[-1]; + int d = dims(); + int dsz = sz.dims(); if( d != dsz ) return false; if( d == 2 ) @@ -1198,42 +1595,47 @@ template inline Mat_<_Tp>::Mat_() : Mat() { - flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type; + flags = (flags & ~CV_MAT_TYPE_MASK) | traits::Type<_Tp>::value; } template inline Mat_<_Tp>::Mat_(int _rows, int _cols) - : Mat(_rows, _cols, DataType<_Tp>::type) + : Mat(_rows, _cols, traits::Type<_Tp>::value) { } template inline Mat_<_Tp>::Mat_(int _rows, int _cols, const _Tp& value) - : Mat(_rows, _cols, DataType<_Tp>::type) + : Mat(_rows, _cols, traits::Type<_Tp>::value) { *this = value; } template inline Mat_<_Tp>::Mat_(Size _sz) - : Mat(_sz.height, _sz.width, DataType<_Tp>::type) + : Mat(_sz.height, _sz.width, traits::Type<_Tp>::value) {} template inline Mat_<_Tp>::Mat_(Size _sz, const _Tp& value) - : Mat(_sz.height, _sz.width, DataType<_Tp>::type) + : Mat(_sz.height, _sz.width, traits::Type<_Tp>::value) { *this = value; } template inline Mat_<_Tp>::Mat_(int _dims, const int* _sz) - : Mat(_dims, _sz, DataType<_Tp>::type) + : Mat(_dims, _sz, traits::Type<_Tp>::value) {} template inline Mat_<_Tp>::Mat_(int _dims, const int* _sz, const _Tp& _s) - : Mat(_dims, _sz, DataType<_Tp>::type, Scalar(_s)) + : Mat(_dims, _sz, traits::Type<_Tp>::value, Scalar(_s)) +{} + +template inline +Mat_<_Tp>::Mat_(int _dims, const int* _sz, _Tp* _data, const size_t* _steps) + : Mat(_dims, _sz, traits::Type<_Tp>::value, _data, _steps) {} template inline @@ -1241,11 +1643,16 @@ Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const Range* ranges) : Mat(m, ranges) {} +template inline +Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const std::vector& ranges) + : Mat(m, ranges) +{} + template inline Mat_<_Tp>::Mat_(const Mat& m) : Mat() { - flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type; + flags = (flags & ~CV_MAT_TYPE_MASK) | traits::Type<_Tp>::value; *this = m; } @@ -1256,7 +1663,7 @@ Mat_<_Tp>::Mat_(const Mat_& m) template inline Mat_<_Tp>::Mat_(int _rows, int _cols, _Tp* _data, size_t steps) - : Mat(_rows, _cols, DataType<_Tp>::type, _data, steps) + : Mat(_rows, _cols, traits::Type<_Tp>::value, _data, steps) {} template inline @@ -1271,7 +1678,7 @@ Mat_<_Tp>::Mat_(const Mat_& m, const Rect& roi) template template inline Mat_<_Tp>::Mat_(const Vec::channel_type, n>& vec, bool copyData) - : Mat(n / DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&vec) + : Mat(n / DataType<_Tp>::channels, 1, traits::Type<_Tp>::value, (void*)&vec) { CV_Assert(n%DataType<_Tp>::channels == 0); if( copyData ) @@ -1280,7 +1687,7 @@ Mat_<_Tp>::Mat_(const Vec::channel_type, n>& vec, bool co template template inline Mat_<_Tp>::Mat_(const Matx::channel_type, m, n>& M, bool copyData) - : Mat(m, n / DataType<_Tp>::channels, DataType<_Tp>::type, (void*)&M) + : Mat(m, n / DataType<_Tp>::channels, traits::Type<_Tp>::value, (void*)&M) { CV_Assert(n % DataType<_Tp>::channels == 0); if( copyData ) @@ -1289,7 +1696,7 @@ Mat_<_Tp>::Mat_(const Matx::channel_type, m, n>& M, bool template inline Mat_<_Tp>::Mat_(const Point_::channel_type>& pt, bool copyData) - : Mat(2 / DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&pt) + : Mat(2 / DataType<_Tp>::channels, 1, traits::Type<_Tp>::value, (void*)&pt) { CV_Assert(2 % DataType<_Tp>::channels == 0); if( copyData ) @@ -1298,7 +1705,7 @@ Mat_<_Tp>::Mat_(const Point_::channel_type>& pt, bool cop template inline Mat_<_Tp>::Mat_(const Point3_::channel_type>& pt, bool copyData) - : Mat(3 / DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&pt) + : Mat(3 / DataType<_Tp>::channels, 1, traits::Type<_Tp>::value, (void*)&pt) { CV_Assert(3 % DataType<_Tp>::channels == 0); if( copyData ) @@ -1315,19 +1722,38 @@ Mat_<_Tp>::Mat_(const std::vector<_Tp>& vec, bool copyData) : Mat(vec, copyData) {} +#ifdef CV_CXX11 +template inline +Mat_<_Tp>::Mat_(std::initializer_list<_Tp> list) + : Mat(list) +{} + +template inline +Mat_<_Tp>::Mat_(const std::initializer_list sizes, std::initializer_list<_Tp> list) + : Mat(sizes, list) +{} +#endif + +#ifdef CV_CXX_STD_ARRAY +template template inline +Mat_<_Tp>::Mat_(const std::array<_Tp, _Nm>& arr, bool copyData) + : Mat(arr, copyData) +{} +#endif + template inline Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat& m) { - if( DataType<_Tp>::type == m.type() ) + if( traits::Type<_Tp>::value == m.type() ) { Mat::operator = (m); return *this; } - if( DataType<_Tp>::depth == m.depth() ) + if( traits::Depth<_Tp>::value == m.depth() ) { return (*this = m.reshape(DataType<_Tp>::channels, m.dims, 0)); } - CV_DbgAssert(DataType<_Tp>::channels == m.channels()); + CV_Assert(DataType<_Tp>::channels == m.channels() || m.empty()); m.convertTo(*this, type()); return *this; } @@ -1350,19 +1776,28 @@ Mat_<_Tp>& Mat_<_Tp>::operator = (const _Tp& s) template inline void Mat_<_Tp>::create(int _rows, int _cols) { - Mat::create(_rows, _cols, DataType<_Tp>::type); + Mat::create(_rows, _cols, traits::Type<_Tp>::value); } template inline void Mat_<_Tp>::create(Size _sz) { - Mat::create(_sz, DataType<_Tp>::type); + Mat::create(_sz, traits::Type<_Tp>::value); } template inline void Mat_<_Tp>::create(int _dims, const int* _sz) { - Mat::create(_dims, _sz, DataType<_Tp>::type); + Mat::create(_dims, _sz, traits::Type<_Tp>::value); +} + +template inline +void Mat_<_Tp>::release() +{ + Mat::release(); +#ifdef _DEBUG + flags = (flags & ~CV_MAT_TYPE_MASK) | traits::Type<_Tp>::value; +#endif } template inline @@ -1418,15 +1853,15 @@ size_t Mat_<_Tp>::elemSize1() const template inline int Mat_<_Tp>::type() const { - CV_DbgAssert( Mat::type() == DataType<_Tp>::type ); - return DataType<_Tp>::type; + CV_DbgAssert( Mat::type() == traits::Type<_Tp>::value ); + return traits::Type<_Tp>::value; } template inline int Mat_<_Tp>::depth() const { - CV_DbgAssert( Mat::depth() == DataType<_Tp>::depth ); - return DataType<_Tp>::depth; + CV_DbgAssert( Mat::depth() == traits::Depth<_Tp>::value ); + return traits::Depth<_Tp>::value; } template inline @@ -1472,57 +1907,67 @@ Mat_<_Tp> Mat_<_Tp>::operator()( const Range* ranges ) const return Mat_<_Tp>(*this, ranges); } +template inline +Mat_<_Tp> Mat_<_Tp>::operator()(const std::vector& ranges) const +{ + return Mat_<_Tp>(*this, ranges); +} + template inline _Tp* Mat_<_Tp>::operator [](int y) { - CV_DbgAssert( 0 <= y && y < rows ); + CV_DbgAssert( 0 <= y && y < size.p[0] ); return (_Tp*)(data + y*step.p[0]); } template inline const _Tp* Mat_<_Tp>::operator [](int y) const { - CV_DbgAssert( 0 <= y && y < rows ); + CV_DbgAssert( 0 <= y && y < size.p[0] ); return (const _Tp*)(data + y*step.p[0]); } template inline _Tp& Mat_<_Tp>::operator ()(int i0, int i1) { - CV_DbgAssert( dims <= 2 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] && - type() == DataType<_Tp>::type ); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); return ((_Tp*)(data + step.p[0] * i0))[i1]; } template inline const _Tp& Mat_<_Tp>::operator ()(int i0, int i1) const { - CV_DbgAssert( dims <= 2 && data && - (unsigned)i0 < (unsigned)size.p[0] && - (unsigned)i1 < (unsigned)size.p[1] && - type() == DataType<_Tp>::type ); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); return ((const _Tp*)(data + step.p[0] * i0))[i1]; } template inline _Tp& Mat_<_Tp>::operator ()(Point pt) { - CV_DbgAssert( dims <= 2 && data && - (unsigned)pt.y < (unsigned)size.p[0] && - (unsigned)pt.x < (unsigned)size.p[1] && - type() == DataType<_Tp>::type ); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)pt.x < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); return ((_Tp*)(data + step.p[0] * pt.y))[pt.x]; } template inline const _Tp& Mat_<_Tp>::operator ()(Point pt) const { - CV_DbgAssert( dims <= 2 && data && - (unsigned)pt.y < (unsigned)size.p[0] && - (unsigned)pt.x < (unsigned)size.p[1] && - type() == DataType<_Tp>::type ); + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)pt.x < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); return ((const _Tp*)(data + step.p[0] * pt.y))[pt.x]; } @@ -1582,11 +2027,27 @@ Mat_<_Tp>::operator std::vector<_Tp>() const return v; } +#ifdef CV_CXX_STD_ARRAY +template template inline +Mat_<_Tp>::operator std::array<_Tp, _Nm>() const +{ + std::array<_Tp, _Nm> a; + copyTo(a); + return a; +} +#endif + template template inline Mat_<_Tp>::operator Vec::channel_type, n>() const { CV_Assert(n % DataType<_Tp>::channels == 0); + +#if defined _MSC_VER + const Mat* pMat = (const Mat*)this; // workaround for MSVS <= 2012 compiler bugs (but GCC 4.6 dislikes this workaround) + return pMat->operator Vec::channel_type, n>(); +#else return this->Mat::operator Vec::channel_type, n>(); +#endif } template template inline @@ -1594,8 +2055,14 @@ Mat_<_Tp>::operator Matx::channel_type, m, n>() const { CV_Assert(n % DataType<_Tp>::channels == 0); +#if defined _MSC_VER + const Mat* pMat = (const Mat*)this; // workaround for MSVS <= 2012 compiler bugs (but GCC 4.6 dislikes this workaround) + Matx::channel_type, m, n> res = pMat->operator Matx::channel_type, m, n>(); + return res; +#else Matx::channel_type, m, n> res = this->Mat::operator Matx::channel_type, m, n>(); return res; +#endif } template inline @@ -1632,6 +2099,57 @@ void Mat_<_Tp>::forEach(const Functor& operation) const { Mat::forEach<_Tp, Functor>(operation); } +#ifdef CV_CXX_MOVE_SEMANTICS + +template inline +Mat_<_Tp>::Mat_(Mat_&& m) + : Mat(m) +{ +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (Mat_&& m) +{ + Mat::operator = (std::move(m)); + return *this; +} + +template inline +Mat_<_Tp>::Mat_(Mat&& m) + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) | traits::Type<_Tp>::value; + *this = m; +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (Mat&& m) +{ + if( traits::Type<_Tp>::value == m.type() ) + { + Mat::operator = ((Mat&&)m); + return *this; + } + if( traits::Depth<_Tp>::value == m.depth() ) + { + Mat::operator = ((Mat&&)m.reshape(DataType<_Tp>::channels, m.dims, 0)); + return *this; + } + CV_DbgAssert(DataType<_Tp>::channels == m.channels()); + m.convertTo(*this, type()); + return *this; +} + +template inline +Mat_<_Tp>::Mat_(MatExpr&& e) + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) | traits::Type<_Tp>::value; + *this = Mat(e); +} + +#endif + ///////////////////////////// SparseMat ///////////////////////////// inline @@ -1963,21 +2481,21 @@ SparseMatConstIterator_<_Tp> SparseMat::end() const template inline SparseMat_<_Tp>::SparseMat_() { - flags = MAGIC_VAL | DataType<_Tp>::type; + flags = MAGIC_VAL | traits::Type<_Tp>::value; } template inline SparseMat_<_Tp>::SparseMat_(int _dims, const int* _sizes) - : SparseMat(_dims, _sizes, DataType<_Tp>::type) + : SparseMat(_dims, _sizes, traits::Type<_Tp>::value) {} template inline SparseMat_<_Tp>::SparseMat_(const SparseMat& m) { - if( m.type() == DataType<_Tp>::type ) + if( m.type() == traits::Type<_Tp>::value ) *this = (const SparseMat_<_Tp>&)m; else - m.convertTo(*this, DataType<_Tp>::type); + m.convertTo(*this, traits::Type<_Tp>::value); } template inline @@ -2012,9 +2530,9 @@ SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const SparseMat_<_Tp>& m) template inline SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const SparseMat& m) { - if( m.type() == DataType<_Tp>::type ) + if( m.type() == traits::Type<_Tp>::value ) return (*this = (const SparseMat_<_Tp>&)m); - m.convertTo(*this, DataType<_Tp>::type); + m.convertTo(*this, traits::Type<_Tp>::value); return *this; } @@ -2035,19 +2553,19 @@ SparseMat_<_Tp> SparseMat_<_Tp>::clone() const template inline void SparseMat_<_Tp>::create(int _dims, const int* _sizes) { - SparseMat::create(_dims, _sizes, DataType<_Tp>::type); + SparseMat::create(_dims, _sizes, traits::Type<_Tp>::value); } template inline int SparseMat_<_Tp>::type() const { - return DataType<_Tp>::type; + return traits::Type<_Tp>::value; } template inline int SparseMat_<_Tp>::depth() const { - return DataType<_Tp>::depth; + return traits::Depth<_Tp>::value; } template inline @@ -2300,7 +2818,7 @@ ptrdiff_t operator - (const MatConstIterator& b, const MatConstIterator& a) if( a.m != b.m ) return ((size_t)(-1) >> 1); if( a.sliceEnd == b.sliceEnd ) - return (b.ptr - a.ptr)/b.elemSize; + return (b.ptr - a.ptr)/static_cast(b.elemSize); return b.lpos() - a.lpos(); } @@ -2369,7 +2887,7 @@ MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator = (const MatConstIterat } template inline -_Tp MatConstIterator_<_Tp>::operator *() const +const _Tp& MatConstIterator_<_Tp>::operator *() const { return *(_Tp*)(this->ptr); } @@ -2475,7 +2993,7 @@ MatConstIterator_<_Tp> operator - (const MatConstIterator_<_Tp>& a, ptrdiff_t of } template inline -_Tp MatConstIterator_<_Tp>::operator [](ptrdiff_t i) const +const _Tp& MatConstIterator_<_Tp>::operator [](ptrdiff_t i) const { return *(_Tp*)MatConstIterator::operator [](i); } @@ -2748,7 +3266,7 @@ template inline SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMat* _m) : SparseMatConstIterator(_m) { - CV_Assert( _m->type() == DataType<_Tp>::type ); + CV_Assert( _m->type() == traits::Type<_Tp>::value ); } template inline @@ -2884,50 +3402,50 @@ Mat& Mat::operator = (const MatExpr& e) template inline Mat_<_Tp>::Mat_(const MatExpr& e) { - e.op->assign(e, *this, DataType<_Tp>::type); + e.op->assign(e, *this, traits::Type<_Tp>::value); } template inline Mat_<_Tp>& Mat_<_Tp>::operator = (const MatExpr& e) { - e.op->assign(e, *this, DataType<_Tp>::type); + e.op->assign(e, *this, traits::Type<_Tp>::value); return *this; } template inline MatExpr Mat_<_Tp>::zeros(int rows, int cols) { - return Mat::zeros(rows, cols, DataType<_Tp>::type); + return Mat::zeros(rows, cols, traits::Type<_Tp>::value); } template inline MatExpr Mat_<_Tp>::zeros(Size sz) { - return Mat::zeros(sz, DataType<_Tp>::type); + return Mat::zeros(sz, traits::Type<_Tp>::value); } template inline MatExpr Mat_<_Tp>::ones(int rows, int cols) { - return Mat::ones(rows, cols, DataType<_Tp>::type); + return Mat::ones(rows, cols, traits::Type<_Tp>::value); } template inline MatExpr Mat_<_Tp>::ones(Size sz) { - return Mat::ones(sz, DataType<_Tp>::type); + return Mat::ones(sz, traits::Type<_Tp>::value); } template inline MatExpr Mat_<_Tp>::eye(int rows, int cols) { - return Mat::eye(rows, cols, DataType<_Tp>::type); + return Mat::eye(rows, cols, traits::Type<_Tp>::value); } template inline MatExpr Mat_<_Tp>::eye(Size sz) { - return Mat::eye(sz, DataType<_Tp>::type); + return Mat::eye(sz, traits::Type<_Tp>::value); } inline @@ -2953,7 +3471,7 @@ template inline MatExpr::operator Mat_<_Tp>() const { Mat_<_Tp> m; - op->assign(*this, m, DataType<_Tp>::type); + op->assign(*this, m, traits::Type<_Tp>::value); return m; } @@ -3186,7 +3704,7 @@ UMat::UMat(const UMat& m) template inline UMat::UMat(const std::vector<_Tp>& vec, bool copyData) -: flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()), +: flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()), cols(1), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows) { if(vec.empty()) @@ -3197,10 +3715,9 @@ cols(1), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows) CV_Error(Error::StsNotImplemented, ""); } else - Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this); + Mat((int)vec.size(), 1, traits::Type<_Tp>::value, (uchar*)&vec[0]).copyTo(*this); } - inline UMat& UMat::operator = (const UMat& m) { @@ -3331,6 +3848,12 @@ UMat UMat::operator()(const Range* ranges) const return UMat(*this, ranges); } +inline +UMat UMat::operator()(const std::vector& ranges) const +{ + return UMat(*this, ranges); +} + inline bool UMat::isContinuous() const { @@ -3346,7 +3869,9 @@ bool UMat::isSubmatrix() const inline size_t UMat::elemSize() const { - return dims > 0 ? step.p[dims - 1] : 0; + size_t res = dims > 0 ? step.p[dims - 1] : 0; + CV_DbgAssert(res != 0); + return res; } inline @@ -3382,7 +3907,7 @@ size_t UMat::step1(int i) const inline bool UMat::empty() const { - return u == 0 || total() == 0; + return u == 0 || total() == 0 || dims == 0; } inline @@ -3396,6 +3921,71 @@ size_t UMat::total() const return p; } +#ifdef CV_CXX_MOVE_SEMANTICS + +inline +UMat::UMat(UMat&& m) +: flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), allocator(m.allocator), + usageFlags(m.usageFlags), u(m.u), offset(m.offset), size(&rows) +{ + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.allocator = NULL; + m.u = NULL; + m.offset = 0; +} + +inline +UMat& UMat::operator = (UMat&& m) +{ + if (this == &m) + return *this; + release(); + flags = m.flags; dims = m.dims; rows = m.rows; cols = m.cols; + allocator = m.allocator; usageFlags = m.usageFlags; + u = m.u; + offset = m.offset; + if (step.p != step.buf) // release self step/size + { + fastFree(step.p); + step.p = step.buf; + size.p = &rows; + } + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.allocator = NULL; + m.u = NULL; + m.offset = 0; + return *this; +} + +#endif + + inline bool UMatData::hostCopyObsolete() const { return (flags & HOST_COPY_OBSOLETE) != 0; } inline bool UMatData::deviceCopyObsolete() const { return (flags & DEVICE_COPY_OBSOLETE) != 0; } inline bool UMatData::deviceMemMapped() const { return (flags & DEVICE_MEM_MAPPED) != 0; } @@ -3426,11 +4016,12 @@ inline void UMatData::markDeviceCopyObsolete(bool flag) flags &= ~DEVICE_COPY_OBSOLETE; } -inline UMatDataAutoLock::UMatDataAutoLock(UMatData* _u) : u(_u) { u->lock(); } -inline UMatDataAutoLock::~UMatDataAutoLock() { u->unlock(); } - //! @endcond } //cv +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + #endif diff --git a/include/opencv2/core/matx.hpp b/include/opencv2/core/matx.hpp index 2a17744..bf3f046 100644 --- a/include/opencv2/core/matx.hpp +++ b/include/opencv2/core/matx.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CORE_MATX_HPP__ -#define __OPENCV_CORE_MATX_HPP__ +#ifndef OPENCV_CORE_MATX_HPP +#define OPENCV_CORE_MATX_HPP #ifndef __cplusplus # error matx.hpp header must be compiled as C++ @@ -51,6 +51,11 @@ #include "opencv2/core/cvdef.h" #include "opencv2/core/base.hpp" #include "opencv2/core/traits.hpp" +#include "opencv2/core/saturate.hpp" + +#ifdef CV_CXX11 +#include +#endif namespace cv { @@ -61,13 +66,14 @@ namespace cv ////////////////////////////// Small Matrix /////////////////////////// //! @cond IGNORED -struct CV_EXPORTS Matx_AddOp {}; -struct CV_EXPORTS Matx_SubOp {}; -struct CV_EXPORTS Matx_ScaleOp {}; -struct CV_EXPORTS Matx_MulOp {}; -struct CV_EXPORTS Matx_DivOp {}; -struct CV_EXPORTS Matx_MatMulOp {}; -struct CV_EXPORTS Matx_TOp {}; +// FIXIT Remove this (especially CV_EXPORTS modifier) +struct CV_EXPORTS Matx_AddOp { Matx_AddOp() {} Matx_AddOp(const Matx_AddOp&) {} }; +struct CV_EXPORTS Matx_SubOp { Matx_SubOp() {} Matx_SubOp(const Matx_SubOp&) {} }; +struct CV_EXPORTS Matx_ScaleOp { Matx_ScaleOp() {} Matx_ScaleOp(const Matx_ScaleOp&) {} }; +struct CV_EXPORTS Matx_MulOp { Matx_MulOp() {} Matx_MulOp(const Matx_MulOp&) {} }; +struct CV_EXPORTS Matx_DivOp { Matx_DivOp() {} Matx_DivOp(const Matx_DivOp&) {} }; +struct CV_EXPORTS Matx_MatMulOp { Matx_MatMulOp() {} Matx_MatMulOp(const Matx_MatMulOp&) {} }; +struct CV_EXPORTS Matx_TOp { Matx_TOp() {} Matx_TOp(const Matx_TOp&) {} }; //! @endcond /** @brief Template class for small matrices whose type and size are known at compilation time @@ -76,21 +82,33 @@ If you need a more flexible type, use Mat . The elements of the matrix M are acc M(i,j) notation. Most of the common matrix operations (see also @ref MatrixExpressions ) are available. To do an operation on Matx that is not implemented, you can easily convert the matrix to Mat and backwards: -@code +@code{.cpp} Matx33f m(1, 2, 3, 4, 5, 6, 7, 8, 9); cout << sum(Mat(m*m.t())) << endl; - @endcode +@endcode +Except of the plain constructor which takes a list of elements, Matx can be initialized from a C-array: +@code{.cpp} + float values[] = { 1, 2, 3}; + Matx31f m(values); +@endcode +In case if C++11 features are available, std::initializer_list can be also used to initialize Matx: +@code{.cpp} + Matx31f m = { 1, 2, 3}; +@endcode */ template class Matx { public: - enum { depth = DataType<_Tp>::depth, + enum { rows = m, cols = n, channels = rows*cols, +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + depth = traits::Type<_Tp>::value, type = CV_MAKETYPE(depth, channels), +#endif shortdim = (m < n ? m : n) }; @@ -101,7 +119,7 @@ public: //! default constructor Matx(); - Matx(_Tp v0); //!< 1x1 matrix + explicit Matx(_Tp v0); //!< 1x1 matrix Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix @@ -114,12 +132,20 @@ public: Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11, + _Tp v12, _Tp v13); //!< 1x14, 2x7, 7x2 or 14x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix explicit Matx(const _Tp* vals); //!< initialize from a plain array +#ifdef CV_CXX11 + Matx(std::initializer_list<_Tp>); //!< initialize from an initializer list +#endif + static Matx all(_Tp alpha); static Matx zeros(); static Matx ones(); @@ -237,13 +263,23 @@ public: typedef value_type vec_type; enum { generic_type = 0, - depth = DataType::depth, channels = m * n, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; }; +namespace traits { +template +struct Depth< Matx<_Tp, m, n> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Matx<_Tp, m, n> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, n*m) }; }; +} // namespace + + /** @brief Comma-separated Matrix Initializer */ template class MatxCommaInitializer @@ -301,9 +337,13 @@ template class Vec : public Matx<_Tp, cn, 1> { public: typedef _Tp value_type; - enum { depth = Matx<_Tp, cn, 1>::depth, + enum { channels = cn, - type = CV_MAKETYPE(depth, channels) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + depth = Matx<_Tp, cn, 1>::depth, + type = CV_MAKETYPE(depth, channels), +#endif + _dummy_enum_finalizer = 0 }; //! default constructor @@ -319,8 +359,13 @@ public: Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 10-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13); //!< 14-element vector constructor explicit Vec(const _Tp* values); +#ifdef CV_CXX11 + Vec(std::initializer_list<_Tp>); +#endif + Vec(const Vec<_Tp, cn>& v); static Vec all(_Tp alpha); @@ -395,13 +440,24 @@ public: typedef value_type vec_type; enum { generic_type = 0, - depth = DataType::depth, channels = cn, fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + depth = DataType::depth, + type = CV_MAKETYPE(depth, channels), +#endif + _dummy_enum_finalizer = 0 }; }; +namespace traits { +template +struct Depth< Vec<_Tp, cn> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Vec<_Tp, cn> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, cn) }; }; +} // namespace + + /** @brief Comma-separated Vec Initializer */ template class VecCommaInitializer : public MatxCommaInitializer<_Tp, m, 1> @@ -432,7 +488,7 @@ template struct Matx_DetOp return p; for( int i = 0; i < m; i++ ) p *= temp(i, i); - return 1./p; + return p; } }; @@ -494,7 +550,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0) template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1) { - CV_StaticAssert(channels >= 2, "Matx should have at least 2 elaments."); + CV_StaticAssert(channels >= 2, "Matx should have at least 2 elements."); val[0] = v0; val[1] = v1; for(int i = 2; i < channels; i++) val[i] = _Tp(0); } @@ -502,7 +558,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1) template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2) { - CV_StaticAssert(channels >= 3, "Matx should have at least 3 elaments."); + CV_StaticAssert(channels >= 3, "Matx should have at least 3 elements."); val[0] = v0; val[1] = v1; val[2] = v2; for(int i = 3; i < channels; i++) val[i] = _Tp(0); } @@ -510,7 +566,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2) template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3) { - CV_StaticAssert(channels >= 4, "Matx should have at least 4 elaments."); + CV_StaticAssert(channels >= 4, "Matx should have at least 4 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; for(int i = 4; i < channels; i++) val[i] = _Tp(0); } @@ -518,7 +574,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3) template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4) { - CV_StaticAssert(channels >= 5, "Matx should have at least 5 elaments."); + CV_StaticAssert(channels >= 5, "Matx should have at least 5 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; for(int i = 5; i < channels; i++) val[i] = _Tp(0); } @@ -526,7 +582,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4) template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5) { - CV_StaticAssert(channels >= 6, "Matx should have at least 6 elaments."); + CV_StaticAssert(channels >= 6, "Matx should have at least 6 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; for(int i = 6; i < channels; i++) val[i] = _Tp(0); @@ -535,7 +591,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5) template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6) { - CV_StaticAssert(channels >= 7, "Matx should have at least 7 elaments."); + CV_StaticAssert(channels >= 7, "Matx should have at least 7 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; for(int i = 7; i < channels; i++) val[i] = _Tp(0); @@ -544,7 +600,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6) template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7) { - CV_StaticAssert(channels >= 8, "Matx should have at least 8 elaments."); + CV_StaticAssert(channels >= 8, "Matx should have at least 8 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; for(int i = 8; i < channels; i++) val[i] = _Tp(0); @@ -553,7 +609,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _T template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8) { - CV_StaticAssert(channels >= 9, "Matx should have at least 9 elaments."); + CV_StaticAssert(channels >= 9, "Matx should have at least 9 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; @@ -563,7 +619,7 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _T template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9) { - CV_StaticAssert(channels >= 10, "Matx should have at least 10 elaments."); + CV_StaticAssert(channels >= 10, "Matx should have at least 10 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; val[9] = v9; @@ -574,20 +630,34 @@ Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _T template inline Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11) { - CV_StaticAssert(channels == 12, "Matx should have at least 12 elaments."); + CV_StaticAssert(channels >= 12, "Matx should have at least 12 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; + for(int i = 12; i < channels; i++) val[i] = _Tp(0); } +template inline +Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13) +{ + CV_StaticAssert(channels >= 14, "Matx should have at least 14 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; + val[12] = v12; val[13] = v13; + for (int i = 14; i < channels; i++) val[i] = _Tp(0); +} + + template inline Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13, _Tp v14, _Tp v15) { - CV_StaticAssert(channels == 16, "Matx should have at least 16 elaments."); + CV_StaticAssert(channels >= 16, "Matx should have at least 16 elements."); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; val[12] = v12; val[13] = v13; val[14] = v14; val[15] = v15; + for(int i = 16; i < channels; i++) val[i] = _Tp(0); } template inline @@ -596,6 +666,19 @@ Matx<_Tp, m, n>::Matx(const _Tp* values) for( int i = 0; i < channels; i++ ) val[i] = values[i]; } +#ifdef CV_CXX11 +template inline +Matx<_Tp, m, n>::Matx(std::initializer_list<_Tp> list) +{ + CV_DbgAssert(list.size() == channels); + int i = 0; + for(const auto& elem : list) + { + val[i++] = elem; + } +} +#endif + template inline Matx<_Tp, m, n> Matx<_Tp, m, n>::all(_Tp alpha) { @@ -838,9 +921,17 @@ double norm(const Matx<_Tp, m, n>& M) template static inline double norm(const Matx<_Tp, m, n>& M, int normType) { - return normType == NORM_INF ? (double)normInf<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n) : - normType == NORM_L1 ? (double)normL1<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n) : - std::sqrt((double)normL2Sqr<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n)); + switch(normType) { + case NORM_INF: + return (double)normInf<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n); + case NORM_L1: + return (double)normL1<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n); + case NORM_L2SQR: + return (double)normL2Sqr<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n); + default: + case NORM_L2: + return std::sqrt((double)normL2Sqr<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n)); + } } @@ -921,10 +1012,20 @@ template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9) : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) {} +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) {} + template inline Vec<_Tp, cn>::Vec(const _Tp* values) : Matx<_Tp, cn, 1>(values) {} +#ifdef CV_CXX11 +template inline +Vec<_Tp, cn>::Vec(std::initializer_list<_Tp> list) + : Matx<_Tp, cn, 1>(list) {} +#endif + template inline Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& m) : Matx<_Tp, cn, 1>(m.val) {} @@ -991,17 +1092,17 @@ Vec<_Tp, cn> Vec<_Tp, cn>::cross(const Vec<_Tp, cn>&) const template<> inline Vec Vec::cross(const Vec& v) const { - return Vec(val[1]*v.val[2] - val[2]*v.val[1], - val[2]*v.val[0] - val[0]*v.val[2], - val[0]*v.val[1] - val[1]*v.val[0]); + return Vec(this->val[1]*v.val[2] - this->val[2]*v.val[1], + this->val[2]*v.val[0] - this->val[0]*v.val[2], + this->val[0]*v.val[1] - this->val[1]*v.val[0]); } template<> inline Vec Vec::cross(const Vec& v) const { - return Vec(val[1]*v.val[2] - val[2]*v.val[1], - val[2]*v.val[0] - val[0]*v.val[2], - val[0]*v.val[1] - val[1]*v.val[0]); + return Vec(this->val[1]*v.val[2] - this->val[2]*v.val[1], + this->val[2]*v.val[0] - this->val[0]*v.val[2], + this->val[0]*v.val[1] - this->val[1]*v.val[0]); } template template inline @@ -1049,7 +1150,7 @@ Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v) -//////////////////////////////// matx comma initializer ////////////////////////////////// +//////////////////////////////// vec comma initializer ////////////////////////////////// template static inline @@ -1373,4 +1474,4 @@ template inline Vec<_Tp, 4>& operator *= (Vec<_Tp, 4>& v1, const V } // cv -#endif // __OPENCV_CORE_MATX_HPP__ +#endif // OPENCV_CORE_MATX_HPP diff --git a/include/opencv2/core/neon_utils.hpp b/include/opencv2/core/neon_utils.hpp new file mode 100644 index 0000000..573ba99 --- /dev/null +++ b/include/opencv2/core/neon_utils.hpp @@ -0,0 +1,128 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_HAL_NEON_UTILS_HPP +#define OPENCV_HAL_NEON_UTILS_HPP + +#include "opencv2/core/cvdef.h" + +//! @addtogroup core_utils_neon +//! @{ + +#if CV_NEON + +inline int32x2_t cv_vrnd_s32_f32(float32x2_t v) +{ + static int32x2_t v_sign = vdup_n_s32(1 << 31), + v_05 = vreinterpret_s32_f32(vdup_n_f32(0.5f)); + + int32x2_t v_addition = vorr_s32(v_05, vand_s32(v_sign, vreinterpret_s32_f32(v))); + return vcvt_s32_f32(vadd_f32(v, vreinterpret_f32_s32(v_addition))); +} + +inline int32x4_t cv_vrndq_s32_f32(float32x4_t v) +{ + static int32x4_t v_sign = vdupq_n_s32(1 << 31), + v_05 = vreinterpretq_s32_f32(vdupq_n_f32(0.5f)); + + int32x4_t v_addition = vorrq_s32(v_05, vandq_s32(v_sign, vreinterpretq_s32_f32(v))); + return vcvtq_s32_f32(vaddq_f32(v, vreinterpretq_f32_s32(v_addition))); +} + +inline uint32x2_t cv_vrnd_u32_f32(float32x2_t v) +{ + static float32x2_t v_05 = vdup_n_f32(0.5f); + return vcvt_u32_f32(vadd_f32(v, v_05)); +} + +inline uint32x4_t cv_vrndq_u32_f32(float32x4_t v) +{ + static float32x4_t v_05 = vdupq_n_f32(0.5f); + return vcvtq_u32_f32(vaddq_f32(v, v_05)); +} + +inline float32x4_t cv_vrecpq_f32(float32x4_t val) +{ + float32x4_t reciprocal = vrecpeq_f32(val); + reciprocal = vmulq_f32(vrecpsq_f32(val, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(val, reciprocal), reciprocal); + return reciprocal; +} + +inline float32x2_t cv_vrecp_f32(float32x2_t val) +{ + float32x2_t reciprocal = vrecpe_f32(val); + reciprocal = vmul_f32(vrecps_f32(val, reciprocal), reciprocal); + reciprocal = vmul_f32(vrecps_f32(val, reciprocal), reciprocal); + return reciprocal; +} + +inline float32x4_t cv_vrsqrtq_f32(float32x4_t val) +{ + float32x4_t e = vrsqrteq_f32(val); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(e, e), val), e); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(e, e), val), e); + return e; +} + +inline float32x2_t cv_vrsqrt_f32(float32x2_t val) +{ + float32x2_t e = vrsqrte_f32(val); + e = vmul_f32(vrsqrts_f32(vmul_f32(e, e), val), e); + e = vmul_f32(vrsqrts_f32(vmul_f32(e, e), val), e); + return e; +} + +inline float32x4_t cv_vsqrtq_f32(float32x4_t val) +{ + return cv_vrecpq_f32(cv_vrsqrtq_f32(val)); +} + +inline float32x2_t cv_vsqrt_f32(float32x2_t val) +{ + return cv_vrecp_f32(cv_vrsqrt_f32(val)); +} + +#endif + +//! @} + +#endif // OPENCV_HAL_NEON_UTILS_HPP diff --git a/include/opencv2/core/ocl.hpp b/include/opencv2/core/ocl.hpp index 173722f..95f0fcd 100644 --- a/include/opencv2/core/ocl.hpp +++ b/include/opencv2/core/ocl.hpp @@ -39,8 +39,8 @@ // //M*/ -#ifndef __OPENCV_OPENCL_HPP__ -#define __OPENCV_OPENCL_HPP__ +#ifndef OPENCV_OPENCL_HPP +#define OPENCV_OPENCL_HPP #include "opencv2/core.hpp" @@ -59,7 +59,7 @@ CV_EXPORTS_W void finish(); CV_EXPORTS bool haveSVM(); class CV_EXPORTS Context; -class CV_EXPORTS Device; +class CV_EXPORTS_W_SIMPLE Device; class CV_EXPORTS Kernel; class CV_EXPORTS Program; class CV_EXPORTS ProgramSource; @@ -67,14 +67,14 @@ class CV_EXPORTS Queue; class CV_EXPORTS PlatformInfo; class CV_EXPORTS Image2D; -class CV_EXPORTS Device +class CV_EXPORTS_W_SIMPLE Device { public: - Device(); + CV_WRAP Device(); explicit Device(void* d); Device(const Device& d); Device& operator = (const Device& d); - ~Device(); + CV_WRAP ~Device(); void set(void* d); @@ -89,23 +89,24 @@ public: TYPE_ALL = 0xFFFFFFFF }; - String name() const; - String extensions() const; - String version() const; - String vendorName() const; - String OpenCL_C_Version() const; - String OpenCLVersion() const; - int deviceVersionMajor() const; - int deviceVersionMinor() const; - String driverVersion() const; + CV_WRAP String name() const; + CV_WRAP String extensions() const; + CV_WRAP bool isExtensionSupported(const String& extensionName) const; + CV_WRAP String version() const; + CV_WRAP String vendorName() const; + CV_WRAP String OpenCL_C_Version() const; + CV_WRAP String OpenCLVersion() const; + CV_WRAP int deviceVersionMajor() const; + CV_WRAP int deviceVersionMinor() const; + CV_WRAP String driverVersion() const; void* ptr() const; - int type() const; + CV_WRAP int type() const; - int addressBits() const; - bool available() const; - bool compilerAvailable() const; - bool linkerAvailable() const; + CV_WRAP int addressBits() const; + CV_WRAP bool available() const; + CV_WRAP bool compilerAvailable() const; + CV_WRAP bool linkerAvailable() const; enum { @@ -118,21 +119,21 @@ public: FP_SOFT_FLOAT=(1 << 6), FP_CORRECTLY_ROUNDED_DIVIDE_SQRT=(1 << 7) }; - int doubleFPConfig() const; - int singleFPConfig() const; - int halfFPConfig() const; + CV_WRAP int doubleFPConfig() const; + CV_WRAP int singleFPConfig() const; + CV_WRAP int halfFPConfig() const; - bool endianLittle() const; - bool errorCorrectionSupport() const; + CV_WRAP bool endianLittle() const; + CV_WRAP bool errorCorrectionSupport() const; enum { EXEC_KERNEL=(1 << 0), EXEC_NATIVE_KERNEL=(1 << 1) }; - int executionCapabilities() const; + CV_WRAP int executionCapabilities() const; - size_t globalMemCacheSize() const; + CV_WRAP size_t globalMemCacheSize() const; enum { @@ -140,35 +141,38 @@ public: READ_ONLY_CACHE=1, READ_WRITE_CACHE=2 }; - int globalMemCacheType() const; - int globalMemCacheLineSize() const; - size_t globalMemSize() const; + CV_WRAP int globalMemCacheType() const; + CV_WRAP int globalMemCacheLineSize() const; + CV_WRAP size_t globalMemSize() const; - size_t localMemSize() const; + CV_WRAP size_t localMemSize() const; enum { NO_LOCAL_MEM=0, LOCAL_IS_LOCAL=1, LOCAL_IS_GLOBAL=2 }; - int localMemType() const; - bool hostUnifiedMemory() const; + CV_WRAP int localMemType() const; + CV_WRAP bool hostUnifiedMemory() const; - bool imageSupport() const; + CV_WRAP bool imageSupport() const; - bool imageFromBufferSupport() const; + CV_WRAP bool imageFromBufferSupport() const; uint imagePitchAlignment() const; uint imageBaseAddressAlignment() const; - size_t image2DMaxWidth() const; - size_t image2DMaxHeight() const; + /// deprecated, use isExtensionSupported() method (probably with "cl_khr_subgroups" value) + CV_WRAP bool intelSubgroupsSupport() const; - size_t image3DMaxWidth() const; - size_t image3DMaxHeight() const; - size_t image3DMaxDepth() const; + CV_WRAP size_t image2DMaxWidth() const; + CV_WRAP size_t image2DMaxHeight() const; - size_t imageMaxBufferSize() const; - size_t imageMaxArraySize() const; + CV_WRAP size_t image3DMaxWidth() const; + CV_WRAP size_t image3DMaxHeight() const; + CV_WRAP size_t image3DMaxDepth() const; + + CV_WRAP size_t imageMaxBufferSize() const; + CV_WRAP size_t imageMaxArraySize() const; enum { @@ -177,53 +181,53 @@ public: VENDOR_INTEL=2, VENDOR_NVIDIA=3 }; - int vendorID() const; + CV_WRAP int vendorID() const; // FIXIT // dev.isAMD() doesn't work for OpenCL CPU devices from AMD OpenCL platform. // This method should use platform name instead of vendor name. // After fix restore code in arithm.cpp: ocl_compare() - inline bool isAMD() const { return vendorID() == VENDOR_AMD; } - inline bool isIntel() const { return vendorID() == VENDOR_INTEL; } - inline bool isNVidia() const { return vendorID() == VENDOR_NVIDIA; } + CV_WRAP inline bool isAMD() const { return vendorID() == VENDOR_AMD; } + CV_WRAP inline bool isIntel() const { return vendorID() == VENDOR_INTEL; } + CV_WRAP inline bool isNVidia() const { return vendorID() == VENDOR_NVIDIA; } - int maxClockFrequency() const; - int maxComputeUnits() const; - int maxConstantArgs() const; - size_t maxConstantBufferSize() const; + CV_WRAP int maxClockFrequency() const; + CV_WRAP int maxComputeUnits() const; + CV_WRAP int maxConstantArgs() const; + CV_WRAP size_t maxConstantBufferSize() const; - size_t maxMemAllocSize() const; - size_t maxParameterSize() const; + CV_WRAP size_t maxMemAllocSize() const; + CV_WRAP size_t maxParameterSize() const; - int maxReadImageArgs() const; - int maxWriteImageArgs() const; - int maxSamplers() const; + CV_WRAP int maxReadImageArgs() const; + CV_WRAP int maxWriteImageArgs() const; + CV_WRAP int maxSamplers() const; - size_t maxWorkGroupSize() const; - int maxWorkItemDims() const; + CV_WRAP size_t maxWorkGroupSize() const; + CV_WRAP int maxWorkItemDims() const; void maxWorkItemSizes(size_t*) const; - int memBaseAddrAlign() const; + CV_WRAP int memBaseAddrAlign() const; - int nativeVectorWidthChar() const; - int nativeVectorWidthShort() const; - int nativeVectorWidthInt() const; - int nativeVectorWidthLong() const; - int nativeVectorWidthFloat() const; - int nativeVectorWidthDouble() const; - int nativeVectorWidthHalf() const; + CV_WRAP int nativeVectorWidthChar() const; + CV_WRAP int nativeVectorWidthShort() const; + CV_WRAP int nativeVectorWidthInt() const; + CV_WRAP int nativeVectorWidthLong() const; + CV_WRAP int nativeVectorWidthFloat() const; + CV_WRAP int nativeVectorWidthDouble() const; + CV_WRAP int nativeVectorWidthHalf() const; - int preferredVectorWidthChar() const; - int preferredVectorWidthShort() const; - int preferredVectorWidthInt() const; - int preferredVectorWidthLong() const; - int preferredVectorWidthFloat() const; - int preferredVectorWidthDouble() const; - int preferredVectorWidthHalf() const; + CV_WRAP int preferredVectorWidthChar() const; + CV_WRAP int preferredVectorWidthShort() const; + CV_WRAP int preferredVectorWidthInt() const; + CV_WRAP int preferredVectorWidthLong() const; + CV_WRAP int preferredVectorWidthFloat() const; + CV_WRAP int preferredVectorWidthDouble() const; + CV_WRAP int preferredVectorWidthHalf() const; - size_t printfBufferSize() const; - size_t profilingTimerResolution() const; + CV_WRAP size_t printfBufferSize() const; + CV_WRAP size_t profilingTimerResolution() const; - static const Device& getDefault(); + CV_WRAP static const Device& getDefault(); protected: struct Impl; @@ -246,6 +250,7 @@ public: const Device& device(size_t idx) const; Program getProg(const ProgramSource& prog, const String& buildopt, String& errmsg); + void unloadProg(Program& prog); static Context& getDefault(bool initialize = true); void* ptr() const; @@ -256,6 +261,8 @@ public: void setUseSVM(bool enabled); struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } +//protected: Impl* p; }; @@ -276,6 +283,41 @@ protected: Impl* p; }; +/** @brief Attaches OpenCL context to OpenCV +@note + OpenCV will check if available OpenCL platform has platformName name, then assign context to + OpenCV and call `clRetainContext` function. The deviceID device will be used as target device and + new command queue will be created. +@param platformName name of OpenCL platform to attach, this string is used to check if platform is available to OpenCV at runtime +@param platformID ID of platform attached context was created for +@param context OpenCL context to be attached to OpenCV +@param deviceID ID of device, must be created from attached context +*/ +CV_EXPORTS void attachContext(const String& platformName, void* platformID, void* context, void* deviceID); + +/** @brief Convert OpenCL buffer to UMat +@note + OpenCL buffer (cl_mem_buffer) should contain 2D image data, compatible with OpenCV. Memory + content is not copied from `clBuffer` to UMat. Instead, buffer handle assigned to UMat and + `clRetainMemObject` is called. +@param cl_mem_buffer source clBuffer handle +@param step num of bytes in single row +@param rows number of rows +@param cols number of cols +@param type OpenCV type of image +@param dst destination UMat +*/ +CV_EXPORTS void convertFromBuffer(void* cl_mem_buffer, size_t step, int rows, int cols, int type, UMat& dst); + +/** @brief Convert OpenCL image2d_t to UMat +@note + OpenCL `image2d_t` (cl_mem_image), should be compatible with OpenCV UMat formats. Memory content + is copied from image to UMat with `clEnqueueCopyImageToBuffer` function. +@param cl_mem_image source image2d_t handle +@param dst destination UMat +*/ +CV_EXPORTS void convertFromImage(void* cl_mem_image, UMat& dst); + // TODO Move to internal header void initializeContextFromHandle(Context& ctx, void* platform, void* context, void* device); @@ -293,8 +335,12 @@ public: void* ptr() const; static Queue& getDefault(); + /// @brief Returns OpenCL command queue with enable profiling mode support + const Queue& getProfilingQueue() const; + + struct Impl; friend struct Impl; + inline Impl* getImpl() const { return p; } protected: - struct Impl; Impl* p; }; @@ -306,7 +352,8 @@ public: KernelArg(int _flags, UMat* _m, int wscale=1, int iwscale=1, const void* _obj=0, size_t _sz=0); KernelArg(); - static KernelArg Local() { return KernelArg(LOCAL, 0); } + static KernelArg Local(size_t localMemSize) + { return KernelArg(LOCAL, 0, 1, 1, 0, localMemSize); } static KernelArg PtrWriteOnly(const UMat& m) { return KernelArg(PTR_ONLY+WRITE_ONLY, (UMat*)&m); } static KernelArg PtrReadOnly(const UMat& m) @@ -515,11 +562,26 @@ public: i = set(i, a6); i = set(i, a7); i = set(i, a8); i = set(i, a9); i = set(i, a10); i = set(i, a11); i = set(i, a12); i = set(i, a13); i = set(i, a14); set(i, a15); return *this; } - + /** @brief Run the OpenCL kernel. + @param dims the work problem dimensions. It is the length of globalsize and localsize. It can be either 1, 2 or 3. + @param globalsize work items for each dimension. It is not the final globalsize passed to + OpenCL. Each dimension will be adjusted to the nearest integer divisible by the corresponding + value in localsize. If localsize is NULL, it will still be adjusted depending on dims. The + adjusted values are greater than or equal to the original values. + @param localsize work-group size for each dimension. + @param sync specify whether to wait for OpenCL computation to finish before return. + @param q command queue + */ bool run(int dims, size_t globalsize[], size_t localsize[], bool sync, const Queue& q=Queue()); bool runTask(bool sync, const Queue& q=Queue()); + /** @brief Similar to synchronized run() call with returning of kernel execution time + * Separate OpenCL command queue may be used (with CL_QUEUE_PROFILING_ENABLE) + * @return Execution time in nanoseconds or negative number on error + */ + int64 runProfiling(int dims, size_t globalsize[], size_t localsize[], const Queue& q=Queue()); + size_t workGroupSize() const; size_t preferedWorkGroupSizeMultiple() const; bool compileWorkGroupSize(size_t wsz[]) const; @@ -538,7 +600,6 @@ public: Program(); Program(const ProgramSource& src, const String& buildflags, String& errmsg); - explicit Program(const String& buf); Program(const Program& prog); Program& operator = (const Program& prog); @@ -546,38 +607,104 @@ public: bool create(const ProgramSource& src, const String& buildflags, String& errmsg); - bool read(const String& buf, const String& buildflags); - bool write(String& buf) const; - const ProgramSource& source() const; void* ptr() const; - String getPrefix() const; - static String getPrefix(const String& buildflags); + /** + * @brief Query device-specific program binary. + * + * Returns RAW OpenCL executable binary without additional attachments. + * + * @sa ProgramSource::fromBinary + * + * @param[out] binary output buffer + */ + void getBinary(std::vector& binary) const; + struct Impl; friend struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } protected: - struct Impl; Impl* p; +public: +#ifndef OPENCV_REMOVE_DEPRECATED_API + // TODO Remove this + CV_DEPRECATED bool read(const String& buf, const String& buildflags); // removed, use ProgramSource instead + CV_DEPRECATED bool write(String& buf) const; // removed, use getBinary() method instead (RAW OpenCL binary) + CV_DEPRECATED const ProgramSource& source() const; // implementation removed + CV_DEPRECATED String getPrefix() const; // deprecated, implementation replaced + CV_DEPRECATED static String getPrefix(const String& buildflags); // deprecated, implementation replaced +#endif }; class CV_EXPORTS ProgramSource { public: - typedef uint64 hash_t; + typedef uint64 hash_t; // deprecated ProgramSource(); - explicit ProgramSource(const String& prog); - explicit ProgramSource(const char* prog); + explicit ProgramSource(const String& module, const String& name, const String& codeStr, const String& codeHash); + explicit ProgramSource(const String& prog); // deprecated + explicit ProgramSource(const char* prog); // deprecated ~ProgramSource(); ProgramSource(const ProgramSource& prog); ProgramSource& operator = (const ProgramSource& prog); - const String& source() const; - hash_t hash() const; + const String& source() const; // deprecated + hash_t hash() const; // deprecated + + /** @brief Describe OpenCL program binary. + * Do not call clCreateProgramWithBinary() and/or clBuildProgram(). + * + * Caller should guarantee binary buffer lifetime greater than ProgramSource object (and any of its copies). + * + * This kind of binary is not portable between platforms in general - it is specific to OpenCL vendor / device / driver version. + * + * @param module name of program owner module + * @param name unique name of program (module+name is used as key for OpenCL program caching) + * @param binary buffer address. See buffer lifetime requirement in description. + * @param size buffer size + * @param buildOptions additional program-related build options passed to clBuildProgram() + * @return created ProgramSource object + */ + static ProgramSource fromBinary(const String& module, const String& name, + const unsigned char* binary, const size_t size, + const cv::String& buildOptions = cv::String()); + + /** @brief Describe OpenCL program in SPIR format. + * Do not call clCreateProgramWithBinary() and/or clBuildProgram(). + * + * Supports SPIR 1.2 by default (pass '-spir-std=X.Y' in buildOptions to override this behavior) + * + * Caller should guarantee binary buffer lifetime greater than ProgramSource object (and any of its copies). + * + * Programs in this format are portable between OpenCL implementations with 'khr_spir' extension: + * https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/cl_khr_spir.html + * (but they are not portable between different platforms: 32-bit / 64-bit) + * + * Note: these programs can't support vendor specific extensions, like 'cl_intel_subgroups'. + * + * @param module name of program owner module + * @param name unique name of program (module+name is used as key for OpenCL program caching) + * @param binary buffer address. See buffer lifetime requirement in description. + * @param size buffer size + * @param buildOptions additional program-related build options passed to clBuildProgram() + * (these options are added automatically: '-x spir' and '-spir-std=1.2') + * @return created ProgramSource object. + */ + static ProgramSource fromSPIR(const String& module, const String& name, + const unsigned char* binary, const size_t size, + const cv::String& buildOptions = cv::String()); + + //OpenCL 2.1+ only + //static Program fromSPIRV(const String& module, const String& name, + // const unsigned char* binary, const size_t size, + // const cv::String& buildOptions = cv::String()); + + struct Impl; friend struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } protected: - struct Impl; Impl* p; }; @@ -606,6 +733,7 @@ CV_EXPORTS const char* convertTypeStr(int sdepth, int ddepth, int cn, char* buf) CV_EXPORTS const char* typeToStr(int t); CV_EXPORTS const char* memopTypeToStr(int t); CV_EXPORTS const char* vecopTypeToStr(int t); +CV_EXPORTS const char* getOpenCLErrorString(int errorCode); CV_EXPORTS String kernelToStr(InputArray _kernel, int ddepth = -1, const char * name = NULL); CV_EXPORTS void getPlatfomsInfo(std::vector& platform_info); @@ -645,22 +773,25 @@ class CV_EXPORTS Image2D public: Image2D(); - // src: The UMat from which to get image properties and data - // norm: Flag to enable the use of normalized channel data types - // alias: Flag indicating that the image should alias the src UMat. - // If true, changes to the image or src will be reflected in - // both objects. + /** + @param src UMat object from which to get image properties and data + @param norm flag to enable the use of normalized channel data types + @param alias flag indicating that the image should alias the src UMat. If true, changes to the + image or src will be reflected in both objects. + */ explicit Image2D(const UMat &src, bool norm = false, bool alias = false); Image2D(const Image2D & i); ~Image2D(); Image2D & operator = (const Image2D & i); - // Indicates if creating an aliased image should succeed. Depends on the - // underlying platform and the dimensions of the UMat. + /** Indicates if creating an aliased image should succeed. + Depends on the underlying platform and the dimensions of the UMat. + */ static bool canCreateAlias(const UMat &u); - // Indicates if the image format is supported. + /** Indicates if the image format is supported. + */ static bool isFormatSupported(int depth, int cn, bool norm); void* ptr() const; @@ -669,6 +800,24 @@ protected: Impl* p; }; +class CV_EXPORTS Timer +{ +public: + Timer(const Queue& q); + ~Timer(); + void start(); + void stop(); + + uint64 durationNS() const; //< duration in nanoseconds + +protected: + struct Impl; + Impl* const p; + +private: + Timer(const Timer&); // disabled + Timer& operator=(const Timer&); // disabled +}; CV_EXPORTS MatAllocator* getOpenCLAllocator(); @@ -676,6 +825,9 @@ CV_EXPORTS MatAllocator* getOpenCLAllocator(); #ifdef __OPENCV_BUILD namespace internal { +CV_EXPORTS bool isOpenCLForced(); +#define OCL_FORCE_CHECK(condition) (cv::ocl::internal::isOpenCLForced() || (condition)) + CV_EXPORTS bool isPerformanceCheckBypassed(); #define OCL_PERFORMANCE_CHECK(condition) (cv::ocl::internal::isPerformanceCheckBypassed() || (condition)) diff --git a/include/opencv2/core/ocl_genbase.hpp b/include/opencv2/core/ocl_genbase.hpp index d53bc1a..5334cf1 100644 --- a/include/opencv2/core/ocl_genbase.hpp +++ b/include/opencv2/core/ocl_genbase.hpp @@ -39,26 +39,31 @@ // //M*/ -#ifndef __OPENCV_OPENCL_GENBASE_HPP__ -#define __OPENCV_OPENCL_GENBASE_HPP__ - -namespace cv -{ -namespace ocl -{ +#ifndef OPENCV_OPENCL_GENBASE_HPP +#define OPENCV_OPENCL_GENBASE_HPP //! @cond IGNORED -struct ProgramEntry +namespace cv { +namespace ocl { + +class ProgramSource; + +namespace internal { + +struct CV_EXPORTS ProgramEntry { + const char* module; const char* name; - const char* programStr; + const char* programCode; const char* programHash; + ProgramSource* pProgramSource; + + operator ProgramSource& () const; }; +} } } // namespace + //! @endcond -} -} - #endif diff --git a/include/opencv2/core/opencl/ocl_defs.hpp b/include/opencv2/core/opencl/ocl_defs.hpp new file mode 100644 index 0000000..605a65f --- /dev/null +++ b/include/opencv2/core/opencl/ocl_defs.hpp @@ -0,0 +1,75 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. + +#ifndef OPENCV_CORE_OPENCL_DEFS_HPP +#define OPENCV_CORE_OPENCL_DEFS_HPP + +#include "opencv2/core/utility.hpp" +#include "cvconfig.h" + +namespace cv { namespace ocl { +#ifdef HAVE_OPENCL +/// Call is similar to useOpenCL() but doesn't try to load OpenCL runtime or create OpenCL context +CV_EXPORTS bool isOpenCLActivated(); +#else +static inline bool isOpenCLActivated() { return false; } +#endif +}} // namespace + + +//#define CV_OPENCL_RUN_ASSERT + +#ifdef HAVE_OPENCL + +#ifdef CV_OPENCL_RUN_VERBOSE +#define CV_OCL_RUN_(condition, func, ...) \ + { \ + if (cv::ocl::isOpenCLActivated() && (condition) && func) \ + { \ + printf("%s: OpenCL implementation is running\n", CV_Func); \ + fflush(stdout); \ + CV_IMPL_ADD(CV_IMPL_OCL); \ + return __VA_ARGS__; \ + } \ + else \ + { \ + printf("%s: Plain implementation is running\n", CV_Func); \ + fflush(stdout); \ + } \ + } +#elif defined CV_OPENCL_RUN_ASSERT +#define CV_OCL_RUN_(condition, func, ...) \ + { \ + if (cv::ocl::isOpenCLActivated() && (condition)) \ + { \ + if(func) \ + { \ + CV_IMPL_ADD(CV_IMPL_OCL); \ + } \ + else \ + { \ + CV_Error(cv::Error::StsAssert, #func); \ + } \ + return __VA_ARGS__; \ + } \ + } +#else +#define CV_OCL_RUN_(condition, func, ...) \ + if (cv::ocl::isOpenCLActivated() && (condition) && func) \ + { \ + CV_IMPL_ADD(CV_IMPL_OCL); \ + return __VA_ARGS__; \ + } +#endif + +#else +#define CV_OCL_RUN_(condition, func, ...) +#endif + +#define CV_OCL_RUN(condition, func) CV_OCL_RUN_(condition, func) + +#endif // OPENCV_CORE_OPENCL_DEFS_HPP diff --git a/include/opencv2/core/opencl/opencl_info.hpp b/include/opencv2/core/opencl/opencl_info.hpp new file mode 100644 index 0000000..b5d3739 --- /dev/null +++ b/include/opencv2/core/opencl/opencl_info.hpp @@ -0,0 +1,198 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include + +#include +#include + +#ifndef DUMP_CONFIG_PROPERTY +#define DUMP_CONFIG_PROPERTY(...) +#endif + +#ifndef DUMP_MESSAGE_STDOUT +#define DUMP_MESSAGE_STDOUT(...) do { std::cout << __VA_ARGS__ << std::endl; } while (false) +#endif + +namespace cv { + +namespace { +static std::string bytesToStringRepr(size_t value) +{ + size_t b = value % 1024; + value /= 1024; + + size_t kb = value % 1024; + value /= 1024; + + size_t mb = value % 1024; + value /= 1024; + + size_t gb = value; + + std::ostringstream stream; + + if (gb > 0) + stream << gb << " GB "; + if (mb > 0) + stream << mb << " MB "; + if (kb > 0) + stream << kb << " KB "; + if (b > 0) + stream << b << " B"; + + std::string s = stream.str(); + if (s[s.size() - 1] == ' ') + s = s.substr(0, s.size() - 1); + return s; +} +} // namespace + +static void dumpOpenCLInformation() +{ + using namespace cv::ocl; + + try + { + if (!haveOpenCL() || !useOpenCL()) + { + DUMP_MESSAGE_STDOUT("OpenCL is disabled"); + DUMP_CONFIG_PROPERTY("cv_ocl", "disabled"); + return; + } + + std::vector platforms; + cv::ocl::getPlatfomsInfo(platforms); + if (platforms.size() > 0) + { + DUMP_MESSAGE_STDOUT("OpenCL Platforms: "); + for (size_t i = 0; i < platforms.size(); i++) + { + const PlatformInfo* platform = &platforms[i]; + DUMP_MESSAGE_STDOUT(" " << platform->name().c_str()); + Device current_device; + for (int j = 0; j < platform->deviceNumber(); j++) + { + platform->getDevice(current_device, j); + const char* deviceTypeStr = current_device.type() == Device::TYPE_CPU + ? ("CPU") : (current_device.type() == Device::TYPE_GPU ? current_device.hostUnifiedMemory() ? "iGPU" : "dGPU" : "unknown"); + DUMP_MESSAGE_STDOUT( " " << deviceTypeStr << ": " << current_device.name().c_str() << " (" << current_device.version().c_str() << ")"); + DUMP_CONFIG_PROPERTY( cv::format("cv_ocl_platform_%d_device_%d", (int)i, (int)j ), + cv::format("(Platform=%s)(Type=%s)(Name=%s)(Version=%s)", + platform->name().c_str(), deviceTypeStr, current_device.name().c_str(), current_device.version().c_str()) ); + } + } + } + else + { + DUMP_MESSAGE_STDOUT("OpenCL is not available"); + DUMP_CONFIG_PROPERTY("cv_ocl", "not available"); + return; + } + + const Device& device = Device::getDefault(); + if (!device.available()) + CV_Error(Error::OpenCLInitError, "OpenCL device is not available"); + + DUMP_MESSAGE_STDOUT("Current OpenCL device: "); + +#if 0 + DUMP_MESSAGE_STDOUT(" Platform = " << device.getPlatform().name()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_platformName", device.getPlatform().name()); +#endif + + const char* deviceTypeStr = device.type() == Device::TYPE_CPU + ? ("CPU") : (device.type() == Device::TYPE_GPU ? device.hostUnifiedMemory() ? "iGPU" : "dGPU" : "unknown"); + DUMP_MESSAGE_STDOUT(" Type = " << deviceTypeStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_deviceType", deviceTypeStr); + + DUMP_MESSAGE_STDOUT(" Name = " << device.name()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_deviceName", device.name()); + + DUMP_MESSAGE_STDOUT(" Version = " << device.version()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_deviceVersion", device.version()); + + DUMP_MESSAGE_STDOUT(" Driver version = " << device.driverVersion()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_driverVersion", device.driverVersion()); + + DUMP_MESSAGE_STDOUT(" Address bits = " << device.addressBits()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_addressBits", device.addressBits()); + + DUMP_MESSAGE_STDOUT(" Compute units = " << device.maxComputeUnits()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_maxComputeUnits", device.maxComputeUnits()); + + DUMP_MESSAGE_STDOUT(" Max work group size = " << device.maxWorkGroupSize()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_maxWorkGroupSize", device.maxWorkGroupSize()); + + std::string localMemorySizeStr = bytesToStringRepr(device.localMemSize()); + DUMP_MESSAGE_STDOUT(" Local memory size = " << localMemorySizeStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_localMemSize", device.localMemSize()); + + std::string maxMemAllocSizeStr = bytesToStringRepr(device.maxMemAllocSize()); + DUMP_MESSAGE_STDOUT(" Max memory allocation size = " << maxMemAllocSizeStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_maxMemAllocSize", device.maxMemAllocSize()); + + const char* doubleSupportStr = device.doubleFPConfig() > 0 ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Double support = " << doubleSupportStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_haveDoubleSupport", device.doubleFPConfig() > 0); + + const char* isUnifiedMemoryStr = device.hostUnifiedMemory() ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Host unified memory = " << isUnifiedMemoryStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_hostUnifiedMemory", device.hostUnifiedMemory()); + + DUMP_MESSAGE_STDOUT(" Device extensions:"); + String extensionsStr = device.extensions(); + size_t pos = 0; + while (pos < extensionsStr.size()) + { + size_t pos2 = extensionsStr.find(' ', pos); + if (pos2 == String::npos) + pos2 = extensionsStr.size(); + if (pos2 > pos) + { + String extensionName = extensionsStr.substr(pos, pos2 - pos); + DUMP_MESSAGE_STDOUT(" " << extensionName); + } + pos = pos2 + 1; + } + DUMP_CONFIG_PROPERTY("cv_ocl_current_extensions", extensionsStr.c_str()); + + const char* haveAmdBlasStr = haveAmdBlas() ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Has AMD Blas = " << haveAmdBlasStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_AmdBlas", haveAmdBlas()); + + const char* haveAmdFftStr = haveAmdFft() ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Has AMD Fft = " << haveAmdFftStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_AmdFft", haveAmdFft()); + + + DUMP_MESSAGE_STDOUT(" Preferred vector width char = " << device.preferredVectorWidthChar()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthChar", device.preferredVectorWidthChar()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width short = " << device.preferredVectorWidthShort()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthShort", device.preferredVectorWidthShort()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width int = " << device.preferredVectorWidthInt()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthInt", device.preferredVectorWidthInt()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width long = " << device.preferredVectorWidthLong()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthLong", device.preferredVectorWidthLong()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width float = " << device.preferredVectorWidthFloat()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthFloat", device.preferredVectorWidthFloat()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width double = " << device.preferredVectorWidthDouble()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthDouble", device.preferredVectorWidthDouble()); + } + catch (...) + { + DUMP_MESSAGE_STDOUT("Exception. Can't dump OpenCL info"); + DUMP_MESSAGE_STDOUT("OpenCL device not available"); + DUMP_CONFIG_PROPERTY("cv_ocl", "not available"); + } +} +#undef DUMP_MESSAGE_STDOUT +#undef DUMP_CONFIG_PROPERTY + +} // namespace diff --git a/include/opencv2/core/opencl/opencl_svm.hpp b/include/opencv2/core/opencl/opencl_svm.hpp new file mode 100644 index 0000000..7453082 --- /dev/null +++ b/include/opencv2/core/opencl/opencl_svm.hpp @@ -0,0 +1,81 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OPENCL_SVM_HPP +#define OPENCV_CORE_OPENCL_SVM_HPP + +// +// Internal usage only (binary compatibility is not guaranteed) +// +#ifndef __OPENCV_BUILD +#error Internal header file +#endif + +#if defined(HAVE_OPENCL) && defined(HAVE_OPENCL_SVM) +#include "runtime/opencl_core.hpp" +#include "runtime/opencl_svm_20.hpp" +#include "runtime/opencl_svm_hsa_extension.hpp" + +namespace cv { namespace ocl { namespace svm { + +struct SVMCapabilities +{ + enum Value + { + SVM_COARSE_GRAIN_BUFFER = (1 << 0), + SVM_FINE_GRAIN_BUFFER = (1 << 1), + SVM_FINE_GRAIN_SYSTEM = (1 << 2), + SVM_ATOMICS = (1 << 3), + }; + int value_; + + SVMCapabilities(int capabilities = 0) : value_(capabilities) { } + operator int() const { return value_; } + + inline bool isNoSVMSupport() const { return value_ == 0; } + inline bool isSupportCoarseGrainBuffer() const { return (value_ & SVM_COARSE_GRAIN_BUFFER) != 0; } + inline bool isSupportFineGrainBuffer() const { return (value_ & SVM_FINE_GRAIN_BUFFER) != 0; } + inline bool isSupportFineGrainSystem() const { return (value_ & SVM_FINE_GRAIN_SYSTEM) != 0; } + inline bool isSupportAtomics() const { return (value_ & SVM_ATOMICS) != 0; } +}; + +CV_EXPORTS const SVMCapabilities getSVMCapabilitites(const ocl::Context& context); + +struct SVMFunctions +{ + clSVMAllocAMD_fn fn_clSVMAlloc; + clSVMFreeAMD_fn fn_clSVMFree; + clSetKernelArgSVMPointerAMD_fn fn_clSetKernelArgSVMPointer; + //clSetKernelExecInfoAMD_fn fn_clSetKernelExecInfo; + //clEnqueueSVMFreeAMD_fn fn_clEnqueueSVMFree; + clEnqueueSVMMemcpyAMD_fn fn_clEnqueueSVMMemcpy; + clEnqueueSVMMemFillAMD_fn fn_clEnqueueSVMMemFill; + clEnqueueSVMMapAMD_fn fn_clEnqueueSVMMap; + clEnqueueSVMUnmapAMD_fn fn_clEnqueueSVMUnmap; + + inline SVMFunctions() + : fn_clSVMAlloc(NULL), fn_clSVMFree(NULL), + fn_clSetKernelArgSVMPointer(NULL), /*fn_clSetKernelExecInfo(NULL),*/ + /*fn_clEnqueueSVMFree(NULL),*/ fn_clEnqueueSVMMemcpy(NULL), fn_clEnqueueSVMMemFill(NULL), + fn_clEnqueueSVMMap(NULL), fn_clEnqueueSVMUnmap(NULL) + { + // nothing + } + + inline bool isValid() const + { + return fn_clSVMAlloc != NULL && fn_clSVMFree && fn_clSetKernelArgSVMPointer && + /*fn_clSetKernelExecInfo && fn_clEnqueueSVMFree &&*/ fn_clEnqueueSVMMemcpy && + fn_clEnqueueSVMMemFill && fn_clEnqueueSVMMap && fn_clEnqueueSVMUnmap; + } +}; + +// We should guarantee that SVMFunctions lifetime is not less than context's lifetime +CV_EXPORTS const SVMFunctions* getSVMFunctions(const ocl::Context& context); + +CV_EXPORTS bool useSVM(UMatUsageFlags usageFlags); + +}}} //namespace cv::ocl::svm +#endif + +#endif // OPENCV_CORE_OPENCL_SVM_HPP +/* End of file. */ diff --git a/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdblas.hpp b/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdblas.hpp new file mode 100644 index 0000000..65c8493 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdblas.hpp @@ -0,0 +1,714 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP +#error "Invalid usage" +#endif + +// generated by parser_clamdblas.py +#define clAmdBlasAddScratchImage clAmdBlasAddScratchImage_ +#define clAmdBlasCaxpy clAmdBlasCaxpy_ +#define clAmdBlasCcopy clAmdBlasCcopy_ +#define clAmdBlasCdotc clAmdBlasCdotc_ +#define clAmdBlasCdotu clAmdBlasCdotu_ +#define clAmdBlasCgbmv clAmdBlasCgbmv_ +#define clAmdBlasCgemm clAmdBlasCgemm_ +#define clAmdBlasCgemmEx clAmdBlasCgemmEx_ +#define clAmdBlasCgemv clAmdBlasCgemv_ +#define clAmdBlasCgemvEx clAmdBlasCgemvEx_ +#define clAmdBlasCgerc clAmdBlasCgerc_ +#define clAmdBlasCgeru clAmdBlasCgeru_ +#define clAmdBlasChbmv clAmdBlasChbmv_ +#define clAmdBlasChemm clAmdBlasChemm_ +#define clAmdBlasChemv clAmdBlasChemv_ +#define clAmdBlasCher clAmdBlasCher_ +#define clAmdBlasCher2 clAmdBlasCher2_ +#define clAmdBlasCher2k clAmdBlasCher2k_ +#define clAmdBlasCherk clAmdBlasCherk_ +#define clAmdBlasChpmv clAmdBlasChpmv_ +#define clAmdBlasChpr clAmdBlasChpr_ +#define clAmdBlasChpr2 clAmdBlasChpr2_ +#define clAmdBlasCrotg clAmdBlasCrotg_ +#define clAmdBlasCscal clAmdBlasCscal_ +#define clAmdBlasCsrot clAmdBlasCsrot_ +#define clAmdBlasCsscal clAmdBlasCsscal_ +#define clAmdBlasCswap clAmdBlasCswap_ +#define clAmdBlasCsymm clAmdBlasCsymm_ +#define clAmdBlasCsyr2k clAmdBlasCsyr2k_ +#define clAmdBlasCsyr2kEx clAmdBlasCsyr2kEx_ +#define clAmdBlasCsyrk clAmdBlasCsyrk_ +#define clAmdBlasCsyrkEx clAmdBlasCsyrkEx_ +#define clAmdBlasCtbmv clAmdBlasCtbmv_ +#define clAmdBlasCtbsv clAmdBlasCtbsv_ +#define clAmdBlasCtpmv clAmdBlasCtpmv_ +#define clAmdBlasCtpsv clAmdBlasCtpsv_ +#define clAmdBlasCtrmm clAmdBlasCtrmm_ +#define clAmdBlasCtrmmEx clAmdBlasCtrmmEx_ +#define clAmdBlasCtrmv clAmdBlasCtrmv_ +#define clAmdBlasCtrsm clAmdBlasCtrsm_ +#define clAmdBlasCtrsmEx clAmdBlasCtrsmEx_ +#define clAmdBlasCtrsv clAmdBlasCtrsv_ +#define clAmdBlasDasum clAmdBlasDasum_ +#define clAmdBlasDaxpy clAmdBlasDaxpy_ +#define clAmdBlasDcopy clAmdBlasDcopy_ +#define clAmdBlasDdot clAmdBlasDdot_ +#define clAmdBlasDgbmv clAmdBlasDgbmv_ +#define clAmdBlasDgemm clAmdBlasDgemm_ +#define clAmdBlasDgemmEx clAmdBlasDgemmEx_ +#define clAmdBlasDgemv clAmdBlasDgemv_ +#define clAmdBlasDgemvEx clAmdBlasDgemvEx_ +#define clAmdBlasDger clAmdBlasDger_ +#define clAmdBlasDnrm2 clAmdBlasDnrm2_ +#define clAmdBlasDrot clAmdBlasDrot_ +#define clAmdBlasDrotg clAmdBlasDrotg_ +#define clAmdBlasDrotm clAmdBlasDrotm_ +#define clAmdBlasDrotmg clAmdBlasDrotmg_ +#define clAmdBlasDsbmv clAmdBlasDsbmv_ +#define clAmdBlasDscal clAmdBlasDscal_ +#define clAmdBlasDspmv clAmdBlasDspmv_ +#define clAmdBlasDspr clAmdBlasDspr_ +#define clAmdBlasDspr2 clAmdBlasDspr2_ +#define clAmdBlasDswap clAmdBlasDswap_ +#define clAmdBlasDsymm clAmdBlasDsymm_ +#define clAmdBlasDsymv clAmdBlasDsymv_ +#define clAmdBlasDsymvEx clAmdBlasDsymvEx_ +#define clAmdBlasDsyr clAmdBlasDsyr_ +#define clAmdBlasDsyr2 clAmdBlasDsyr2_ +#define clAmdBlasDsyr2k clAmdBlasDsyr2k_ +#define clAmdBlasDsyr2kEx clAmdBlasDsyr2kEx_ +#define clAmdBlasDsyrk clAmdBlasDsyrk_ +#define clAmdBlasDsyrkEx clAmdBlasDsyrkEx_ +#define clAmdBlasDtbmv clAmdBlasDtbmv_ +#define clAmdBlasDtbsv clAmdBlasDtbsv_ +#define clAmdBlasDtpmv clAmdBlasDtpmv_ +#define clAmdBlasDtpsv clAmdBlasDtpsv_ +#define clAmdBlasDtrmm clAmdBlasDtrmm_ +#define clAmdBlasDtrmmEx clAmdBlasDtrmmEx_ +#define clAmdBlasDtrmv clAmdBlasDtrmv_ +#define clAmdBlasDtrsm clAmdBlasDtrsm_ +#define clAmdBlasDtrsmEx clAmdBlasDtrsmEx_ +#define clAmdBlasDtrsv clAmdBlasDtrsv_ +#define clAmdBlasDzasum clAmdBlasDzasum_ +#define clAmdBlasDznrm2 clAmdBlasDznrm2_ +#define clAmdBlasGetVersion clAmdBlasGetVersion_ +#define clAmdBlasRemoveScratchImage clAmdBlasRemoveScratchImage_ +#define clAmdBlasSasum clAmdBlasSasum_ +#define clAmdBlasSaxpy clAmdBlasSaxpy_ +#define clAmdBlasScasum clAmdBlasScasum_ +#define clAmdBlasScnrm2 clAmdBlasScnrm2_ +#define clAmdBlasScopy clAmdBlasScopy_ +#define clAmdBlasSdot clAmdBlasSdot_ +#define clAmdBlasSetup clAmdBlasSetup_ +#define clAmdBlasSgbmv clAmdBlasSgbmv_ +#define clAmdBlasSgemm clAmdBlasSgemm_ +#define clAmdBlasSgemmEx clAmdBlasSgemmEx_ +#define clAmdBlasSgemv clAmdBlasSgemv_ +#define clAmdBlasSgemvEx clAmdBlasSgemvEx_ +#define clAmdBlasSger clAmdBlasSger_ +#define clAmdBlasSnrm2 clAmdBlasSnrm2_ +#define clAmdBlasSrot clAmdBlasSrot_ +#define clAmdBlasSrotg clAmdBlasSrotg_ +#define clAmdBlasSrotm clAmdBlasSrotm_ +#define clAmdBlasSrotmg clAmdBlasSrotmg_ +#define clAmdBlasSsbmv clAmdBlasSsbmv_ +#define clAmdBlasSscal clAmdBlasSscal_ +#define clAmdBlasSspmv clAmdBlasSspmv_ +#define clAmdBlasSspr clAmdBlasSspr_ +#define clAmdBlasSspr2 clAmdBlasSspr2_ +#define clAmdBlasSswap clAmdBlasSswap_ +#define clAmdBlasSsymm clAmdBlasSsymm_ +#define clAmdBlasSsymv clAmdBlasSsymv_ +#define clAmdBlasSsymvEx clAmdBlasSsymvEx_ +#define clAmdBlasSsyr clAmdBlasSsyr_ +#define clAmdBlasSsyr2 clAmdBlasSsyr2_ +#define clAmdBlasSsyr2k clAmdBlasSsyr2k_ +#define clAmdBlasSsyr2kEx clAmdBlasSsyr2kEx_ +#define clAmdBlasSsyrk clAmdBlasSsyrk_ +#define clAmdBlasSsyrkEx clAmdBlasSsyrkEx_ +#define clAmdBlasStbmv clAmdBlasStbmv_ +#define clAmdBlasStbsv clAmdBlasStbsv_ +#define clAmdBlasStpmv clAmdBlasStpmv_ +#define clAmdBlasStpsv clAmdBlasStpsv_ +#define clAmdBlasStrmm clAmdBlasStrmm_ +#define clAmdBlasStrmmEx clAmdBlasStrmmEx_ +#define clAmdBlasStrmv clAmdBlasStrmv_ +#define clAmdBlasStrsm clAmdBlasStrsm_ +#define clAmdBlasStrsmEx clAmdBlasStrsmEx_ +#define clAmdBlasStrsv clAmdBlasStrsv_ +#define clAmdBlasTeardown clAmdBlasTeardown_ +#define clAmdBlasZaxpy clAmdBlasZaxpy_ +#define clAmdBlasZcopy clAmdBlasZcopy_ +#define clAmdBlasZdotc clAmdBlasZdotc_ +#define clAmdBlasZdotu clAmdBlasZdotu_ +#define clAmdBlasZdrot clAmdBlasZdrot_ +#define clAmdBlasZdscal clAmdBlasZdscal_ +#define clAmdBlasZgbmv clAmdBlasZgbmv_ +#define clAmdBlasZgemm clAmdBlasZgemm_ +#define clAmdBlasZgemmEx clAmdBlasZgemmEx_ +#define clAmdBlasZgemv clAmdBlasZgemv_ +#define clAmdBlasZgemvEx clAmdBlasZgemvEx_ +#define clAmdBlasZgerc clAmdBlasZgerc_ +#define clAmdBlasZgeru clAmdBlasZgeru_ +#define clAmdBlasZhbmv clAmdBlasZhbmv_ +#define clAmdBlasZhemm clAmdBlasZhemm_ +#define clAmdBlasZhemv clAmdBlasZhemv_ +#define clAmdBlasZher clAmdBlasZher_ +#define clAmdBlasZher2 clAmdBlasZher2_ +#define clAmdBlasZher2k clAmdBlasZher2k_ +#define clAmdBlasZherk clAmdBlasZherk_ +#define clAmdBlasZhpmv clAmdBlasZhpmv_ +#define clAmdBlasZhpr clAmdBlasZhpr_ +#define clAmdBlasZhpr2 clAmdBlasZhpr2_ +#define clAmdBlasZrotg clAmdBlasZrotg_ +#define clAmdBlasZscal clAmdBlasZscal_ +#define clAmdBlasZswap clAmdBlasZswap_ +#define clAmdBlasZsymm clAmdBlasZsymm_ +#define clAmdBlasZsyr2k clAmdBlasZsyr2k_ +#define clAmdBlasZsyr2kEx clAmdBlasZsyr2kEx_ +#define clAmdBlasZsyrk clAmdBlasZsyrk_ +#define clAmdBlasZsyrkEx clAmdBlasZsyrkEx_ +#define clAmdBlasZtbmv clAmdBlasZtbmv_ +#define clAmdBlasZtbsv clAmdBlasZtbsv_ +#define clAmdBlasZtpmv clAmdBlasZtpmv_ +#define clAmdBlasZtpsv clAmdBlasZtpsv_ +#define clAmdBlasZtrmm clAmdBlasZtrmm_ +#define clAmdBlasZtrmmEx clAmdBlasZtrmmEx_ +#define clAmdBlasZtrmv clAmdBlasZtrmv_ +#define clAmdBlasZtrsm clAmdBlasZtrsm_ +#define clAmdBlasZtrsmEx clAmdBlasZtrsmEx_ +#define clAmdBlasZtrsv clAmdBlasZtrsv_ +#define clAmdBlasiCamax clAmdBlasiCamax_ +#define clAmdBlasiDamax clAmdBlasiDamax_ +#define clAmdBlasiSamax clAmdBlasiSamax_ +#define clAmdBlasiZamax clAmdBlasiZamax_ + +#include + +// generated by parser_clamdblas.py +#undef clAmdBlasAddScratchImage +//#define clAmdBlasAddScratchImage clAmdBlasAddScratchImage_pfn +#undef clAmdBlasCaxpy +//#define clAmdBlasCaxpy clAmdBlasCaxpy_pfn +#undef clAmdBlasCcopy +//#define clAmdBlasCcopy clAmdBlasCcopy_pfn +#undef clAmdBlasCdotc +//#define clAmdBlasCdotc clAmdBlasCdotc_pfn +#undef clAmdBlasCdotu +//#define clAmdBlasCdotu clAmdBlasCdotu_pfn +#undef clAmdBlasCgbmv +//#define clAmdBlasCgbmv clAmdBlasCgbmv_pfn +#undef clAmdBlasCgemm +//#define clAmdBlasCgemm clAmdBlasCgemm_pfn +#undef clAmdBlasCgemmEx +#define clAmdBlasCgemmEx clAmdBlasCgemmEx_pfn +#undef clAmdBlasCgemv +//#define clAmdBlasCgemv clAmdBlasCgemv_pfn +#undef clAmdBlasCgemvEx +//#define clAmdBlasCgemvEx clAmdBlasCgemvEx_pfn +#undef clAmdBlasCgerc +//#define clAmdBlasCgerc clAmdBlasCgerc_pfn +#undef clAmdBlasCgeru +//#define clAmdBlasCgeru clAmdBlasCgeru_pfn +#undef clAmdBlasChbmv +//#define clAmdBlasChbmv clAmdBlasChbmv_pfn +#undef clAmdBlasChemm +//#define clAmdBlasChemm clAmdBlasChemm_pfn +#undef clAmdBlasChemv +//#define clAmdBlasChemv clAmdBlasChemv_pfn +#undef clAmdBlasCher +//#define clAmdBlasCher clAmdBlasCher_pfn +#undef clAmdBlasCher2 +//#define clAmdBlasCher2 clAmdBlasCher2_pfn +#undef clAmdBlasCher2k +//#define clAmdBlasCher2k clAmdBlasCher2k_pfn +#undef clAmdBlasCherk +//#define clAmdBlasCherk clAmdBlasCherk_pfn +#undef clAmdBlasChpmv +//#define clAmdBlasChpmv clAmdBlasChpmv_pfn +#undef clAmdBlasChpr +//#define clAmdBlasChpr clAmdBlasChpr_pfn +#undef clAmdBlasChpr2 +//#define clAmdBlasChpr2 clAmdBlasChpr2_pfn +#undef clAmdBlasCrotg +//#define clAmdBlasCrotg clAmdBlasCrotg_pfn +#undef clAmdBlasCscal +//#define clAmdBlasCscal clAmdBlasCscal_pfn +#undef clAmdBlasCsrot +//#define clAmdBlasCsrot clAmdBlasCsrot_pfn +#undef clAmdBlasCsscal +//#define clAmdBlasCsscal clAmdBlasCsscal_pfn +#undef clAmdBlasCswap +//#define clAmdBlasCswap clAmdBlasCswap_pfn +#undef clAmdBlasCsymm +//#define clAmdBlasCsymm clAmdBlasCsymm_pfn +#undef clAmdBlasCsyr2k +//#define clAmdBlasCsyr2k clAmdBlasCsyr2k_pfn +#undef clAmdBlasCsyr2kEx +//#define clAmdBlasCsyr2kEx clAmdBlasCsyr2kEx_pfn +#undef clAmdBlasCsyrk +//#define clAmdBlasCsyrk clAmdBlasCsyrk_pfn +#undef clAmdBlasCsyrkEx +//#define clAmdBlasCsyrkEx clAmdBlasCsyrkEx_pfn +#undef clAmdBlasCtbmv +//#define clAmdBlasCtbmv clAmdBlasCtbmv_pfn +#undef clAmdBlasCtbsv +//#define clAmdBlasCtbsv clAmdBlasCtbsv_pfn +#undef clAmdBlasCtpmv +//#define clAmdBlasCtpmv clAmdBlasCtpmv_pfn +#undef clAmdBlasCtpsv +//#define clAmdBlasCtpsv clAmdBlasCtpsv_pfn +#undef clAmdBlasCtrmm +//#define clAmdBlasCtrmm clAmdBlasCtrmm_pfn +#undef clAmdBlasCtrmmEx +//#define clAmdBlasCtrmmEx clAmdBlasCtrmmEx_pfn +#undef clAmdBlasCtrmv +//#define clAmdBlasCtrmv clAmdBlasCtrmv_pfn +#undef clAmdBlasCtrsm +//#define clAmdBlasCtrsm clAmdBlasCtrsm_pfn +#undef clAmdBlasCtrsmEx +//#define clAmdBlasCtrsmEx clAmdBlasCtrsmEx_pfn +#undef clAmdBlasCtrsv +//#define clAmdBlasCtrsv clAmdBlasCtrsv_pfn +#undef clAmdBlasDasum +//#define clAmdBlasDasum clAmdBlasDasum_pfn +#undef clAmdBlasDaxpy +//#define clAmdBlasDaxpy clAmdBlasDaxpy_pfn +#undef clAmdBlasDcopy +//#define clAmdBlasDcopy clAmdBlasDcopy_pfn +#undef clAmdBlasDdot +//#define clAmdBlasDdot clAmdBlasDdot_pfn +#undef clAmdBlasDgbmv +//#define clAmdBlasDgbmv clAmdBlasDgbmv_pfn +#undef clAmdBlasDgemm +//#define clAmdBlasDgemm clAmdBlasDgemm_pfn +#undef clAmdBlasDgemmEx +#define clAmdBlasDgemmEx clAmdBlasDgemmEx_pfn +#undef clAmdBlasDgemv +//#define clAmdBlasDgemv clAmdBlasDgemv_pfn +#undef clAmdBlasDgemvEx +//#define clAmdBlasDgemvEx clAmdBlasDgemvEx_pfn +#undef clAmdBlasDger +//#define clAmdBlasDger clAmdBlasDger_pfn +#undef clAmdBlasDnrm2 +//#define clAmdBlasDnrm2 clAmdBlasDnrm2_pfn +#undef clAmdBlasDrot +//#define clAmdBlasDrot clAmdBlasDrot_pfn +#undef clAmdBlasDrotg +//#define clAmdBlasDrotg clAmdBlasDrotg_pfn +#undef clAmdBlasDrotm +//#define clAmdBlasDrotm clAmdBlasDrotm_pfn +#undef clAmdBlasDrotmg +//#define clAmdBlasDrotmg clAmdBlasDrotmg_pfn +#undef clAmdBlasDsbmv +//#define clAmdBlasDsbmv clAmdBlasDsbmv_pfn +#undef clAmdBlasDscal +//#define clAmdBlasDscal clAmdBlasDscal_pfn +#undef clAmdBlasDspmv +//#define clAmdBlasDspmv clAmdBlasDspmv_pfn +#undef clAmdBlasDspr +//#define clAmdBlasDspr clAmdBlasDspr_pfn +#undef clAmdBlasDspr2 +//#define clAmdBlasDspr2 clAmdBlasDspr2_pfn +#undef clAmdBlasDswap +//#define clAmdBlasDswap clAmdBlasDswap_pfn +#undef clAmdBlasDsymm +//#define clAmdBlasDsymm clAmdBlasDsymm_pfn +#undef clAmdBlasDsymv +//#define clAmdBlasDsymv clAmdBlasDsymv_pfn +#undef clAmdBlasDsymvEx +//#define clAmdBlasDsymvEx clAmdBlasDsymvEx_pfn +#undef clAmdBlasDsyr +//#define clAmdBlasDsyr clAmdBlasDsyr_pfn +#undef clAmdBlasDsyr2 +//#define clAmdBlasDsyr2 clAmdBlasDsyr2_pfn +#undef clAmdBlasDsyr2k +//#define clAmdBlasDsyr2k clAmdBlasDsyr2k_pfn +#undef clAmdBlasDsyr2kEx +//#define clAmdBlasDsyr2kEx clAmdBlasDsyr2kEx_pfn +#undef clAmdBlasDsyrk +//#define clAmdBlasDsyrk clAmdBlasDsyrk_pfn +#undef clAmdBlasDsyrkEx +//#define clAmdBlasDsyrkEx clAmdBlasDsyrkEx_pfn +#undef clAmdBlasDtbmv +//#define clAmdBlasDtbmv clAmdBlasDtbmv_pfn +#undef clAmdBlasDtbsv +//#define clAmdBlasDtbsv clAmdBlasDtbsv_pfn +#undef clAmdBlasDtpmv +//#define clAmdBlasDtpmv clAmdBlasDtpmv_pfn +#undef clAmdBlasDtpsv +//#define clAmdBlasDtpsv clAmdBlasDtpsv_pfn +#undef clAmdBlasDtrmm +//#define clAmdBlasDtrmm clAmdBlasDtrmm_pfn +#undef clAmdBlasDtrmmEx +//#define clAmdBlasDtrmmEx clAmdBlasDtrmmEx_pfn +#undef clAmdBlasDtrmv +//#define clAmdBlasDtrmv clAmdBlasDtrmv_pfn +#undef clAmdBlasDtrsm +//#define clAmdBlasDtrsm clAmdBlasDtrsm_pfn +#undef clAmdBlasDtrsmEx +//#define clAmdBlasDtrsmEx clAmdBlasDtrsmEx_pfn +#undef clAmdBlasDtrsv +//#define clAmdBlasDtrsv clAmdBlasDtrsv_pfn +#undef clAmdBlasDzasum +//#define clAmdBlasDzasum clAmdBlasDzasum_pfn +#undef clAmdBlasDznrm2 +//#define clAmdBlasDznrm2 clAmdBlasDznrm2_pfn +#undef clAmdBlasGetVersion +//#define clAmdBlasGetVersion clAmdBlasGetVersion_pfn +#undef clAmdBlasRemoveScratchImage +//#define clAmdBlasRemoveScratchImage clAmdBlasRemoveScratchImage_pfn +#undef clAmdBlasSasum +//#define clAmdBlasSasum clAmdBlasSasum_pfn +#undef clAmdBlasSaxpy +//#define clAmdBlasSaxpy clAmdBlasSaxpy_pfn +#undef clAmdBlasScasum +//#define clAmdBlasScasum clAmdBlasScasum_pfn +#undef clAmdBlasScnrm2 +//#define clAmdBlasScnrm2 clAmdBlasScnrm2_pfn +#undef clAmdBlasScopy +//#define clAmdBlasScopy clAmdBlasScopy_pfn +#undef clAmdBlasSdot +//#define clAmdBlasSdot clAmdBlasSdot_pfn +#undef clAmdBlasSetup +#define clAmdBlasSetup clAmdBlasSetup_pfn +#undef clAmdBlasSgbmv +//#define clAmdBlasSgbmv clAmdBlasSgbmv_pfn +#undef clAmdBlasSgemm +//#define clAmdBlasSgemm clAmdBlasSgemm_pfn +#undef clAmdBlasSgemmEx +#define clAmdBlasSgemmEx clAmdBlasSgemmEx_pfn +#undef clAmdBlasSgemv +//#define clAmdBlasSgemv clAmdBlasSgemv_pfn +#undef clAmdBlasSgemvEx +//#define clAmdBlasSgemvEx clAmdBlasSgemvEx_pfn +#undef clAmdBlasSger +//#define clAmdBlasSger clAmdBlasSger_pfn +#undef clAmdBlasSnrm2 +//#define clAmdBlasSnrm2 clAmdBlasSnrm2_pfn +#undef clAmdBlasSrot +//#define clAmdBlasSrot clAmdBlasSrot_pfn +#undef clAmdBlasSrotg +//#define clAmdBlasSrotg clAmdBlasSrotg_pfn +#undef clAmdBlasSrotm +//#define clAmdBlasSrotm clAmdBlasSrotm_pfn +#undef clAmdBlasSrotmg +//#define clAmdBlasSrotmg clAmdBlasSrotmg_pfn +#undef clAmdBlasSsbmv +//#define clAmdBlasSsbmv clAmdBlasSsbmv_pfn +#undef clAmdBlasSscal +//#define clAmdBlasSscal clAmdBlasSscal_pfn +#undef clAmdBlasSspmv +//#define clAmdBlasSspmv clAmdBlasSspmv_pfn +#undef clAmdBlasSspr +//#define clAmdBlasSspr clAmdBlasSspr_pfn +#undef clAmdBlasSspr2 +//#define clAmdBlasSspr2 clAmdBlasSspr2_pfn +#undef clAmdBlasSswap +//#define clAmdBlasSswap clAmdBlasSswap_pfn +#undef clAmdBlasSsymm +//#define clAmdBlasSsymm clAmdBlasSsymm_pfn +#undef clAmdBlasSsymv +//#define clAmdBlasSsymv clAmdBlasSsymv_pfn +#undef clAmdBlasSsymvEx +//#define clAmdBlasSsymvEx clAmdBlasSsymvEx_pfn +#undef clAmdBlasSsyr +//#define clAmdBlasSsyr clAmdBlasSsyr_pfn +#undef clAmdBlasSsyr2 +//#define clAmdBlasSsyr2 clAmdBlasSsyr2_pfn +#undef clAmdBlasSsyr2k +//#define clAmdBlasSsyr2k clAmdBlasSsyr2k_pfn +#undef clAmdBlasSsyr2kEx +//#define clAmdBlasSsyr2kEx clAmdBlasSsyr2kEx_pfn +#undef clAmdBlasSsyrk +//#define clAmdBlasSsyrk clAmdBlasSsyrk_pfn +#undef clAmdBlasSsyrkEx +//#define clAmdBlasSsyrkEx clAmdBlasSsyrkEx_pfn +#undef clAmdBlasStbmv +//#define clAmdBlasStbmv clAmdBlasStbmv_pfn +#undef clAmdBlasStbsv +//#define clAmdBlasStbsv clAmdBlasStbsv_pfn +#undef clAmdBlasStpmv +//#define clAmdBlasStpmv clAmdBlasStpmv_pfn +#undef clAmdBlasStpsv +//#define clAmdBlasStpsv clAmdBlasStpsv_pfn +#undef clAmdBlasStrmm +//#define clAmdBlasStrmm clAmdBlasStrmm_pfn +#undef clAmdBlasStrmmEx +//#define clAmdBlasStrmmEx clAmdBlasStrmmEx_pfn +#undef clAmdBlasStrmv +//#define clAmdBlasStrmv clAmdBlasStrmv_pfn +#undef clAmdBlasStrsm +//#define clAmdBlasStrsm clAmdBlasStrsm_pfn +#undef clAmdBlasStrsmEx +//#define clAmdBlasStrsmEx clAmdBlasStrsmEx_pfn +#undef clAmdBlasStrsv +//#define clAmdBlasStrsv clAmdBlasStrsv_pfn +#undef clAmdBlasTeardown +#define clAmdBlasTeardown clAmdBlasTeardown_pfn +#undef clAmdBlasZaxpy +//#define clAmdBlasZaxpy clAmdBlasZaxpy_pfn +#undef clAmdBlasZcopy +//#define clAmdBlasZcopy clAmdBlasZcopy_pfn +#undef clAmdBlasZdotc +//#define clAmdBlasZdotc clAmdBlasZdotc_pfn +#undef clAmdBlasZdotu +//#define clAmdBlasZdotu clAmdBlasZdotu_pfn +#undef clAmdBlasZdrot +//#define clAmdBlasZdrot clAmdBlasZdrot_pfn +#undef clAmdBlasZdscal +//#define clAmdBlasZdscal clAmdBlasZdscal_pfn +#undef clAmdBlasZgbmv +//#define clAmdBlasZgbmv clAmdBlasZgbmv_pfn +#undef clAmdBlasZgemm +//#define clAmdBlasZgemm clAmdBlasZgemm_pfn +#undef clAmdBlasZgemmEx +#define clAmdBlasZgemmEx clAmdBlasZgemmEx_pfn +#undef clAmdBlasZgemv +//#define clAmdBlasZgemv clAmdBlasZgemv_pfn +#undef clAmdBlasZgemvEx +//#define clAmdBlasZgemvEx clAmdBlasZgemvEx_pfn +#undef clAmdBlasZgerc +//#define clAmdBlasZgerc clAmdBlasZgerc_pfn +#undef clAmdBlasZgeru +//#define clAmdBlasZgeru clAmdBlasZgeru_pfn +#undef clAmdBlasZhbmv +//#define clAmdBlasZhbmv clAmdBlasZhbmv_pfn +#undef clAmdBlasZhemm +//#define clAmdBlasZhemm clAmdBlasZhemm_pfn +#undef clAmdBlasZhemv +//#define clAmdBlasZhemv clAmdBlasZhemv_pfn +#undef clAmdBlasZher +//#define clAmdBlasZher clAmdBlasZher_pfn +#undef clAmdBlasZher2 +//#define clAmdBlasZher2 clAmdBlasZher2_pfn +#undef clAmdBlasZher2k +//#define clAmdBlasZher2k clAmdBlasZher2k_pfn +#undef clAmdBlasZherk +//#define clAmdBlasZherk clAmdBlasZherk_pfn +#undef clAmdBlasZhpmv +//#define clAmdBlasZhpmv clAmdBlasZhpmv_pfn +#undef clAmdBlasZhpr +//#define clAmdBlasZhpr clAmdBlasZhpr_pfn +#undef clAmdBlasZhpr2 +//#define clAmdBlasZhpr2 clAmdBlasZhpr2_pfn +#undef clAmdBlasZrotg +//#define clAmdBlasZrotg clAmdBlasZrotg_pfn +#undef clAmdBlasZscal +//#define clAmdBlasZscal clAmdBlasZscal_pfn +#undef clAmdBlasZswap +//#define clAmdBlasZswap clAmdBlasZswap_pfn +#undef clAmdBlasZsymm +//#define clAmdBlasZsymm clAmdBlasZsymm_pfn +#undef clAmdBlasZsyr2k +//#define clAmdBlasZsyr2k clAmdBlasZsyr2k_pfn +#undef clAmdBlasZsyr2kEx +//#define clAmdBlasZsyr2kEx clAmdBlasZsyr2kEx_pfn +#undef clAmdBlasZsyrk +//#define clAmdBlasZsyrk clAmdBlasZsyrk_pfn +#undef clAmdBlasZsyrkEx +//#define clAmdBlasZsyrkEx clAmdBlasZsyrkEx_pfn +#undef clAmdBlasZtbmv +//#define clAmdBlasZtbmv clAmdBlasZtbmv_pfn +#undef clAmdBlasZtbsv +//#define clAmdBlasZtbsv clAmdBlasZtbsv_pfn +#undef clAmdBlasZtpmv +//#define clAmdBlasZtpmv clAmdBlasZtpmv_pfn +#undef clAmdBlasZtpsv +//#define clAmdBlasZtpsv clAmdBlasZtpsv_pfn +#undef clAmdBlasZtrmm +//#define clAmdBlasZtrmm clAmdBlasZtrmm_pfn +#undef clAmdBlasZtrmmEx +//#define clAmdBlasZtrmmEx clAmdBlasZtrmmEx_pfn +#undef clAmdBlasZtrmv +//#define clAmdBlasZtrmv clAmdBlasZtrmv_pfn +#undef clAmdBlasZtrsm +//#define clAmdBlasZtrsm clAmdBlasZtrsm_pfn +#undef clAmdBlasZtrsmEx +//#define clAmdBlasZtrsmEx clAmdBlasZtrsmEx_pfn +#undef clAmdBlasZtrsv +//#define clAmdBlasZtrsv clAmdBlasZtrsv_pfn +#undef clAmdBlasiCamax +//#define clAmdBlasiCamax clAmdBlasiCamax_pfn +#undef clAmdBlasiDamax +//#define clAmdBlasiDamax clAmdBlasiDamax_pfn +#undef clAmdBlasiSamax +//#define clAmdBlasiSamax clAmdBlasiSamax_pfn +#undef clAmdBlasiZamax +//#define clAmdBlasiZamax clAmdBlasiZamax_pfn + +// generated by parser_clamdblas.py +//extern CL_RUNTIME_EXPORT cl_ulong (*clAmdBlasAddScratchImage)(cl_context context, size_t width, size_t height, clAmdBlasStatus* status); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCaxpy)(size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCcopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCdotc)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCdotu)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCgbmv)(clAmdBlasOrder order, clAmdBlasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCgemm)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, FloatComplex beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCgemmEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, FloatComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCgemv)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t lda, const cl_mem x, size_t offx, int incx, FloatComplex beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCgemvEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, FloatComplex beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCgerc)(clAmdBlasOrder order, size_t M, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCgeru)(clAmdBlasOrder order, size_t M, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasChbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, size_t K, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasChemm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, size_t M, size_t N, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasChemv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, FloatComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, FloatComplex beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCher)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCher2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCher2k)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCherk)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, float alpha, const cl_mem A, size_t offa, size_t lda, float beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasChpmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float2 alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_float2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasChpr)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasChpr2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCrotg)(cl_mem CA, size_t offCA, cl_mem CB, size_t offCB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCscal)(size_t N, cl_float2 alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCsrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_float C, cl_float S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCsscal)(size_t N, cl_float alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCsymm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, size_t M, size_t N, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCsyr2k)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, FloatComplex beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCsyr2kEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, FloatComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCsyrk)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t lda, FloatComplex beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCsyrkEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, FloatComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtbsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtpmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtpsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtrmm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtrmmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtrmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtrsm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtrsmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasCtrsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDaxpy)(size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDcopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDdot)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDgbmv)(clAmdBlasOrder order, clAmdBlasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_double alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDgemm)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, cl_double beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDgemmEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_double beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDgemv)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t lda, const cl_mem x, size_t offx, int incx, cl_double beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDgemvEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_double beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDger)(clAmdBlasOrder order, size_t M, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDnrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_double C, cl_double S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDrotg)(cl_mem DA, size_t offDA, cl_mem DB, size_t offDB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDrotm)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, const cl_mem DPARAM, size_t offDparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDrotmg)(cl_mem DD1, size_t offDD1, cl_mem DD2, size_t offDD2, cl_mem DX1, size_t offDX1, const cl_mem DY1, size_t offDY1, cl_mem DPARAM, size_t offDparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDscal)(size_t N, cl_double alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDspmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_double beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDspr)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDspr2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsymm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsymv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem A, size_t lda, const cl_mem x, size_t offx, int incx, cl_double beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsymvEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_double beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsyr)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsyr2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsyr2k)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, cl_double beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsyr2kEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_double beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsyrk)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t lda, cl_double beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDsyrkEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offA, size_t lda, cl_double beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtbsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtpmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtpsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtrmm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtrmmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtrmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtrsm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtrsmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDtrsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDzasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasDznrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasGetVersion)(cl_uint* major, cl_uint* minor, cl_uint* patch); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasRemoveScratchImage)(cl_ulong imageID); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSaxpy)(size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasScasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasScnrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasScopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSdot)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSetup)(); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSgbmv)(clAmdBlasOrder order, clAmdBlasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_float alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSgemm)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, cl_float beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSgemmEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_float beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSgemv)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t lda, const cl_mem x, size_t offx, int incx, cl_float beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSgemvEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_float beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSger)(clAmdBlasOrder order, size_t M, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSnrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_float C, cl_float S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSrotg)(cl_mem SA, size_t offSA, cl_mem SB, size_t offSB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSrotm)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, const cl_mem SPARAM, size_t offSparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSrotmg)(cl_mem SD1, size_t offSD1, cl_mem SD2, size_t offSD2, cl_mem SX1, size_t offSX1, const cl_mem SY1, size_t offSY1, cl_mem SPARAM, size_t offSparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSscal)(size_t N, cl_float alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSspmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_float beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSspr)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSspr2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsymm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsymv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem A, size_t lda, const cl_mem x, size_t offx, int incx, cl_float beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsymvEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_float beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsyr)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsyr2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsyr2k)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, cl_float beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsyr2kEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_float beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsyrk)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t lda, cl_float beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasSsyrkEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offA, size_t lda, cl_float beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStbsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStpmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStpsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStrmm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStrmmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStrmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStrsm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStrsmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasStrsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT void (*clAmdBlasTeardown)(); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZaxpy)(size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZcopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZdotc)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZdotu)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZdrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_double C, cl_double S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZdscal)(size_t N, cl_double alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZgbmv)(clAmdBlasOrder order, clAmdBlasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZgemm)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, DoubleComplex beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZgemmEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, clAmdBlasTranspose transB, size_t M, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, DoubleComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZgemv)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t lda, const cl_mem x, size_t offx, int incx, DoubleComplex beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZgemvEx)(clAmdBlasOrder order, clAmdBlasTranspose transA, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, DoubleComplex beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZgerc)(clAmdBlasOrder order, size_t M, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZgeru)(clAmdBlasOrder order, size_t M, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZhbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, size_t K, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZhemm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, size_t M, size_t N, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZhemv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, DoubleComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, DoubleComplex beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZher)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZher2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZher2k)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZherk)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, double alpha, const cl_mem A, size_t offa, size_t lda, double beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZhpmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double2 alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_double2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZhpr)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZhpr2)(clAmdBlasOrder order, clAmdBlasUplo uplo, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZrotg)(cl_mem CA, size_t offCA, cl_mem CB, size_t offCB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZscal)(size_t N, cl_double2 alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZsymm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, size_t M, size_t N, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZsyr2k)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t lda, const cl_mem B, size_t ldb, DoubleComplex beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZsyr2kEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transAB, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, DoubleComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZsyrk)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t lda, DoubleComplex beta, cl_mem C, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZsyrkEx)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose transA, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, DoubleComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtbmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtbsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtpmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtpsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtrmm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtrmmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtrmv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtrsm)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t lda, cl_mem B, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtrsmEx)(clAmdBlasOrder order, clAmdBlasSide side, clAmdBlasUplo uplo, clAmdBlasTranspose transA, clAmdBlasDiag diag, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasZtrsv)(clAmdBlasOrder order, clAmdBlasUplo uplo, clAmdBlasTranspose trans, clAmdBlasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasiCamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasiDamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasiSamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clAmdBlasStatus (*clAmdBlasiZamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); diff --git a/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdfft.hpp b/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdfft.hpp new file mode 100644 index 0000000..1457d7e --- /dev/null +++ b/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdfft.hpp @@ -0,0 +1,142 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP +#error "Invalid usage" +#endif + +// generated by parser_clamdfft.py +#define clAmdFftBakePlan clAmdFftBakePlan_ +#define clAmdFftCopyPlan clAmdFftCopyPlan_ +#define clAmdFftCreateDefaultPlan clAmdFftCreateDefaultPlan_ +#define clAmdFftDestroyPlan clAmdFftDestroyPlan_ +#define clAmdFftEnqueueTransform clAmdFftEnqueueTransform_ +#define clAmdFftGetLayout clAmdFftGetLayout_ +#define clAmdFftGetPlanBatchSize clAmdFftGetPlanBatchSize_ +#define clAmdFftGetPlanContext clAmdFftGetPlanContext_ +#define clAmdFftGetPlanDim clAmdFftGetPlanDim_ +#define clAmdFftGetPlanDistance clAmdFftGetPlanDistance_ +#define clAmdFftGetPlanInStride clAmdFftGetPlanInStride_ +#define clAmdFftGetPlanLength clAmdFftGetPlanLength_ +#define clAmdFftGetPlanOutStride clAmdFftGetPlanOutStride_ +#define clAmdFftGetPlanPrecision clAmdFftGetPlanPrecision_ +#define clAmdFftGetPlanScale clAmdFftGetPlanScale_ +#define clAmdFftGetPlanTransposeResult clAmdFftGetPlanTransposeResult_ +#define clAmdFftGetResultLocation clAmdFftGetResultLocation_ +#define clAmdFftGetTmpBufSize clAmdFftGetTmpBufSize_ +#define clAmdFftGetVersion clAmdFftGetVersion_ +#define clAmdFftSetLayout clAmdFftSetLayout_ +#define clAmdFftSetPlanBatchSize clAmdFftSetPlanBatchSize_ +#define clAmdFftSetPlanDim clAmdFftSetPlanDim_ +#define clAmdFftSetPlanDistance clAmdFftSetPlanDistance_ +#define clAmdFftSetPlanInStride clAmdFftSetPlanInStride_ +#define clAmdFftSetPlanLength clAmdFftSetPlanLength_ +#define clAmdFftSetPlanOutStride clAmdFftSetPlanOutStride_ +#define clAmdFftSetPlanPrecision clAmdFftSetPlanPrecision_ +#define clAmdFftSetPlanScale clAmdFftSetPlanScale_ +#define clAmdFftSetPlanTransposeResult clAmdFftSetPlanTransposeResult_ +#define clAmdFftSetResultLocation clAmdFftSetResultLocation_ +#define clAmdFftSetup clAmdFftSetup_ +#define clAmdFftTeardown clAmdFftTeardown_ + +#include + +// generated by parser_clamdfft.py +#undef clAmdFftBakePlan +#define clAmdFftBakePlan clAmdFftBakePlan_pfn +#undef clAmdFftCopyPlan +//#define clAmdFftCopyPlan clAmdFftCopyPlan_pfn +#undef clAmdFftCreateDefaultPlan +#define clAmdFftCreateDefaultPlan clAmdFftCreateDefaultPlan_pfn +#undef clAmdFftDestroyPlan +#define clAmdFftDestroyPlan clAmdFftDestroyPlan_pfn +#undef clAmdFftEnqueueTransform +#define clAmdFftEnqueueTransform clAmdFftEnqueueTransform_pfn +#undef clAmdFftGetLayout +//#define clAmdFftGetLayout clAmdFftGetLayout_pfn +#undef clAmdFftGetPlanBatchSize +//#define clAmdFftGetPlanBatchSize clAmdFftGetPlanBatchSize_pfn +#undef clAmdFftGetPlanContext +//#define clAmdFftGetPlanContext clAmdFftGetPlanContext_pfn +#undef clAmdFftGetPlanDim +//#define clAmdFftGetPlanDim clAmdFftGetPlanDim_pfn +#undef clAmdFftGetPlanDistance +//#define clAmdFftGetPlanDistance clAmdFftGetPlanDistance_pfn +#undef clAmdFftGetPlanInStride +//#define clAmdFftGetPlanInStride clAmdFftGetPlanInStride_pfn +#undef clAmdFftGetPlanLength +//#define clAmdFftGetPlanLength clAmdFftGetPlanLength_pfn +#undef clAmdFftGetPlanOutStride +//#define clAmdFftGetPlanOutStride clAmdFftGetPlanOutStride_pfn +#undef clAmdFftGetPlanPrecision +//#define clAmdFftGetPlanPrecision clAmdFftGetPlanPrecision_pfn +#undef clAmdFftGetPlanScale +//#define clAmdFftGetPlanScale clAmdFftGetPlanScale_pfn +#undef clAmdFftGetPlanTransposeResult +//#define clAmdFftGetPlanTransposeResult clAmdFftGetPlanTransposeResult_pfn +#undef clAmdFftGetResultLocation +//#define clAmdFftGetResultLocation clAmdFftGetResultLocation_pfn +#undef clAmdFftGetTmpBufSize +#define clAmdFftGetTmpBufSize clAmdFftGetTmpBufSize_pfn +#undef clAmdFftGetVersion +#define clAmdFftGetVersion clAmdFftGetVersion_pfn +#undef clAmdFftSetLayout +#define clAmdFftSetLayout clAmdFftSetLayout_pfn +#undef clAmdFftSetPlanBatchSize +#define clAmdFftSetPlanBatchSize clAmdFftSetPlanBatchSize_pfn +#undef clAmdFftSetPlanDim +//#define clAmdFftSetPlanDim clAmdFftSetPlanDim_pfn +#undef clAmdFftSetPlanDistance +#define clAmdFftSetPlanDistance clAmdFftSetPlanDistance_pfn +#undef clAmdFftSetPlanInStride +#define clAmdFftSetPlanInStride clAmdFftSetPlanInStride_pfn +#undef clAmdFftSetPlanLength +//#define clAmdFftSetPlanLength clAmdFftSetPlanLength_pfn +#undef clAmdFftSetPlanOutStride +#define clAmdFftSetPlanOutStride clAmdFftSetPlanOutStride_pfn +#undef clAmdFftSetPlanPrecision +#define clAmdFftSetPlanPrecision clAmdFftSetPlanPrecision_pfn +#undef clAmdFftSetPlanScale +#define clAmdFftSetPlanScale clAmdFftSetPlanScale_pfn +#undef clAmdFftSetPlanTransposeResult +//#define clAmdFftSetPlanTransposeResult clAmdFftSetPlanTransposeResult_pfn +#undef clAmdFftSetResultLocation +#define clAmdFftSetResultLocation clAmdFftSetResultLocation_pfn +#undef clAmdFftSetup +#define clAmdFftSetup clAmdFftSetup_pfn +#undef clAmdFftTeardown +#define clAmdFftTeardown clAmdFftTeardown_pfn + +// generated by parser_clamdfft.py +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftBakePlan)(clAmdFftPlanHandle plHandle, cl_uint numQueues, cl_command_queue* commQueueFFT, void (CL_CALLBACK* pfn_notify) (clAmdFftPlanHandle plHandle, void* user_data), void* user_data); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftCopyPlan)(clAmdFftPlanHandle* out_plHandle, cl_context new_context, clAmdFftPlanHandle in_plHandle); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftCreateDefaultPlan)(clAmdFftPlanHandle* plHandle, cl_context context, const clAmdFftDim dim, const size_t* clLengths); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftDestroyPlan)(clAmdFftPlanHandle* plHandle); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftEnqueueTransform)(clAmdFftPlanHandle plHandle, clAmdFftDirection dir, cl_uint numQueuesAndEvents, cl_command_queue* commQueues, cl_uint numWaitEvents, const cl_event* waitEvents, cl_event* outEvents, cl_mem* inputBuffers, cl_mem* outputBuffers, cl_mem tmpBuffer); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetLayout)(const clAmdFftPlanHandle plHandle, clAmdFftLayout* iLayout, clAmdFftLayout* oLayout); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanBatchSize)(const clAmdFftPlanHandle plHandle, size_t* batchSize); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanContext)(const clAmdFftPlanHandle plHandle, cl_context* context); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanDim)(const clAmdFftPlanHandle plHandle, clAmdFftDim* dim, cl_uint* size); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanDistance)(const clAmdFftPlanHandle plHandle, size_t* iDist, size_t* oDist); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanInStride)(const clAmdFftPlanHandle plHandle, const clAmdFftDim dim, size_t* clStrides); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanLength)(const clAmdFftPlanHandle plHandle, const clAmdFftDim dim, size_t* clLengths); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanOutStride)(const clAmdFftPlanHandle plHandle, const clAmdFftDim dim, size_t* clStrides); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanPrecision)(const clAmdFftPlanHandle plHandle, clAmdFftPrecision* precision); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanScale)(const clAmdFftPlanHandle plHandle, clAmdFftDirection dir, cl_float* scale); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetPlanTransposeResult)(const clAmdFftPlanHandle plHandle, clAmdFftResultTransposed* transposed); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetResultLocation)(const clAmdFftPlanHandle plHandle, clAmdFftResultLocation* placeness); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetTmpBufSize)(const clAmdFftPlanHandle plHandle, size_t* buffersize); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftGetVersion)(cl_uint* major, cl_uint* minor, cl_uint* patch); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetLayout)(clAmdFftPlanHandle plHandle, clAmdFftLayout iLayout, clAmdFftLayout oLayout); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanBatchSize)(clAmdFftPlanHandle plHandle, size_t batchSize); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanDim)(clAmdFftPlanHandle plHandle, const clAmdFftDim dim); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanDistance)(clAmdFftPlanHandle plHandle, size_t iDist, size_t oDist); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanInStride)(clAmdFftPlanHandle plHandle, const clAmdFftDim dim, size_t* clStrides); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanLength)(clAmdFftPlanHandle plHandle, const clAmdFftDim dim, const size_t* clLengths); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanOutStride)(clAmdFftPlanHandle plHandle, const clAmdFftDim dim, size_t* clStrides); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanPrecision)(clAmdFftPlanHandle plHandle, clAmdFftPrecision precision); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanScale)(clAmdFftPlanHandle plHandle, clAmdFftDirection dir, cl_float scale); +//extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetPlanTransposeResult)(clAmdFftPlanHandle plHandle, clAmdFftResultTransposed transposed); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetResultLocation)(clAmdFftPlanHandle plHandle, clAmdFftResultLocation placeness); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftSetup)(const clAmdFftSetupData* setupData); +extern CL_RUNTIME_EXPORT clAmdFftStatus (*clAmdFftTeardown)(); diff --git a/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp b/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp new file mode 100644 index 0000000..fdaf469 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp @@ -0,0 +1,370 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP +#error "Invalid usage" +#endif + +// generated by parser_cl.py +#define clBuildProgram clBuildProgram_ +#define clCompileProgram clCompileProgram_ +#define clCreateBuffer clCreateBuffer_ +#define clCreateCommandQueue clCreateCommandQueue_ +#define clCreateContext clCreateContext_ +#define clCreateContextFromType clCreateContextFromType_ +#define clCreateImage clCreateImage_ +#define clCreateImage2D clCreateImage2D_ +#define clCreateImage3D clCreateImage3D_ +#define clCreateKernel clCreateKernel_ +#define clCreateKernelsInProgram clCreateKernelsInProgram_ +#define clCreateProgramWithBinary clCreateProgramWithBinary_ +#define clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels_ +#define clCreateProgramWithSource clCreateProgramWithSource_ +#define clCreateSampler clCreateSampler_ +#define clCreateSubBuffer clCreateSubBuffer_ +#define clCreateSubDevices clCreateSubDevices_ +#define clCreateUserEvent clCreateUserEvent_ +#define clEnqueueBarrier clEnqueueBarrier_ +#define clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList_ +#define clEnqueueCopyBuffer clEnqueueCopyBuffer_ +#define clEnqueueCopyBufferRect clEnqueueCopyBufferRect_ +#define clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage_ +#define clEnqueueCopyImage clEnqueueCopyImage_ +#define clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer_ +#define clEnqueueFillBuffer clEnqueueFillBuffer_ +#define clEnqueueFillImage clEnqueueFillImage_ +#define clEnqueueMapBuffer clEnqueueMapBuffer_ +#define clEnqueueMapImage clEnqueueMapImage_ +#define clEnqueueMarker clEnqueueMarker_ +#define clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList_ +#define clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects_ +#define clEnqueueNDRangeKernel clEnqueueNDRangeKernel_ +#define clEnqueueNativeKernel clEnqueueNativeKernel_ +#define clEnqueueReadBuffer clEnqueueReadBuffer_ +#define clEnqueueReadBufferRect clEnqueueReadBufferRect_ +#define clEnqueueReadImage clEnqueueReadImage_ +#define clEnqueueTask clEnqueueTask_ +#define clEnqueueUnmapMemObject clEnqueueUnmapMemObject_ +#define clEnqueueWaitForEvents clEnqueueWaitForEvents_ +#define clEnqueueWriteBuffer clEnqueueWriteBuffer_ +#define clEnqueueWriteBufferRect clEnqueueWriteBufferRect_ +#define clEnqueueWriteImage clEnqueueWriteImage_ +#define clFinish clFinish_ +#define clFlush clFlush_ +#define clGetCommandQueueInfo clGetCommandQueueInfo_ +#define clGetContextInfo clGetContextInfo_ +#define clGetDeviceIDs clGetDeviceIDs_ +#define clGetDeviceInfo clGetDeviceInfo_ +#define clGetEventInfo clGetEventInfo_ +#define clGetEventProfilingInfo clGetEventProfilingInfo_ +#define clGetExtensionFunctionAddress clGetExtensionFunctionAddress_ +#define clGetExtensionFunctionAddressForPlatform clGetExtensionFunctionAddressForPlatform_ +#define clGetImageInfo clGetImageInfo_ +#define clGetKernelArgInfo clGetKernelArgInfo_ +#define clGetKernelInfo clGetKernelInfo_ +#define clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo_ +#define clGetMemObjectInfo clGetMemObjectInfo_ +#define clGetPlatformIDs clGetPlatformIDs_ +#define clGetPlatformInfo clGetPlatformInfo_ +#define clGetProgramBuildInfo clGetProgramBuildInfo_ +#define clGetProgramInfo clGetProgramInfo_ +#define clGetSamplerInfo clGetSamplerInfo_ +#define clGetSupportedImageFormats clGetSupportedImageFormats_ +#define clLinkProgram clLinkProgram_ +#define clReleaseCommandQueue clReleaseCommandQueue_ +#define clReleaseContext clReleaseContext_ +#define clReleaseDevice clReleaseDevice_ +#define clReleaseEvent clReleaseEvent_ +#define clReleaseKernel clReleaseKernel_ +#define clReleaseMemObject clReleaseMemObject_ +#define clReleaseProgram clReleaseProgram_ +#define clReleaseSampler clReleaseSampler_ +#define clRetainCommandQueue clRetainCommandQueue_ +#define clRetainContext clRetainContext_ +#define clRetainDevice clRetainDevice_ +#define clRetainEvent clRetainEvent_ +#define clRetainKernel clRetainKernel_ +#define clRetainMemObject clRetainMemObject_ +#define clRetainProgram clRetainProgram_ +#define clRetainSampler clRetainSampler_ +#define clSetEventCallback clSetEventCallback_ +#define clSetKernelArg clSetKernelArg_ +#define clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback_ +#define clSetUserEventStatus clSetUserEventStatus_ +#define clUnloadCompiler clUnloadCompiler_ +#define clUnloadPlatformCompiler clUnloadPlatformCompiler_ +#define clWaitForEvents clWaitForEvents_ + +#if defined __APPLE__ +#include +#else +#include +#endif + +// generated by parser_cl.py +#undef clBuildProgram +#define clBuildProgram clBuildProgram_pfn +#undef clCompileProgram +#define clCompileProgram clCompileProgram_pfn +#undef clCreateBuffer +#define clCreateBuffer clCreateBuffer_pfn +#undef clCreateCommandQueue +#define clCreateCommandQueue clCreateCommandQueue_pfn +#undef clCreateContext +#define clCreateContext clCreateContext_pfn +#undef clCreateContextFromType +#define clCreateContextFromType clCreateContextFromType_pfn +#undef clCreateImage +#define clCreateImage clCreateImage_pfn +#undef clCreateImage2D +#define clCreateImage2D clCreateImage2D_pfn +#undef clCreateImage3D +#define clCreateImage3D clCreateImage3D_pfn +#undef clCreateKernel +#define clCreateKernel clCreateKernel_pfn +#undef clCreateKernelsInProgram +#define clCreateKernelsInProgram clCreateKernelsInProgram_pfn +#undef clCreateProgramWithBinary +#define clCreateProgramWithBinary clCreateProgramWithBinary_pfn +#undef clCreateProgramWithBuiltInKernels +#define clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels_pfn +#undef clCreateProgramWithSource +#define clCreateProgramWithSource clCreateProgramWithSource_pfn +#undef clCreateSampler +#define clCreateSampler clCreateSampler_pfn +#undef clCreateSubBuffer +#define clCreateSubBuffer clCreateSubBuffer_pfn +#undef clCreateSubDevices +#define clCreateSubDevices clCreateSubDevices_pfn +#undef clCreateUserEvent +#define clCreateUserEvent clCreateUserEvent_pfn +#undef clEnqueueBarrier +#define clEnqueueBarrier clEnqueueBarrier_pfn +#undef clEnqueueBarrierWithWaitList +#define clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList_pfn +#undef clEnqueueCopyBuffer +#define clEnqueueCopyBuffer clEnqueueCopyBuffer_pfn +#undef clEnqueueCopyBufferRect +#define clEnqueueCopyBufferRect clEnqueueCopyBufferRect_pfn +#undef clEnqueueCopyBufferToImage +#define clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage_pfn +#undef clEnqueueCopyImage +#define clEnqueueCopyImage clEnqueueCopyImage_pfn +#undef clEnqueueCopyImageToBuffer +#define clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer_pfn +#undef clEnqueueFillBuffer +#define clEnqueueFillBuffer clEnqueueFillBuffer_pfn +#undef clEnqueueFillImage +#define clEnqueueFillImage clEnqueueFillImage_pfn +#undef clEnqueueMapBuffer +#define clEnqueueMapBuffer clEnqueueMapBuffer_pfn +#undef clEnqueueMapImage +#define clEnqueueMapImage clEnqueueMapImage_pfn +#undef clEnqueueMarker +#define clEnqueueMarker clEnqueueMarker_pfn +#undef clEnqueueMarkerWithWaitList +#define clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList_pfn +#undef clEnqueueMigrateMemObjects +#define clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects_pfn +#undef clEnqueueNDRangeKernel +#define clEnqueueNDRangeKernel clEnqueueNDRangeKernel_pfn +#undef clEnqueueNativeKernel +#define clEnqueueNativeKernel clEnqueueNativeKernel_pfn +#undef clEnqueueReadBuffer +#define clEnqueueReadBuffer clEnqueueReadBuffer_pfn +#undef clEnqueueReadBufferRect +#define clEnqueueReadBufferRect clEnqueueReadBufferRect_pfn +#undef clEnqueueReadImage +#define clEnqueueReadImage clEnqueueReadImage_pfn +#undef clEnqueueTask +#define clEnqueueTask clEnqueueTask_pfn +#undef clEnqueueUnmapMemObject +#define clEnqueueUnmapMemObject clEnqueueUnmapMemObject_pfn +#undef clEnqueueWaitForEvents +#define clEnqueueWaitForEvents clEnqueueWaitForEvents_pfn +#undef clEnqueueWriteBuffer +#define clEnqueueWriteBuffer clEnqueueWriteBuffer_pfn +#undef clEnqueueWriteBufferRect +#define clEnqueueWriteBufferRect clEnqueueWriteBufferRect_pfn +#undef clEnqueueWriteImage +#define clEnqueueWriteImage clEnqueueWriteImage_pfn +#undef clFinish +#define clFinish clFinish_pfn +#undef clFlush +#define clFlush clFlush_pfn +#undef clGetCommandQueueInfo +#define clGetCommandQueueInfo clGetCommandQueueInfo_pfn +#undef clGetContextInfo +#define clGetContextInfo clGetContextInfo_pfn +#undef clGetDeviceIDs +#define clGetDeviceIDs clGetDeviceIDs_pfn +#undef clGetDeviceInfo +#define clGetDeviceInfo clGetDeviceInfo_pfn +#undef clGetEventInfo +#define clGetEventInfo clGetEventInfo_pfn +#undef clGetEventProfilingInfo +#define clGetEventProfilingInfo clGetEventProfilingInfo_pfn +#undef clGetExtensionFunctionAddress +#define clGetExtensionFunctionAddress clGetExtensionFunctionAddress_pfn +#undef clGetExtensionFunctionAddressForPlatform +#define clGetExtensionFunctionAddressForPlatform clGetExtensionFunctionAddressForPlatform_pfn +#undef clGetImageInfo +#define clGetImageInfo clGetImageInfo_pfn +#undef clGetKernelArgInfo +#define clGetKernelArgInfo clGetKernelArgInfo_pfn +#undef clGetKernelInfo +#define clGetKernelInfo clGetKernelInfo_pfn +#undef clGetKernelWorkGroupInfo +#define clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo_pfn +#undef clGetMemObjectInfo +#define clGetMemObjectInfo clGetMemObjectInfo_pfn +#undef clGetPlatformIDs +#define clGetPlatformIDs clGetPlatformIDs_pfn +#undef clGetPlatformInfo +#define clGetPlatformInfo clGetPlatformInfo_pfn +#undef clGetProgramBuildInfo +#define clGetProgramBuildInfo clGetProgramBuildInfo_pfn +#undef clGetProgramInfo +#define clGetProgramInfo clGetProgramInfo_pfn +#undef clGetSamplerInfo +#define clGetSamplerInfo clGetSamplerInfo_pfn +#undef clGetSupportedImageFormats +#define clGetSupportedImageFormats clGetSupportedImageFormats_pfn +#undef clLinkProgram +#define clLinkProgram clLinkProgram_pfn +#undef clReleaseCommandQueue +#define clReleaseCommandQueue clReleaseCommandQueue_pfn +#undef clReleaseContext +#define clReleaseContext clReleaseContext_pfn +#undef clReleaseDevice +#define clReleaseDevice clReleaseDevice_pfn +#undef clReleaseEvent +#define clReleaseEvent clReleaseEvent_pfn +#undef clReleaseKernel +#define clReleaseKernel clReleaseKernel_pfn +#undef clReleaseMemObject +#define clReleaseMemObject clReleaseMemObject_pfn +#undef clReleaseProgram +#define clReleaseProgram clReleaseProgram_pfn +#undef clReleaseSampler +#define clReleaseSampler clReleaseSampler_pfn +#undef clRetainCommandQueue +#define clRetainCommandQueue clRetainCommandQueue_pfn +#undef clRetainContext +#define clRetainContext clRetainContext_pfn +#undef clRetainDevice +#define clRetainDevice clRetainDevice_pfn +#undef clRetainEvent +#define clRetainEvent clRetainEvent_pfn +#undef clRetainKernel +#define clRetainKernel clRetainKernel_pfn +#undef clRetainMemObject +#define clRetainMemObject clRetainMemObject_pfn +#undef clRetainProgram +#define clRetainProgram clRetainProgram_pfn +#undef clRetainSampler +#define clRetainSampler clRetainSampler_pfn +#undef clSetEventCallback +#define clSetEventCallback clSetEventCallback_pfn +#undef clSetKernelArg +#define clSetKernelArg clSetKernelArg_pfn +#undef clSetMemObjectDestructorCallback +#define clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback_pfn +#undef clSetUserEventStatus +#define clSetUserEventStatus clSetUserEventStatus_pfn +#undef clUnloadCompiler +#define clUnloadCompiler clUnloadCompiler_pfn +#undef clUnloadPlatformCompiler +#define clUnloadPlatformCompiler clUnloadPlatformCompiler_pfn +#undef clWaitForEvents +#define clWaitForEvents clWaitForEvents_pfn + +// generated by parser_cl.py +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clBuildProgram)(cl_program, cl_uint, const cl_device_id*, const char*, void (CL_CALLBACK*) (cl_program, void*), void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clCompileProgram)(cl_program, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, const char**, void (CL_CALLBACK*) (cl_program, void*), void*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateBuffer)(cl_context, cl_mem_flags, size_t, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_command_queue (CL_API_CALL*clCreateCommandQueue)(cl_context, cl_device_id, cl_command_queue_properties, cl_int*); +extern CL_RUNTIME_EXPORT cl_context (CL_API_CALL*clCreateContext)(const cl_context_properties*, cl_uint, const cl_device_id*, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_context (CL_API_CALL*clCreateContextFromType)(const cl_context_properties*, cl_device_type, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateImage)(cl_context, cl_mem_flags, const cl_image_format*, const cl_image_desc*, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateImage2D)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateImage3D)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, size_t, size_t, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_kernel (CL_API_CALL*clCreateKernel)(cl_program, const char*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clCreateKernelsInProgram)(cl_program, cl_uint, cl_kernel*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clCreateProgramWithBinary)(cl_context, cl_uint, const cl_device_id*, const size_t*, const unsigned char**, cl_int*, cl_int*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clCreateProgramWithBuiltInKernels)(cl_context, cl_uint, const cl_device_id*, const char*, cl_int*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clCreateProgramWithSource)(cl_context, cl_uint, const char**, const size_t*, cl_int*); +extern CL_RUNTIME_EXPORT cl_sampler (CL_API_CALL*clCreateSampler)(cl_context, cl_bool, cl_addressing_mode, cl_filter_mode, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateSubBuffer)(cl_mem, cl_mem_flags, cl_buffer_create_type, const void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clCreateSubDevices)(cl_device_id, const cl_device_partition_property*, cl_uint, cl_device_id*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_event (CL_API_CALL*clCreateUserEvent)(cl_context, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueBarrier)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueBarrierWithWaitList)(cl_command_queue, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyBuffer)(cl_command_queue, cl_mem, cl_mem, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyBufferRect)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyBufferToImage)(cl_command_queue, cl_mem, cl_mem, size_t, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyImage)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyImageToBuffer)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueFillBuffer)(cl_command_queue, cl_mem, const void*, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueFillImage)(cl_command_queue, cl_mem, const void*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clEnqueueMapBuffer)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, size_t, size_t, cl_uint, const cl_event*, cl_event*, cl_int*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clEnqueueMapImage)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, const size_t*, const size_t*, size_t*, size_t*, cl_uint, const cl_event*, cl_event*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueMarker)(cl_command_queue, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueMarkerWithWaitList)(cl_command_queue, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueMigrateMemObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_mem_migration_flags, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueNDRangeKernel)(cl_command_queue, cl_kernel, cl_uint, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueNativeKernel)(cl_command_queue, void (CL_CALLBACK*) (void*), void*, size_t, cl_uint, const cl_mem*, const void**, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReadBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReadBufferRect)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReadImage)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueTask)(cl_command_queue, cl_kernel, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueUnmapMemObject)(cl_command_queue, cl_mem, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWaitForEvents)(cl_command_queue, cl_uint, const cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWriteBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWriteBufferRect)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWriteImage)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clFinish)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clFlush)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetCommandQueueInfo)(cl_command_queue, cl_command_queue_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetContextInfo)(cl_context, cl_context_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetDeviceIDs)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetDeviceInfo)(cl_device_id, cl_device_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetEventInfo)(cl_event, cl_event_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetEventProfilingInfo)(cl_event, cl_profiling_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clGetExtensionFunctionAddress)(const char*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clGetExtensionFunctionAddressForPlatform)(cl_platform_id, const char*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetImageInfo)(cl_mem, cl_image_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetKernelArgInfo)(cl_kernel, cl_uint, cl_kernel_arg_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetKernelInfo)(cl_kernel, cl_kernel_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetKernelWorkGroupInfo)(cl_kernel, cl_device_id, cl_kernel_work_group_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetMemObjectInfo)(cl_mem, cl_mem_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetPlatformIDs)(cl_uint, cl_platform_id*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetPlatformInfo)(cl_platform_id, cl_platform_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetProgramBuildInfo)(cl_program, cl_device_id, cl_program_build_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetProgramInfo)(cl_program, cl_program_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetSamplerInfo)(cl_sampler, cl_sampler_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetSupportedImageFormats)(cl_context, cl_mem_flags, cl_mem_object_type, cl_uint, cl_image_format*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clLinkProgram)(cl_context, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, void (CL_CALLBACK*) (cl_program, void*), void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseCommandQueue)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseContext)(cl_context); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseDevice)(cl_device_id); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseEvent)(cl_event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseKernel)(cl_kernel); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseMemObject)(cl_mem); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseProgram)(cl_program); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseSampler)(cl_sampler); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainCommandQueue)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainContext)(cl_context); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainDevice)(cl_device_id); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainEvent)(cl_event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainKernel)(cl_kernel); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainMemObject)(cl_mem); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainProgram)(cl_program); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainSampler)(cl_sampler); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetEventCallback)(cl_event, cl_int, void (CL_CALLBACK*) (cl_event, cl_int, void*), void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetKernelArg)(cl_kernel, cl_uint, size_t, const void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetMemObjectDestructorCallback)(cl_mem, void (CL_CALLBACK*) (cl_mem, void*), void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetUserEventStatus)(cl_event, cl_int); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clUnloadCompiler)(); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clUnloadPlatformCompiler)(cl_platform_id); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clWaitForEvents)(cl_uint, const cl_event*); diff --git a/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp b/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp new file mode 100644 index 0000000..216b22b --- /dev/null +++ b/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp @@ -0,0 +1,272 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP +#error "Invalid usage" +#endif + +// generated by parser_cl.py +#undef clBuildProgram +#define clBuildProgram clBuildProgram_fn +inline cl_int clBuildProgram(cl_program p0, cl_uint p1, const cl_device_id* p2, const char* p3, void (CL_CALLBACK*p4) (cl_program, void*), void* p5) { return clBuildProgram_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCompileProgram +#define clCompileProgram clCompileProgram_fn +inline cl_int clCompileProgram(cl_program p0, cl_uint p1, const cl_device_id* p2, const char* p3, cl_uint p4, const cl_program* p5, const char** p6, void (CL_CALLBACK*p7) (cl_program, void*), void* p8) { return clCompileProgram_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clCreateBuffer +#define clCreateBuffer clCreateBuffer_fn +inline cl_mem clCreateBuffer(cl_context p0, cl_mem_flags p1, size_t p2, void* p3, cl_int* p4) { return clCreateBuffer_pfn(p0, p1, p2, p3, p4); } +#undef clCreateCommandQueue +#define clCreateCommandQueue clCreateCommandQueue_fn +inline cl_command_queue clCreateCommandQueue(cl_context p0, cl_device_id p1, cl_command_queue_properties p2, cl_int* p3) { return clCreateCommandQueue_pfn(p0, p1, p2, p3); } +#undef clCreateContext +#define clCreateContext clCreateContext_fn +inline cl_context clCreateContext(const cl_context_properties* p0, cl_uint p1, const cl_device_id* p2, void (CL_CALLBACK*p3) (const char*, const void*, size_t, void*), void* p4, cl_int* p5) { return clCreateContext_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateContextFromType +#define clCreateContextFromType clCreateContextFromType_fn +inline cl_context clCreateContextFromType(const cl_context_properties* p0, cl_device_type p1, void (CL_CALLBACK*p2) (const char*, const void*, size_t, void*), void* p3, cl_int* p4) { return clCreateContextFromType_pfn(p0, p1, p2, p3, p4); } +#undef clCreateImage +#define clCreateImage clCreateImage_fn +inline cl_mem clCreateImage(cl_context p0, cl_mem_flags p1, const cl_image_format* p2, const cl_image_desc* p3, void* p4, cl_int* p5) { return clCreateImage_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateImage2D +#define clCreateImage2D clCreateImage2D_fn +inline cl_mem clCreateImage2D(cl_context p0, cl_mem_flags p1, const cl_image_format* p2, size_t p3, size_t p4, size_t p5, void* p6, cl_int* p7) { return clCreateImage2D_pfn(p0, p1, p2, p3, p4, p5, p6, p7); } +#undef clCreateImage3D +#define clCreateImage3D clCreateImage3D_fn +inline cl_mem clCreateImage3D(cl_context p0, cl_mem_flags p1, const cl_image_format* p2, size_t p3, size_t p4, size_t p5, size_t p6, size_t p7, void* p8, cl_int* p9) { return clCreateImage3D_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#undef clCreateKernel +#define clCreateKernel clCreateKernel_fn +inline cl_kernel clCreateKernel(cl_program p0, const char* p1, cl_int* p2) { return clCreateKernel_pfn(p0, p1, p2); } +#undef clCreateKernelsInProgram +#define clCreateKernelsInProgram clCreateKernelsInProgram_fn +inline cl_int clCreateKernelsInProgram(cl_program p0, cl_uint p1, cl_kernel* p2, cl_uint* p3) { return clCreateKernelsInProgram_pfn(p0, p1, p2, p3); } +#undef clCreateProgramWithBinary +#define clCreateProgramWithBinary clCreateProgramWithBinary_fn +inline cl_program clCreateProgramWithBinary(cl_context p0, cl_uint p1, const cl_device_id* p2, const size_t* p3, const unsigned char** p4, cl_int* p5, cl_int* p6) { return clCreateProgramWithBinary_pfn(p0, p1, p2, p3, p4, p5, p6); } +#undef clCreateProgramWithBuiltInKernels +#define clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels_fn +inline cl_program clCreateProgramWithBuiltInKernels(cl_context p0, cl_uint p1, const cl_device_id* p2, const char* p3, cl_int* p4) { return clCreateProgramWithBuiltInKernels_pfn(p0, p1, p2, p3, p4); } +#undef clCreateProgramWithSource +#define clCreateProgramWithSource clCreateProgramWithSource_fn +inline cl_program clCreateProgramWithSource(cl_context p0, cl_uint p1, const char** p2, const size_t* p3, cl_int* p4) { return clCreateProgramWithSource_pfn(p0, p1, p2, p3, p4); } +#undef clCreateSampler +#define clCreateSampler clCreateSampler_fn +inline cl_sampler clCreateSampler(cl_context p0, cl_bool p1, cl_addressing_mode p2, cl_filter_mode p3, cl_int* p4) { return clCreateSampler_pfn(p0, p1, p2, p3, p4); } +#undef clCreateSubBuffer +#define clCreateSubBuffer clCreateSubBuffer_fn +inline cl_mem clCreateSubBuffer(cl_mem p0, cl_mem_flags p1, cl_buffer_create_type p2, const void* p3, cl_int* p4) { return clCreateSubBuffer_pfn(p0, p1, p2, p3, p4); } +#undef clCreateSubDevices +#define clCreateSubDevices clCreateSubDevices_fn +inline cl_int clCreateSubDevices(cl_device_id p0, const cl_device_partition_property* p1, cl_uint p2, cl_device_id* p3, cl_uint* p4) { return clCreateSubDevices_pfn(p0, p1, p2, p3, p4); } +#undef clCreateUserEvent +#define clCreateUserEvent clCreateUserEvent_fn +inline cl_event clCreateUserEvent(cl_context p0, cl_int* p1) { return clCreateUserEvent_pfn(p0, p1); } +#undef clEnqueueBarrier +#define clEnqueueBarrier clEnqueueBarrier_fn +inline cl_int clEnqueueBarrier(cl_command_queue p0) { return clEnqueueBarrier_pfn(p0); } +#undef clEnqueueBarrierWithWaitList +#define clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList_fn +inline cl_int clEnqueueBarrierWithWaitList(cl_command_queue p0, cl_uint p1, const cl_event* p2, cl_event* p3) { return clEnqueueBarrierWithWaitList_pfn(p0, p1, p2, p3); } +#undef clEnqueueCopyBuffer +#define clEnqueueCopyBuffer clEnqueueCopyBuffer_fn +inline cl_int clEnqueueCopyBuffer(cl_command_queue p0, cl_mem p1, cl_mem p2, size_t p3, size_t p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueCopyBufferRect +#define clEnqueueCopyBufferRect clEnqueueCopyBufferRect_fn +inline cl_int clEnqueueCopyBufferRect(cl_command_queue p0, cl_mem p1, cl_mem p2, const size_t* p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, size_t p8, size_t p9, cl_uint p10, const cl_event* p11, cl_event* p12) { return clEnqueueCopyBufferRect_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } +#undef clEnqueueCopyBufferToImage +#define clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage_fn +inline cl_int clEnqueueCopyBufferToImage(cl_command_queue p0, cl_mem p1, cl_mem p2, size_t p3, const size_t* p4, const size_t* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyBufferToImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueCopyImage +#define clEnqueueCopyImage clEnqueueCopyImage_fn +inline cl_int clEnqueueCopyImage(cl_command_queue p0, cl_mem p1, cl_mem p2, const size_t* p3, const size_t* p4, const size_t* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueCopyImageToBuffer +#define clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer_fn +inline cl_int clEnqueueCopyImageToBuffer(cl_command_queue p0, cl_mem p1, cl_mem p2, const size_t* p3, const size_t* p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyImageToBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueFillBuffer +#define clEnqueueFillBuffer clEnqueueFillBuffer_fn +inline cl_int clEnqueueFillBuffer(cl_command_queue p0, cl_mem p1, const void* p2, size_t p3, size_t p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueFillBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueFillImage +#define clEnqueueFillImage clEnqueueFillImage_fn +inline cl_int clEnqueueFillImage(cl_command_queue p0, cl_mem p1, const void* p2, const size_t* p3, const size_t* p4, cl_uint p5, const cl_event* p6, cl_event* p7) { return clEnqueueFillImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7); } +#undef clEnqueueMapBuffer +#define clEnqueueMapBuffer clEnqueueMapBuffer_fn +inline void* clEnqueueMapBuffer(cl_command_queue p0, cl_mem p1, cl_bool p2, cl_map_flags p3, size_t p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8, cl_int* p9) { return clEnqueueMapBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#undef clEnqueueMapImage +#define clEnqueueMapImage clEnqueueMapImage_fn +inline void* clEnqueueMapImage(cl_command_queue p0, cl_mem p1, cl_bool p2, cl_map_flags p3, const size_t* p4, const size_t* p5, size_t* p6, size_t* p7, cl_uint p8, const cl_event* p9, cl_event* p10, cl_int* p11) { return clEnqueueMapImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } +#undef clEnqueueMarker +#define clEnqueueMarker clEnqueueMarker_fn +inline cl_int clEnqueueMarker(cl_command_queue p0, cl_event* p1) { return clEnqueueMarker_pfn(p0, p1); } +#undef clEnqueueMarkerWithWaitList +#define clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList_fn +inline cl_int clEnqueueMarkerWithWaitList(cl_command_queue p0, cl_uint p1, const cl_event* p2, cl_event* p3) { return clEnqueueMarkerWithWaitList_pfn(p0, p1, p2, p3); } +#undef clEnqueueMigrateMemObjects +#define clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects_fn +inline cl_int clEnqueueMigrateMemObjects(cl_command_queue p0, cl_uint p1, const cl_mem* p2, cl_mem_migration_flags p3, cl_uint p4, const cl_event* p5, cl_event* p6) { return clEnqueueMigrateMemObjects_pfn(p0, p1, p2, p3, p4, p5, p6); } +#undef clEnqueueNDRangeKernel +#define clEnqueueNDRangeKernel clEnqueueNDRangeKernel_fn +inline cl_int clEnqueueNDRangeKernel(cl_command_queue p0, cl_kernel p1, cl_uint p2, const size_t* p3, const size_t* p4, const size_t* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueNDRangeKernel_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueNativeKernel +#define clEnqueueNativeKernel clEnqueueNativeKernel_fn +inline cl_int clEnqueueNativeKernel(cl_command_queue p0, void (CL_CALLBACK*p1) (void*), void* p2, size_t p3, cl_uint p4, const cl_mem* p5, const void** p6, cl_uint p7, const cl_event* p8, cl_event* p9) { return clEnqueueNativeKernel_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#undef clEnqueueReadBuffer +#define clEnqueueReadBuffer clEnqueueReadBuffer_fn +inline cl_int clEnqueueReadBuffer(cl_command_queue p0, cl_mem p1, cl_bool p2, size_t p3, size_t p4, void* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueReadBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueReadBufferRect +#define clEnqueueReadBufferRect clEnqueueReadBufferRect_fn +inline cl_int clEnqueueReadBufferRect(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, size_t p8, size_t p9, void* p10, cl_uint p11, const cl_event* p12, cl_event* p13) { return clEnqueueReadBufferRect_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } +#undef clEnqueueReadImage +#define clEnqueueReadImage clEnqueueReadImage_fn +inline cl_int clEnqueueReadImage(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, size_t p5, size_t p6, void* p7, cl_uint p8, const cl_event* p9, cl_event* p10) { return clEnqueueReadImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } +#undef clEnqueueTask +#define clEnqueueTask clEnqueueTask_fn +inline cl_int clEnqueueTask(cl_command_queue p0, cl_kernel p1, cl_uint p2, const cl_event* p3, cl_event* p4) { return clEnqueueTask_pfn(p0, p1, p2, p3, p4); } +#undef clEnqueueUnmapMemObject +#define clEnqueueUnmapMemObject clEnqueueUnmapMemObject_fn +inline cl_int clEnqueueUnmapMemObject(cl_command_queue p0, cl_mem p1, void* p2, cl_uint p3, const cl_event* p4, cl_event* p5) { return clEnqueueUnmapMemObject_pfn(p0, p1, p2, p3, p4, p5); } +#undef clEnqueueWaitForEvents +#define clEnqueueWaitForEvents clEnqueueWaitForEvents_fn +inline cl_int clEnqueueWaitForEvents(cl_command_queue p0, cl_uint p1, const cl_event* p2) { return clEnqueueWaitForEvents_pfn(p0, p1, p2); } +#undef clEnqueueWriteBuffer +#define clEnqueueWriteBuffer clEnqueueWriteBuffer_fn +inline cl_int clEnqueueWriteBuffer(cl_command_queue p0, cl_mem p1, cl_bool p2, size_t p3, size_t p4, const void* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueWriteBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueWriteBufferRect +#define clEnqueueWriteBufferRect clEnqueueWriteBufferRect_fn +inline cl_int clEnqueueWriteBufferRect(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, size_t p8, size_t p9, const void* p10, cl_uint p11, const cl_event* p12, cl_event* p13) { return clEnqueueWriteBufferRect_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } +#undef clEnqueueWriteImage +#define clEnqueueWriteImage clEnqueueWriteImage_fn +inline cl_int clEnqueueWriteImage(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, size_t p5, size_t p6, const void* p7, cl_uint p8, const cl_event* p9, cl_event* p10) { return clEnqueueWriteImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } +#undef clFinish +#define clFinish clFinish_fn +inline cl_int clFinish(cl_command_queue p0) { return clFinish_pfn(p0); } +#undef clFlush +#define clFlush clFlush_fn +inline cl_int clFlush(cl_command_queue p0) { return clFlush_pfn(p0); } +#undef clGetCommandQueueInfo +#define clGetCommandQueueInfo clGetCommandQueueInfo_fn +inline cl_int clGetCommandQueueInfo(cl_command_queue p0, cl_command_queue_info p1, size_t p2, void* p3, size_t* p4) { return clGetCommandQueueInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetContextInfo +#define clGetContextInfo clGetContextInfo_fn +inline cl_int clGetContextInfo(cl_context p0, cl_context_info p1, size_t p2, void* p3, size_t* p4) { return clGetContextInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetDeviceIDs +#define clGetDeviceIDs clGetDeviceIDs_fn +inline cl_int clGetDeviceIDs(cl_platform_id p0, cl_device_type p1, cl_uint p2, cl_device_id* p3, cl_uint* p4) { return clGetDeviceIDs_pfn(p0, p1, p2, p3, p4); } +#undef clGetDeviceInfo +#define clGetDeviceInfo clGetDeviceInfo_fn +inline cl_int clGetDeviceInfo(cl_device_id p0, cl_device_info p1, size_t p2, void* p3, size_t* p4) { return clGetDeviceInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetEventInfo +#define clGetEventInfo clGetEventInfo_fn +inline cl_int clGetEventInfo(cl_event p0, cl_event_info p1, size_t p2, void* p3, size_t* p4) { return clGetEventInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetEventProfilingInfo +#define clGetEventProfilingInfo clGetEventProfilingInfo_fn +inline cl_int clGetEventProfilingInfo(cl_event p0, cl_profiling_info p1, size_t p2, void* p3, size_t* p4) { return clGetEventProfilingInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetExtensionFunctionAddress +#define clGetExtensionFunctionAddress clGetExtensionFunctionAddress_fn +inline void* clGetExtensionFunctionAddress(const char* p0) { return clGetExtensionFunctionAddress_pfn(p0); } +#undef clGetExtensionFunctionAddressForPlatform +#define clGetExtensionFunctionAddressForPlatform clGetExtensionFunctionAddressForPlatform_fn +inline void* clGetExtensionFunctionAddressForPlatform(cl_platform_id p0, const char* p1) { return clGetExtensionFunctionAddressForPlatform_pfn(p0, p1); } +#undef clGetImageInfo +#define clGetImageInfo clGetImageInfo_fn +inline cl_int clGetImageInfo(cl_mem p0, cl_image_info p1, size_t p2, void* p3, size_t* p4) { return clGetImageInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetKernelArgInfo +#define clGetKernelArgInfo clGetKernelArgInfo_fn +inline cl_int clGetKernelArgInfo(cl_kernel p0, cl_uint p1, cl_kernel_arg_info p2, size_t p3, void* p4, size_t* p5) { return clGetKernelArgInfo_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetKernelInfo +#define clGetKernelInfo clGetKernelInfo_fn +inline cl_int clGetKernelInfo(cl_kernel p0, cl_kernel_info p1, size_t p2, void* p3, size_t* p4) { return clGetKernelInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetKernelWorkGroupInfo +#define clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo_fn +inline cl_int clGetKernelWorkGroupInfo(cl_kernel p0, cl_device_id p1, cl_kernel_work_group_info p2, size_t p3, void* p4, size_t* p5) { return clGetKernelWorkGroupInfo_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetMemObjectInfo +#define clGetMemObjectInfo clGetMemObjectInfo_fn +inline cl_int clGetMemObjectInfo(cl_mem p0, cl_mem_info p1, size_t p2, void* p3, size_t* p4) { return clGetMemObjectInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetPlatformIDs +#define clGetPlatformIDs clGetPlatformIDs_fn +inline cl_int clGetPlatformIDs(cl_uint p0, cl_platform_id* p1, cl_uint* p2) { return clGetPlatformIDs_pfn(p0, p1, p2); } +#undef clGetPlatformInfo +#define clGetPlatformInfo clGetPlatformInfo_fn +inline cl_int clGetPlatformInfo(cl_platform_id p0, cl_platform_info p1, size_t p2, void* p3, size_t* p4) { return clGetPlatformInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetProgramBuildInfo +#define clGetProgramBuildInfo clGetProgramBuildInfo_fn +inline cl_int clGetProgramBuildInfo(cl_program p0, cl_device_id p1, cl_program_build_info p2, size_t p3, void* p4, size_t* p5) { return clGetProgramBuildInfo_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetProgramInfo +#define clGetProgramInfo clGetProgramInfo_fn +inline cl_int clGetProgramInfo(cl_program p0, cl_program_info p1, size_t p2, void* p3, size_t* p4) { return clGetProgramInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetSamplerInfo +#define clGetSamplerInfo clGetSamplerInfo_fn +inline cl_int clGetSamplerInfo(cl_sampler p0, cl_sampler_info p1, size_t p2, void* p3, size_t* p4) { return clGetSamplerInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetSupportedImageFormats +#define clGetSupportedImageFormats clGetSupportedImageFormats_fn +inline cl_int clGetSupportedImageFormats(cl_context p0, cl_mem_flags p1, cl_mem_object_type p2, cl_uint p3, cl_image_format* p4, cl_uint* p5) { return clGetSupportedImageFormats_pfn(p0, p1, p2, p3, p4, p5); } +#undef clLinkProgram +#define clLinkProgram clLinkProgram_fn +inline cl_program clLinkProgram(cl_context p0, cl_uint p1, const cl_device_id* p2, const char* p3, cl_uint p4, const cl_program* p5, void (CL_CALLBACK*p6) (cl_program, void*), void* p7, cl_int* p8) { return clLinkProgram_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clReleaseCommandQueue +#define clReleaseCommandQueue clReleaseCommandQueue_fn +inline cl_int clReleaseCommandQueue(cl_command_queue p0) { return clReleaseCommandQueue_pfn(p0); } +#undef clReleaseContext +#define clReleaseContext clReleaseContext_fn +inline cl_int clReleaseContext(cl_context p0) { return clReleaseContext_pfn(p0); } +#undef clReleaseDevice +#define clReleaseDevice clReleaseDevice_fn +inline cl_int clReleaseDevice(cl_device_id p0) { return clReleaseDevice_pfn(p0); } +#undef clReleaseEvent +#define clReleaseEvent clReleaseEvent_fn +inline cl_int clReleaseEvent(cl_event p0) { return clReleaseEvent_pfn(p0); } +#undef clReleaseKernel +#define clReleaseKernel clReleaseKernel_fn +inline cl_int clReleaseKernel(cl_kernel p0) { return clReleaseKernel_pfn(p0); } +#undef clReleaseMemObject +#define clReleaseMemObject clReleaseMemObject_fn +inline cl_int clReleaseMemObject(cl_mem p0) { return clReleaseMemObject_pfn(p0); } +#undef clReleaseProgram +#define clReleaseProgram clReleaseProgram_fn +inline cl_int clReleaseProgram(cl_program p0) { return clReleaseProgram_pfn(p0); } +#undef clReleaseSampler +#define clReleaseSampler clReleaseSampler_fn +inline cl_int clReleaseSampler(cl_sampler p0) { return clReleaseSampler_pfn(p0); } +#undef clRetainCommandQueue +#define clRetainCommandQueue clRetainCommandQueue_fn +inline cl_int clRetainCommandQueue(cl_command_queue p0) { return clRetainCommandQueue_pfn(p0); } +#undef clRetainContext +#define clRetainContext clRetainContext_fn +inline cl_int clRetainContext(cl_context p0) { return clRetainContext_pfn(p0); } +#undef clRetainDevice +#define clRetainDevice clRetainDevice_fn +inline cl_int clRetainDevice(cl_device_id p0) { return clRetainDevice_pfn(p0); } +#undef clRetainEvent +#define clRetainEvent clRetainEvent_fn +inline cl_int clRetainEvent(cl_event p0) { return clRetainEvent_pfn(p0); } +#undef clRetainKernel +#define clRetainKernel clRetainKernel_fn +inline cl_int clRetainKernel(cl_kernel p0) { return clRetainKernel_pfn(p0); } +#undef clRetainMemObject +#define clRetainMemObject clRetainMemObject_fn +inline cl_int clRetainMemObject(cl_mem p0) { return clRetainMemObject_pfn(p0); } +#undef clRetainProgram +#define clRetainProgram clRetainProgram_fn +inline cl_int clRetainProgram(cl_program p0) { return clRetainProgram_pfn(p0); } +#undef clRetainSampler +#define clRetainSampler clRetainSampler_fn +inline cl_int clRetainSampler(cl_sampler p0) { return clRetainSampler_pfn(p0); } +#undef clSetEventCallback +#define clSetEventCallback clSetEventCallback_fn +inline cl_int clSetEventCallback(cl_event p0, cl_int p1, void (CL_CALLBACK*p2) (cl_event, cl_int, void*), void* p3) { return clSetEventCallback_pfn(p0, p1, p2, p3); } +#undef clSetKernelArg +#define clSetKernelArg clSetKernelArg_fn +inline cl_int clSetKernelArg(cl_kernel p0, cl_uint p1, size_t p2, const void* p3) { return clSetKernelArg_pfn(p0, p1, p2, p3); } +#undef clSetMemObjectDestructorCallback +#define clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback_fn +inline cl_int clSetMemObjectDestructorCallback(cl_mem p0, void (CL_CALLBACK*p1) (cl_mem, void*), void* p2) { return clSetMemObjectDestructorCallback_pfn(p0, p1, p2); } +#undef clSetUserEventStatus +#define clSetUserEventStatus clSetUserEventStatus_fn +inline cl_int clSetUserEventStatus(cl_event p0, cl_int p1) { return clSetUserEventStatus_pfn(p0, p1); } +#undef clUnloadCompiler +#define clUnloadCompiler clUnloadCompiler_fn +inline cl_int clUnloadCompiler() { return clUnloadCompiler_pfn(); } +#undef clUnloadPlatformCompiler +#define clUnloadPlatformCompiler clUnloadPlatformCompiler_fn +inline cl_int clUnloadPlatformCompiler(cl_platform_id p0) { return clUnloadPlatformCompiler_pfn(p0); } +#undef clWaitForEvents +#define clWaitForEvents clWaitForEvents_fn +inline cl_int clWaitForEvents(cl_uint p0, const cl_event* p1) { return clWaitForEvents_pfn(p0, p1); } diff --git a/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp b/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp new file mode 100644 index 0000000..0b12aed --- /dev/null +++ b/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp @@ -0,0 +1,62 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP +#error "Invalid usage" +#endif + +// generated by parser_cl.py +#define clCreateFromGLBuffer clCreateFromGLBuffer_ +#define clCreateFromGLRenderbuffer clCreateFromGLRenderbuffer_ +#define clCreateFromGLTexture clCreateFromGLTexture_ +#define clCreateFromGLTexture2D clCreateFromGLTexture2D_ +#define clCreateFromGLTexture3D clCreateFromGLTexture3D_ +#define clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects_ +#define clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects_ +#define clGetGLContextInfoKHR clGetGLContextInfoKHR_ +#define clGetGLObjectInfo clGetGLObjectInfo_ +#define clGetGLTextureInfo clGetGLTextureInfo_ + +#if defined __APPLE__ +#include +#else +#include +#endif + +// generated by parser_cl.py +#undef clCreateFromGLBuffer +#define clCreateFromGLBuffer clCreateFromGLBuffer_pfn +#undef clCreateFromGLRenderbuffer +#define clCreateFromGLRenderbuffer clCreateFromGLRenderbuffer_pfn +#undef clCreateFromGLTexture +#define clCreateFromGLTexture clCreateFromGLTexture_pfn +#undef clCreateFromGLTexture2D +#define clCreateFromGLTexture2D clCreateFromGLTexture2D_pfn +#undef clCreateFromGLTexture3D +#define clCreateFromGLTexture3D clCreateFromGLTexture3D_pfn +#undef clEnqueueAcquireGLObjects +#define clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects_pfn +#undef clEnqueueReleaseGLObjects +#define clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects_pfn +#undef clGetGLContextInfoKHR +#define clGetGLContextInfoKHR clGetGLContextInfoKHR_pfn +#undef clGetGLObjectInfo +#define clGetGLObjectInfo clGetGLObjectInfo_pfn +#undef clGetGLTextureInfo +#define clGetGLTextureInfo clGetGLTextureInfo_pfn + +#ifdef cl_khr_gl_sharing + +// generated by parser_cl.py +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLBuffer)(cl_context, cl_mem_flags, cl_GLuint, int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLRenderbuffer)(cl_context, cl_mem_flags, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLTexture)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLTexture2D)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLTexture3D)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueAcquireGLObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReleaseGLObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLContextInfoKHR)(const cl_context_properties*, cl_gl_context_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLObjectInfo)(cl_mem, cl_gl_object_type*, cl_GLuint*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLTextureInfo)(cl_mem, cl_gl_texture_info, size_t, void*, size_t*); + +#endif // cl_khr_gl_sharing diff --git a/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp b/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp new file mode 100644 index 0000000..12f342b --- /dev/null +++ b/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp @@ -0,0 +1,42 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP +#error "Invalid usage" +#endif + +#ifdef cl_khr_gl_sharing + +// generated by parser_cl.py +#undef clCreateFromGLBuffer +#define clCreateFromGLBuffer clCreateFromGLBuffer_fn +inline cl_mem clCreateFromGLBuffer(cl_context p0, cl_mem_flags p1, cl_GLuint p2, int* p3) { return clCreateFromGLBuffer_pfn(p0, p1, p2, p3); } +#undef clCreateFromGLRenderbuffer +#define clCreateFromGLRenderbuffer clCreateFromGLRenderbuffer_fn +inline cl_mem clCreateFromGLRenderbuffer(cl_context p0, cl_mem_flags p1, cl_GLuint p2, cl_int* p3) { return clCreateFromGLRenderbuffer_pfn(p0, p1, p2, p3); } +#undef clCreateFromGLTexture +#define clCreateFromGLTexture clCreateFromGLTexture_fn +inline cl_mem clCreateFromGLTexture(cl_context p0, cl_mem_flags p1, cl_GLenum p2, cl_GLint p3, cl_GLuint p4, cl_int* p5) { return clCreateFromGLTexture_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateFromGLTexture2D +#define clCreateFromGLTexture2D clCreateFromGLTexture2D_fn +inline cl_mem clCreateFromGLTexture2D(cl_context p0, cl_mem_flags p1, cl_GLenum p2, cl_GLint p3, cl_GLuint p4, cl_int* p5) { return clCreateFromGLTexture2D_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateFromGLTexture3D +#define clCreateFromGLTexture3D clCreateFromGLTexture3D_fn +inline cl_mem clCreateFromGLTexture3D(cl_context p0, cl_mem_flags p1, cl_GLenum p2, cl_GLint p3, cl_GLuint p4, cl_int* p5) { return clCreateFromGLTexture3D_pfn(p0, p1, p2, p3, p4, p5); } +#undef clEnqueueAcquireGLObjects +#define clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects_fn +inline cl_int clEnqueueAcquireGLObjects(cl_command_queue p0, cl_uint p1, const cl_mem* p2, cl_uint p3, const cl_event* p4, cl_event* p5) { return clEnqueueAcquireGLObjects_pfn(p0, p1, p2, p3, p4, p5); } +#undef clEnqueueReleaseGLObjects +#define clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects_fn +inline cl_int clEnqueueReleaseGLObjects(cl_command_queue p0, cl_uint p1, const cl_mem* p2, cl_uint p3, const cl_event* p4, cl_event* p5) { return clEnqueueReleaseGLObjects_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetGLContextInfoKHR +#define clGetGLContextInfoKHR clGetGLContextInfoKHR_fn +inline cl_int clGetGLContextInfoKHR(const cl_context_properties* p0, cl_gl_context_info p1, size_t p2, void* p3, size_t* p4) { return clGetGLContextInfoKHR_pfn(p0, p1, p2, p3, p4); } +#undef clGetGLObjectInfo +#define clGetGLObjectInfo clGetGLObjectInfo_fn +inline cl_int clGetGLObjectInfo(cl_mem p0, cl_gl_object_type* p1, cl_GLuint* p2) { return clGetGLObjectInfo_pfn(p0, p1, p2); } +#undef clGetGLTextureInfo +#define clGetGLTextureInfo clGetGLTextureInfo_fn +inline cl_int clGetGLTextureInfo(cl_mem p0, cl_gl_texture_info p1, size_t p2, void* p3, size_t* p4) { return clGetGLTextureInfo_pfn(p0, p1, p2, p3, p4); } + +#endif // cl_khr_gl_sharing diff --git a/include/opencv2/core/opencl/runtime/opencl_clamdblas.hpp b/include/opencv2/core/opencl/runtime/opencl_clamdblas.hpp new file mode 100644 index 0000000..2ad8ac0 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_clamdblas.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the OpenCV Foundation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP +#define OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP + +#ifdef HAVE_CLAMDBLAS + +#include "opencl_core.hpp" + +#include "autogenerated/opencl_clamdblas.hpp" + +#endif // HAVE_CLAMDBLAS + +#endif // OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_clamdfft.hpp b/include/opencv2/core/opencl/runtime/opencl_clamdfft.hpp new file mode 100644 index 0000000..a328f72 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_clamdfft.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the OpenCV Foundation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP +#define OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP + +#ifdef HAVE_CLAMDFFT + +#include "opencl_core.hpp" + +#include "autogenerated/opencl_clamdfft.hpp" + +#endif // HAVE_CLAMDFFT + +#endif // OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_core.hpp b/include/opencv2/core/opencl/runtime/opencl_core.hpp new file mode 100644 index 0000000..0404b31 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_core.hpp @@ -0,0 +1,84 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the OpenCV Foundation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP + +#ifdef HAVE_OPENCL + +#ifndef CL_RUNTIME_EXPORT +#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_CORE_SHARED)) && (defined _WIN32 || defined WINCE) && \ + !(defined(__OPENCV_BUILD) && defined(OPENCV_MODULE_IS_PART_OF_WORLD)) +#define CL_RUNTIME_EXPORT __declspec(dllimport) +#else +#define CL_RUNTIME_EXPORT +#endif +#endif + +#ifdef HAVE_OPENCL_SVM +#define clSVMAlloc clSVMAlloc_ +#define clSVMFree clSVMFree_ +#define clSetKernelArgSVMPointer clSetKernelArgSVMPointer_ +#define clSetKernelExecInfo clSetKernelExecInfo_ +#define clEnqueueSVMFree clEnqueueSVMFree_ +#define clEnqueueSVMMemcpy clEnqueueSVMMemcpy_ +#define clEnqueueSVMMemFill clEnqueueSVMMemFill_ +#define clEnqueueSVMMap clEnqueueSVMMap_ +#define clEnqueueSVMUnmap clEnqueueSVMUnmap_ +#endif + +#include "autogenerated/opencl_core.hpp" + +#ifndef CL_DEVICE_DOUBLE_FP_CONFIG +#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 +#endif + +#ifndef CL_DEVICE_HALF_FP_CONFIG +#define CL_DEVICE_HALF_FP_CONFIG 0x1033 +#endif + +#ifndef CL_VERSION_1_2 +#define CV_REQUIRE_OPENCL_1_2_ERROR CV_Error(cv::Error::OpenCLApiCallError, "OpenCV compiled without OpenCL v1.2 support, so we can't use functionality from OpenCL v1.2") +#endif + +#endif // HAVE_OPENCL + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp b/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp new file mode 100644 index 0000000..38fcae9 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp @@ -0,0 +1,47 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the OpenCV Foundation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP + +#include "autogenerated/opencl_core_wrappers.hpp" + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_gl.hpp b/include/opencv2/core/opencl/runtime/opencl_gl.hpp new file mode 100644 index 0000000..659c7d8 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_gl.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the OpenCV Foundation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP + +#if defined HAVE_OPENCL && defined HAVE_OPENGL + +#include "opencl_core.hpp" + +#include "autogenerated/opencl_gl.hpp" + +#endif // defined HAVE_OPENCL && defined HAVE_OPENGL + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp b/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp new file mode 100644 index 0000000..9700004 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp @@ -0,0 +1,47 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the OpenCV Foundation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP + +#include "autogenerated/opencl_gl_wrappers.hpp" + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp b/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp new file mode 100644 index 0000000..9636b19 --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp @@ -0,0 +1,48 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP + +#if defined(HAVE_OPENCL_SVM) +#include "opencl_core.hpp" + +#include "opencl_svm_definitions.hpp" + +#undef clSVMAlloc +#define clSVMAlloc clSVMAlloc_pfn +#undef clSVMFree +#define clSVMFree clSVMFree_pfn +#undef clSetKernelArgSVMPointer +#define clSetKernelArgSVMPointer clSetKernelArgSVMPointer_pfn +#undef clSetKernelExecInfo +//#define clSetKernelExecInfo clSetKernelExecInfo_pfn +#undef clEnqueueSVMFree +//#define clEnqueueSVMFree clEnqueueSVMFree_pfn +#undef clEnqueueSVMMemcpy +#define clEnqueueSVMMemcpy clEnqueueSVMMemcpy_pfn +#undef clEnqueueSVMMemFill +#define clEnqueueSVMMemFill clEnqueueSVMMemFill_pfn +#undef clEnqueueSVMMap +#define clEnqueueSVMMap clEnqueueSVMMap_pfn +#undef clEnqueueSVMUnmap +#define clEnqueueSVMUnmap clEnqueueSVMUnmap_pfn + +extern CL_RUNTIME_EXPORT void* (CL_API_CALL *clSVMAlloc)(cl_context context, cl_svm_mem_flags flags, size_t size, unsigned int alignment); +extern CL_RUNTIME_EXPORT void (CL_API_CALL *clSVMFree)(cl_context context, void* svm_pointer); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clSetKernelArgSVMPointer)(cl_kernel kernel, cl_uint arg_index, const void* arg_value); +//extern CL_RUNTIME_EXPORT void* (CL_API_CALL *clSetKernelExecInfo)(cl_kernel kernel, cl_kernel_exec_info param_name, size_t param_value_size, const void* param_value); +//extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMFree)(cl_command_queue command_queue, cl_uint num_svm_pointers, void* svm_pointers[], +// void (CL_CALLBACK *pfn_free_func)(cl_command_queue queue, cl_uint num_svm_pointers, void* svm_pointers[], void* user_data), void* user_data, +// cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMMemcpy)(cl_command_queue command_queue, cl_bool blocking_copy, void* dst_ptr, const void* src_ptr, size_t size, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMMemFill)(cl_command_queue command_queue, void* svm_ptr, const void* pattern, size_t pattern_size, size_t size, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMMap)(cl_command_queue command_queue, cl_bool blocking_map, cl_map_flags map_flags, void* svm_ptr, size_t size, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMUnmap)(cl_command_queue command_queue, void* svm_ptr, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); + +#endif // HAVE_OPENCL_SVM + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp b/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp new file mode 100644 index 0000000..97c927b --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp @@ -0,0 +1,42 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP + +#if defined(HAVE_OPENCL_SVM) +#if defined(CL_VERSION_2_0) + +// OpenCL 2.0 contains SVM definitions + +#else + +typedef cl_bitfield cl_device_svm_capabilities; +typedef cl_bitfield cl_svm_mem_flags; +typedef cl_uint cl_kernel_exec_info; + +// +// TODO Add real values after OpenCL 2.0 release +// + +#ifndef CL_DEVICE_SVM_CAPABILITIES +#define CL_DEVICE_SVM_CAPABILITIES 0x1053 + +#define CL_DEVICE_SVM_COARSE_GRAIN_BUFFER (1 << 0) +#define CL_DEVICE_SVM_FINE_GRAIN_BUFFER (1 << 1) +#define CL_DEVICE_SVM_FINE_GRAIN_SYSTEM (1 << 2) +#define CL_DEVICE_SVM_ATOMICS (1 << 3) +#endif + +#ifndef CL_MEM_SVM_FINE_GRAIN_BUFFER +#define CL_MEM_SVM_FINE_GRAIN_BUFFER (1 << 10) +#endif + +#ifndef CL_MEM_SVM_ATOMICS +#define CL_MEM_SVM_ATOMICS (1 << 11) +#endif + + +#endif // CL_VERSION_2_0 +#endif // HAVE_OPENCL_SVM + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP diff --git a/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp b/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp new file mode 100644 index 0000000..497bc3d --- /dev/null +++ b/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp @@ -0,0 +1,166 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP + +#if defined(HAVE_OPENCL_SVM) +#include "opencl_core.hpp" + +#ifndef CL_DEVICE_SVM_CAPABILITIES_AMD +// +// Part of the file is an extract from the cl_ext.h file from AMD APP SDK package. +// Below is the original copyright. +// +/******************************************************************************* + * Copyright (c) 2008-2013 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/******************************************* + * Shared Virtual Memory (SVM) extension + *******************************************/ +typedef cl_bitfield cl_device_svm_capabilities_amd; +typedef cl_bitfield cl_svm_mem_flags_amd; +typedef cl_uint cl_kernel_exec_info_amd; + +/* cl_device_info */ +#define CL_DEVICE_SVM_CAPABILITIES_AMD 0x1053 +#define CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT_AMD 0x1054 + +/* cl_device_svm_capabilities_amd */ +#define CL_DEVICE_SVM_COARSE_GRAIN_BUFFER_AMD (1 << 0) +#define CL_DEVICE_SVM_FINE_GRAIN_BUFFER_AMD (1 << 1) +#define CL_DEVICE_SVM_FINE_GRAIN_SYSTEM_AMD (1 << 2) +#define CL_DEVICE_SVM_ATOMICS_AMD (1 << 3) + +/* cl_svm_mem_flags_amd */ +#define CL_MEM_SVM_FINE_GRAIN_BUFFER_AMD (1 << 10) +#define CL_MEM_SVM_ATOMICS_AMD (1 << 11) + +/* cl_mem_info */ +#define CL_MEM_USES_SVM_POINTER_AMD 0x1109 + +/* cl_kernel_exec_info_amd */ +#define CL_KERNEL_EXEC_INFO_SVM_PTRS_AMD 0x11B6 +#define CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM_AMD 0x11B7 + +/* cl_command_type */ +#define CL_COMMAND_SVM_FREE_AMD 0x1209 +#define CL_COMMAND_SVM_MEMCPY_AMD 0x120A +#define CL_COMMAND_SVM_MEMFILL_AMD 0x120B +#define CL_COMMAND_SVM_MAP_AMD 0x120C +#define CL_COMMAND_SVM_UNMAP_AMD 0x120D + +typedef CL_API_ENTRY void* +(CL_API_CALL * clSVMAllocAMD_fn)( + cl_context /* context */, + cl_svm_mem_flags_amd /* flags */, + size_t /* size */, + unsigned int /* alignment */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY void +(CL_API_CALL * clSVMFreeAMD_fn)( + cl_context /* context */, + void* /* svm_pointer */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMFreeAMD_fn)( + cl_command_queue /* command_queue */, + cl_uint /* num_svm_pointers */, + void** /* svm_pointers */, + void (CL_CALLBACK *)( /*pfn_free_func*/ + cl_command_queue /* queue */, + cl_uint /* num_svm_pointers */, + void** /* svm_pointers */, + void* /* user_data */), + void* /* user_data */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMMemcpyAMD_fn)( + cl_command_queue /* command_queue */, + cl_bool /* blocking_copy */, + void* /* dst_ptr */, + const void* /* src_ptr */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMMemFillAMD_fn)( + cl_command_queue /* command_queue */, + void* /* svm_ptr */, + const void* /* pattern */, + size_t /* pattern_size */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMMapAMD_fn)( + cl_command_queue /* command_queue */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + void* /* svm_ptr */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMUnmapAMD_fn)( + cl_command_queue /* command_queue */, + void* /* svm_ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clSetKernelArgSVMPointerAMD_fn)( + cl_kernel /* kernel */, + cl_uint /* arg_index */, + const void * /* arg_value */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clSetKernelExecInfoAMD_fn)( + cl_kernel /* kernel */, + cl_kernel_exec_info_amd /* param_name */, + size_t /* param_value_size */, + const void * /* param_value */ +) CL_EXT_SUFFIX__VERSION_1_2; + +#endif + +#endif // HAVE_OPENCL_SVM + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP diff --git a/include/opencv2/core/opengl.hpp b/include/opencv2/core/opengl.hpp index 15c635c..a6288be 100644 --- a/include/opencv2/core/opengl.hpp +++ b/include/opencv2/core/opengl.hpp @@ -40,14 +40,15 @@ // //M*/ -#ifndef __OPENCV_CORE_OPENGL_HPP__ -#define __OPENCV_CORE_OPENGL_HPP__ +#ifndef OPENCV_CORE_OPENGL_HPP +#define OPENCV_CORE_OPENGL_HPP #ifndef __cplusplus # error opengl.hpp header must be compiled as C++ #endif #include "opencv2/core.hpp" +#include "ocl.hpp" namespace cv { namespace ogl { @@ -244,7 +245,7 @@ public: /** @brief Maps OpenGL buffer to CUDA device memory. - This operatation doesn't copy data. Several buffer objects can be mapped to CUDA memory at a time. + This operation doesn't copy data. Several buffer objects can be mapped to CUDA memory at a time. A mapped data store must be unmapped with ogl::Buffer::unmapDevice before its buffer object is used. */ @@ -511,15 +512,57 @@ CV_EXPORTS void render(const Arrays& arr, int mode = POINTS, Scalar color = Scal */ CV_EXPORTS void render(const Arrays& arr, InputArray indices, int mode = POINTS, Scalar color = Scalar::all(255)); -//! @} core_opengl +/////////////////// CL-GL Interoperability Functions /////////////////// +namespace ocl { +using namespace cv::ocl; + +// TODO static functions in the Context class +/** @brief Creates OpenCL context from GL. +@return Returns reference to OpenCL Context + */ +CV_EXPORTS Context& initializeContextFromGL(); + +} // namespace cv::ogl::ocl + +/** @brief Converts InputArray to Texture2D object. +@param src - source InputArray. +@param texture - destination Texture2D object. + */ +CV_EXPORTS void convertToGLTexture2D(InputArray src, Texture2D& texture); + +/** @brief Converts Texture2D object to OutputArray. +@param texture - source Texture2D object. +@param dst - destination OutputArray. + */ +CV_EXPORTS void convertFromGLTexture2D(const Texture2D& texture, OutputArray dst); + +/** @brief Maps Buffer object to process on CL side (convert to UMat). + +Function creates CL buffer from GL one, and then constructs UMat that can be used +to process buffer data with OpenCV functions. Note that in current implementation +UMat constructed this way doesn't own corresponding GL buffer object, so it is +the user responsibility to close down CL/GL buffers relationships by explicitly +calling unmapGLBuffer() function. +@param buffer - source Buffer object. +@param accessFlags - data access flags (ACCESS_READ|ACCESS_WRITE). +@return Returns UMat object + */ +CV_EXPORTS UMat mapGLBuffer(const Buffer& buffer, int accessFlags = ACCESS_READ|ACCESS_WRITE); + +/** @brief Unmaps Buffer object (releases UMat, previously mapped from Buffer). + +Function must be called explicitly by the user for each UMat previously constructed +by the call to mapGLBuffer() function. +@param u - source UMat, created by mapGLBuffer(). + */ +CV_EXPORTS void unmapGLBuffer(UMat& u); + +//! @} }} // namespace cv::ogl namespace cv { namespace cuda { -//! @addtogroup cuda -//! @{ - /** @brief Sets a CUDA device and initializes it for the current thread with OpenGL interoperability. This function should be explicitly called after OpenGL context creation and before any CUDA calls. @@ -528,8 +571,6 @@ This function should be explicitly called after OpenGL context creation and befo */ CV_EXPORTS void setGlDevice(int device = 0); -//! @} - }} //! @cond IGNORED @@ -681,4 +722,4 @@ bool cv::ogl::Arrays::empty() const //! @endcond -#endif /* __OPENCV_CORE_OPENGL_HPP__ */ +#endif /* OPENCV_CORE_OPENGL_HPP */ diff --git a/include/opencv2/core/operations.hpp b/include/opencv2/core/operations.hpp index bced1a7..d706d96 100644 --- a/include/opencv2/core/operations.hpp +++ b/include/opencv2/core/operations.hpp @@ -42,8 +42,8 @@ // //M*/ -#ifndef __OPENCV_CORE_OPERATIONS_HPP__ -#define __OPENCV_CORE_OPERATIONS_HPP__ +#ifndef OPENCV_CORE_OPERATIONS_HPP +#define OPENCV_CORE_OPERATIONS_HPP #ifndef __cplusplus # error operations.hpp header must be compiled as C++ @@ -61,29 +61,44 @@ namespace cv namespace internal { -template struct Matx_FastInvOp +template struct Matx_FastInvOp { - bool operator()(const Matx<_Tp, m, m>& a, Matx<_Tp, m, m>& b, int method) const + bool operator()(const Matx<_Tp, m, n>& a, Matx<_Tp, n, m>& b, int method) const { - Matx<_Tp, m, m> temp = a; - - // assume that b is all 0's on input => make it a unity matrix - for( int i = 0; i < m; i++ ) - b(i, i) = (_Tp)1; - - if( method == DECOMP_CHOLESKY ) - return Cholesky(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m); - - return LU(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m) != 0; + return invert(a, b, method) != 0; } }; -template struct Matx_FastInvOp<_Tp, 2> +template struct Matx_FastInvOp<_Tp, m, m> { - bool operator()(const Matx<_Tp, 2, 2>& a, Matx<_Tp, 2, 2>& b, int) const + bool operator()(const Matx<_Tp, m, m>& a, Matx<_Tp, m, m>& b, int method) const { - _Tp d = determinant(a); - if( d == 0 ) + if (method == DECOMP_LU || method == DECOMP_CHOLESKY) + { + Matx<_Tp, m, m> temp = a; + + // assume that b is all 0's on input => make it a unity matrix + for (int i = 0; i < m; i++) + b(i, i) = (_Tp)1; + + if (method == DECOMP_CHOLESKY) + return Cholesky(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m); + + return LU(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m) != 0; + } + else + { + return invert(a, b, method) != 0; + } + } +}; + +template struct Matx_FastInvOp<_Tp, 2, 2> +{ + bool operator()(const Matx<_Tp, 2, 2>& a, Matx<_Tp, 2, 2>& b, int /*method*/) const + { + _Tp d = (_Tp)determinant(a); + if (d == 0) return false; d = 1/d; b(1,1) = a(0,0)*d; @@ -94,12 +109,12 @@ template struct Matx_FastInvOp<_Tp, 2> } }; -template struct Matx_FastInvOp<_Tp, 3> +template struct Matx_FastInvOp<_Tp, 3, 3> { - bool operator()(const Matx<_Tp, 3, 3>& a, Matx<_Tp, 3, 3>& b, int) const + bool operator()(const Matx<_Tp, 3, 3>& a, Matx<_Tp, 3, 3>& b, int /*method*/) const { _Tp d = (_Tp)determinant(a); - if( d == 0 ) + if (d == 0) return false; d = 1/d; b(0,0) = (a(1,1) * a(2,2) - a(1,2) * a(2,1)) * d; @@ -118,27 +133,43 @@ template struct Matx_FastInvOp<_Tp, 3> }; -template struct Matx_FastSolveOp +template struct Matx_FastSolveOp +{ + bool operator()(const Matx<_Tp, m, l>& a, const Matx<_Tp, m, n>& b, + Matx<_Tp, l, n>& x, int method) const + { + return cv::solve(a, b, x, method); + } +}; + +template struct Matx_FastSolveOp<_Tp, m, m, n> { bool operator()(const Matx<_Tp, m, m>& a, const Matx<_Tp, m, n>& b, Matx<_Tp, m, n>& x, int method) const { - Matx<_Tp, m, m> temp = a; - x = b; - if( method == DECOMP_CHOLESKY ) - return Cholesky(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n); + if (method == DECOMP_LU || method == DECOMP_CHOLESKY) + { + Matx<_Tp, m, m> temp = a; + x = b; + if( method == DECOMP_CHOLESKY ) + return Cholesky(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n); - return LU(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n) != 0; + return LU(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n) != 0; + } + else + { + return cv::solve(a, b, x, method); + } } }; -template struct Matx_FastSolveOp<_Tp, 2, 1> +template struct Matx_FastSolveOp<_Tp, 2, 2, 1> { bool operator()(const Matx<_Tp, 2, 2>& a, const Matx<_Tp, 2, 1>& b, Matx<_Tp, 2, 1>& x, int) const { - _Tp d = determinant(a); - if( d == 0 ) + _Tp d = (_Tp)determinant(a); + if (d == 0) return false; d = 1/d; x(0) = (b(0)*a(1,1) - b(1)*a(0,1))*d; @@ -147,13 +178,13 @@ template struct Matx_FastSolveOp<_Tp, 2, 1> } }; -template struct Matx_FastSolveOp<_Tp, 3, 1> +template struct Matx_FastSolveOp<_Tp, 3, 3, 1> { bool operator()(const Matx<_Tp, 3, 3>& a, const Matx<_Tp, 3, 1>& b, Matx<_Tp, 3, 1>& x, int) const { _Tp d = (_Tp)determinant(a); - if( d == 0 ) + if (d == 0) return false; d = 1/d; x(0) = d*(b(0)*(a(1,1)*a(2,2) - a(1,2)*a(2,1)) - @@ -193,15 +224,8 @@ template inline Matx<_Tp, n, m> Matx<_Tp, m, n>::inv(int method, bool *p_is_ok /*= NULL*/) const { Matx<_Tp, n, m> b; - bool ok; - if( method == DECOMP_LU || method == DECOMP_CHOLESKY ) - ok = cv::internal::Matx_FastInvOp<_Tp, m>()(*this, b, method); - else - { - Mat A(*this, false), B(b, false); - ok = (invert(A, B, method) != 0); - } - if( NULL != p_is_ok ) { *p_is_ok = ok; } + bool ok = cv::internal::Matx_FastInvOp<_Tp, m, n>()(*this, b, method); + if (p_is_ok) *p_is_ok = ok; return ok ? b : Matx<_Tp, n, m>::zeros(); } @@ -209,15 +233,7 @@ template template inline Matx<_Tp, n, l> Matx<_Tp, m, n>::solve(const Matx<_Tp, m, l>& rhs, int method) const { Matx<_Tp, n, l> x; - bool ok; - if( method == DECOMP_LU || method == DECOMP_CHOLESKY ) - ok = cv::internal::Matx_FastSolveOp<_Tp, m, l>()(*this, rhs, x, method); - else - { - Mat A(*this, false), B(rhs, false), X(x, false); - ok = cv::solve(A, B, X, method); - } - + bool ok = cv::internal::Matx_FastSolveOp<_Tp, m, n, l>()(*this, rhs, x, method); return ok ? x : Matx<_Tp, n, l>::zeros(); } @@ -349,6 +365,8 @@ inline int RNG::uniform(int a, int b) { return a == b ? a : (int)(next( inline float RNG::uniform(float a, float b) { return ((float)*this)*(b - a) + a; } inline double RNG::uniform(double a, double b) { return ((double)*this)*(b - a) + a; } +inline bool RNG::operator ==(const RNG& other) const { return state == other.state; } + inline unsigned RNG::next() { state = (uint64)(unsigned)state* /*CV_RNG_COEFF*/ 4164903690U + (unsigned)(state >> 32); @@ -363,6 +381,12 @@ template static inline _Tp randu() ///////////////////////////////// Formatted string generation ///////////////////////////////// +/** @brief Returns a text string formatted using the printf-like expression. + +The function acts like sprintf but forms and returns an STL string. It can be used to form an error +message in the Exception constructor. +@param fmt printf-compatible formatting specifiers. + */ CV_EXPORTS String format( const char* fmt, ... ); ///////////////////////////////// Formatted output of cv::Mat ///////////////////////////////// diff --git a/include/opencv2/core/optim.hpp b/include/opencv2/core/optim.hpp index 23e2155..c4729a9 100644 --- a/include/opencv2/core/optim.hpp +++ b/include/opencv2/core/optim.hpp @@ -39,8 +39,8 @@ // //M*/ -#ifndef __OPENCV_OPTIM_HPP__ -#define __OPENCV_OPTIM_HPP__ +#ifndef OPENCV_OPTIM_HPP +#define OPENCV_OPTIM_HPP #include "opencv2/core.hpp" @@ -73,7 +73,7 @@ public: /** @brief Getter for the optimized function. The optimized function is represented by Function interface, which requires derivatives to - implement the sole method calc(double*) to evaluate the function. + implement the calc(double*) and getDim() methods to evaluate the function. @return Smart-pointer to an object that implements Function interface - it represents the function that is being optimized. It can be empty, if no function was given so far. @@ -115,7 +115,7 @@ public: always sensible) will be used. @param x The initial point, that will become a centroid of an initial simplex. After the algorithm - will terminate, it will be setted to the point where the algorithm stops, the point of possible + will terminate, it will be set to the point where the algorithm stops, the point of possible minimum. @return The value of a function at the point found. */ @@ -288,7 +288,7 @@ Bland's rule is used to prevent cy contain 32- or 64-bit floating point numbers. As a convenience, column-vector may be also submitted, in the latter case it is understood to correspond to \f$c^T\f$. @param Constr `m`-by-`n+1` matrix, whose rightmost column corresponds to \f$b\f$ in formulation above -and the remaining to \f$A\f$. It should containt 32- or 64-bit floating point numbers. +and the remaining to \f$A\f$. It should contain 32- or 64-bit floating point numbers. @param z The solution will be returned here as a column-vector - it corresponds to \f$c\f$ in the formulation above. It will contain 64-bit floating point numbers. @return One of cv::SolveLPResult diff --git a/include/opencv2/core/ovx.hpp b/include/opencv2/core/ovx.hpp new file mode 100644 index 0000000..8bb7d54 --- /dev/null +++ b/include/opencv2/core/ovx.hpp @@ -0,0 +1,28 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2016, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. + +// OpenVX related definitions and declarations + +#pragma once +#ifndef OPENCV_OVX_HPP +#define OPENCV_OVX_HPP + +#include "cvdef.h" + +namespace cv +{ +/// Check if use of OpenVX is possible +CV_EXPORTS_W bool haveOpenVX(); + +/// Check if use of OpenVX is enabled +CV_EXPORTS_W bool useOpenVX(); + +/// Enable/disable use of OpenVX +CV_EXPORTS_W void setUseOpenVX(bool flag); +} // namespace cv + +#endif // OPENCV_OVX_HPP diff --git a/include/opencv2/core/persistence.hpp b/include/opencv2/core/persistence.hpp index 17686dd..126393f 100644 --- a/include/opencv2/core/persistence.hpp +++ b/include/opencv2/core/persistence.hpp @@ -41,8 +41,13 @@ // //M*/ -#ifndef __OPENCV_CORE_PERSISTENCE_HPP__ -#define __OPENCV_CORE_PERSISTENCE_HPP__ +#ifndef OPENCV_CORE_PERSISTENCE_HPP +#define OPENCV_CORE_PERSISTENCE_HPP + +#ifndef CV_DOXYGEN +/// Define to support persistence legacy formats +#define CV__LEGACY_PERSISTENCE +#endif #ifndef __cplusplus # error persistence.hpp header must be compiled as C++ @@ -57,8 +62,9 @@ Several functions that are described below take CvFileStorage\* as inputs and al save or to load hierarchical collections that consist of scalar values, standard CXCore objects (such as matrices, sequences, graphs), and user-defined objects. -OpenCV can read and write data in XML () or YAML () -formats. Below is an example of 3x3 floating-point identity matrix A, stored in XML and YAML files +OpenCV can read and write data in XML (), YAML () or +JSON () formats. Below is an example of 3x3 floating-point identity matrix A, +stored in XML and YAML files using CXCore functions: XML: @code{.xml} @@ -85,10 +91,13 @@ As it can be seen from the examples, XML uses nested tags to represent hierarchy indentation for that purpose (similar to the Python programming language). The same functions can read and write data in both formats; the particular format is determined by -the extension of the opened file, ".xml" for XML files and ".yml" or ".yaml" for YAML. +the extension of the opened file, ".xml" for XML files, ".yml" or ".yaml" for YAML and ".json" for +JSON. */ typedef struct CvFileStorage CvFileStorage; typedef struct CvFileNode CvFileNode; +typedef struct CvMat CvMat; +typedef struct CvMatND CvMatND; //! @} core_c @@ -99,20 +108,20 @@ namespace cv { /** @addtogroup core_xml -XML/YAML file storages. {#xml_storage} +XML/YAML/JSON file storages. {#xml_storage} ======================= Writing to a file storage. -------------------------- -You can store and then restore various OpenCV data structures to/from XML () -or YAML () formats. Also, it is possible store and load arbitrarily complex -data structures, which include OpenCV data structures, as well as primitive data types (integer and -floating-point numbers and text strings) as their elements. +You can store and then restore various OpenCV data structures to/from XML (), +YAML () or JSON () formats. Also, it is possible to store +and load arbitrarily complex data structures, which include OpenCV data structures, as well as +primitive data types (integer and floating-point numbers and text strings) as their elements. -Use the following procedure to write something to XML or YAML: +Use the following procedure to write something to XML, YAML or JSON: -# Create new FileStorage and open it for writing. It can be done with a single call to FileStorage::FileStorage constructor that takes a filename, or you can use the default constructor -and then call FileStorage::open. Format of the file (XML or YAML) is determined from the filename -extension (".xml" and ".yml"/".yaml", respectively) +and then call FileStorage::open. Format of the file (XML, YAML or JSON) is determined from the filename +extension (".xml", ".yml"/".yaml" and ".json", respectively) -# Write all the data you want using the streaming operator `<<`, just like in the case of STL streams. -# Close the file using FileStorage::release. FileStorage destructor also closes the file. @@ -151,7 +160,7 @@ Here is an example: return 0; } @endcode -The sample above stores to XML and integer, text string (calibration date), 2 matrices, and a custom +The sample above stores to YML an integer, a text string (calibration date), 2 matrices, and a custom structure "feature", which includes feature coordinates and LBP (local binary pattern) value. Here is output of the sample: @code{.yaml} @@ -175,19 +184,19 @@ features: - { x:344, y:158, lbp:[ 1, 1, 0, 0, 0, 0, 1, 0 ] } @endcode -As an exercise, you can replace ".yml" with ".xml" in the sample above and see, how the +As an exercise, you can replace ".yml" with ".xml" or ".json" in the sample above and see, how the corresponding XML file will look like. Several things can be noted by looking at the sample code and the output: -- The produced YAML (and XML) consists of heterogeneous collections that can be nested. There are 2 - types of collections: named collections (mappings) and unnamed collections (sequences). In mappings +- The produced YAML (and XML/JSON) consists of heterogeneous collections that can be nested. There are + 2 types of collections: named collections (mappings) and unnamed collections (sequences). In mappings each element has a name and is accessed by name. This is similar to structures and std::map in C/C++ and dictionaries in Python. In sequences elements do not have names, they are accessed by indices. This is similar to arrays and std::vector in C/C++ and lists, tuples in Python. "Heterogeneous" means that elements of each single collection can have different types. - Top-level collection in YAML/XML is a mapping. Each matrix is stored as a mapping, and the matrix + Top-level collection in YAML/XML/JSON is a mapping. Each matrix is stored as a mapping, and the matrix elements are stored as a sequence. Then, there is a sequence of features, where each feature is represented a mapping, and lbp value in a nested sequence. @@ -203,7 +212,7 @@ Several things can be noted by looking at the sample code and the output: - To write a sequence, you first write the special string `[`, then write the elements, then write the closing `]`. -- In YAML (but not XML), mappings and sequences can be written in a compact Python-like inline +- In YAML/JSON (but not XML), mappings and sequences can be written in a compact Python-like inline form. In the sample above matrix elements, as well as each feature, including its lbp value, is stored in such inline form. To store a mapping/sequence in a compact form, put `:` after the opening character, e.g. use `{:` instead of `{` and `[:` instead of `[`. When the @@ -211,7 +220,7 @@ Several things can be noted by looking at the sample code and the output: Reading data from a file storage. --------------------------------- -To read the previously written XML or YAML file, do the following: +To read the previously written XML, YAML or JSON file, do the following: -# Open the file storage using FileStorage::FileStorage constructor or FileStorage::open method. In the current implementation the whole file is parsed and the whole representation of file storage is built in memory as a hierarchy of file nodes (see FileNode) @@ -278,12 +287,12 @@ element is a structure of 2 integers, followed by a single-precision floating-po equivalent notations of the above specification are `iif`, `2i1f` and so forth. Other examples: `u` means that the array consists of bytes, and `2d` means the array consists of pairs of doubles. -@see @ref filestorage.cpp +@see @ref samples/cpp/filestorage.cpp */ //! @{ -/** @example filestorage.cpp +/** @example samples/cpp/filestorage.cpp A complete example using the FileStorage interface */ @@ -292,8 +301,8 @@ A complete example using the FileStorage interface class CV_EXPORTS FileNode; class CV_EXPORTS FileNodeIterator; -/** @brief XML/YAML file storage class that encapsulates all the information necessary for writing or reading -data to/from a file. +/** @brief XML/YAML/JSON file storage class that encapsulates all the information necessary for writing or +reading data to/from a file. */ class CV_EXPORTS_W FileStorage { @@ -309,7 +318,11 @@ public: FORMAT_MASK = (7<<3), //!< mask for format flags FORMAT_AUTO = 0, //!< flag, auto format FORMAT_XML = (1<<3), //!< flag, XML format - FORMAT_YAML = (2<<3) //!< flag, YAML format + FORMAT_YAML = (2<<3), //!< flag, YAML format + FORMAT_JSON = (3<<3), //!< flag, JSON format + + BASE64 = 64, //!< flag, write rawdata in Base64 by default. (consider using WRITE_BASE64) + WRITE_BASE64 = BASE64 | WRITE, //!< flag, enable both WRITE and BASE64 }; enum { @@ -327,16 +340,9 @@ public: CV_WRAP FileStorage(); /** @overload - @param source Name of the file to open or the text string to read the data from. Extension of the - file (.xml or .yml/.yaml) determines its format (XML or YAML respectively). Also you can append .gz - to work with compressed files, for example myHugeMatrix.xml.gz. If both FileStorage::WRITE and - FileStorage::MEMORY flags are specified, source is used just to specify the output file format (e.g. - mydata.xml, .yml etc.). - @param flags Mode of operation. See FileStorage::Mode - @param encoding Encoding of the file. Note that UTF-16 XML encoding is not supported currently and - you should use 8-bit encoding instead of it. + @copydoc open() */ - CV_WRAP FileStorage(const String& source, int flags, const String& encoding=String()); + CV_WRAP FileStorage(const String& filename, int flags, const String& encoding=String()); /** @overload */ FileStorage(CvFileStorage* fs, bool owning=true); @@ -349,10 +355,12 @@ public: See description of parameters in FileStorage::FileStorage. The method calls FileStorage::release before opening the file. @param filename Name of the file to open or the text string to read the data from. - Extension of the file (.xml or .yml/.yaml) determines its format (XML or YAML respectively). - Also you can append .gz to work with compressed files, for example myHugeMatrix.xml.gz. If both + Extension of the file (.xml, .yml/.yaml or .json) determines its format (XML, YAML or JSON + respectively). Also you can append .gz to work with compressed files, for example myHugeMatrix.xml.gz. If both FileStorage::WRITE and FileStorage::MEMORY flags are specified, source is used just to specify - the output file format (e.g. mydata.xml, .yml etc.). + the output file format (e.g. mydata.xml, .yml etc.). A file name can also contain parameters. + You can use this format, "*?base64" (e.g. "file.json?base64" (case sensitive)), as an alternative to + FileStorage::BASE64 flag. @param flags Mode of operation. One of FileStorage::Mode @param encoding Encoding of the file. Note that UTF-16 XML encoding is not supported currently and you should use 8-bit encoding instead of it. @@ -398,7 +406,7 @@ public: FileNode operator[](const String& nodename) const; /** @overload */ - CV_WRAP FileNode operator[](const char* nodename) const; + CV_WRAP_AS(getNode) FileNode operator[](const char* nodename) const; /** @brief Returns the obsolete C FileStorage structure. @returns Pointer to the underlying C FileStorage structure @@ -425,12 +433,40 @@ public: */ void writeObj( const String& name, const void* obj ); + /** + * @brief Simplified writing API to use with bindings. + * @param name Name of the written object + * @param val Value of the written object + */ + CV_WRAP void write(const String& name, int val); + /// @overload + CV_WRAP void write(const String& name, double val); + /// @overload + CV_WRAP void write(const String& name, const String& val); + /// @overload + CV_WRAP void write(const String& name, InputArray val); + + /** @brief Writes a comment. + + The function writes a comment into file storage. The comments are skipped when the storage is read. + @param comment The written comment, single-line or multi-line + @param append If true, the function tries to put the comment at the end of current line. + Else if the comment is multi-line, or if it does not fit at the end of the current + line, the comment starts a new line. + */ + CV_WRAP void writeComment(const String& comment, bool append = false); + /** @brief Returns the normalized object name for the specified name of a file. @param filename Name of a file @returns The normalized object name. */ static String getDefaultObjectName(const String& filename); + /** @brief Returns the current format. + * @returns The current format, see FileStorage::Mode + */ + CV_WRAP int getFormat() const; + Ptr fs; //!< the underlying C FileStorage structure String elname; //!< the currently written element std::vector structs; //!< the stack of written structures @@ -443,7 +479,7 @@ template<> CV_EXPORTS void DefaultDeleter::operator ()(CvFileStor The node is used to store each and every element of the file storage opened for reading. When XML/YAML file is read, it is first parsed and stored in the memory as a hierarchical collection of -nodes. Each node can be a “leaf†that is contain a single number or a string, or be a collection of +nodes. Each node can be a "leaf" that is contain a single number or a string, or be a collection of other nodes. There can be named collections (mappings) where each element has a name and it is accessed by a name, and ordered collections (sequences) where elements do not have names but rather accessed by index. Type of the file node can be determined using FileNode::type method. @@ -499,12 +535,17 @@ public: /** @overload @param nodename Name of an element in the mapping node. */ - CV_WRAP FileNode operator[](const char* nodename) const; + CV_WRAP_AS(getNode) FileNode operator[](const char* nodename) const; /** @overload @param i Index of an element in the sequence node. */ - CV_WRAP FileNode operator[](int i) const; + CV_WRAP_AS(at) FileNode operator[](int i) const; + + /** @brief Returns keys of a mapping node. + @returns Keys of a mapping node. + */ + CV_WRAP std::vector keys() const; /** @brief Returns type of the node. @returns Type of the node. See FileNode::Type @@ -539,9 +580,7 @@ public: operator double() const; //! returns the node content as text string operator String() const; -#ifndef OPENCV_NOSTL operator std::string() const; -#endif //! returns pointer to the underlying file node CvFileNode* operator *(); @@ -566,6 +605,13 @@ public: //! reads the registered object and returns pointer to it void* readObj() const; + //! Simplified reading API to use with bindings. + CV_WRAP double real() const; + //! Simplified reading API to use with bindings. + CV_WRAP String string() const; + //! Simplified reading API to use with bindings. + CV_WRAP Mat mat() const; + // do not use wrapper pointer classes for better efficiency const CvFileStorage* fs; const CvFileNode* node; @@ -659,8 +705,10 @@ CV_EXPORTS void write( FileStorage& fs, const String& name, double value ); CV_EXPORTS void write( FileStorage& fs, const String& name, const String& value ); CV_EXPORTS void write( FileStorage& fs, const String& name, const Mat& value ); CV_EXPORTS void write( FileStorage& fs, const String& name, const SparseMat& value ); +#ifdef CV__LEGACY_PERSISTENCE CV_EXPORTS void write( FileStorage& fs, const String& name, const std::vector& value); CV_EXPORTS void write( FileStorage& fs, const String& name, const std::vector& value); +#endif CV_EXPORTS void writeScalar( FileStorage& fs, int value ); CV_EXPORTS void writeScalar( FileStorage& fs, float value ); @@ -676,10 +724,15 @@ CV_EXPORTS void read(const FileNode& node, int& value, int default_value); CV_EXPORTS void read(const FileNode& node, float& value, float default_value); CV_EXPORTS void read(const FileNode& node, double& value, double default_value); CV_EXPORTS void read(const FileNode& node, String& value, const String& default_value); +CV_EXPORTS void read(const FileNode& node, std::string& value, const std::string& default_value); CV_EXPORTS void read(const FileNode& node, Mat& mat, const Mat& default_mat = Mat() ); CV_EXPORTS void read(const FileNode& node, SparseMat& mat, const SparseMat& default_mat = SparseMat() ); +#ifdef CV__LEGACY_PERSISTENCE CV_EXPORTS void read(const FileNode& node, std::vector& keypoints); CV_EXPORTS void read(const FileNode& node, std::vector& matches); +#endif +CV_EXPORTS void read(const FileNode& node, KeyPoint& value, const KeyPoint& default_value); +CV_EXPORTS void read(const FileNode& node, DMatch& value, const DMatch& default_value); template static inline void read(const FileNode& node, Point_<_Tp>& value, const Point_<_Tp>& default_value) { @@ -773,7 +826,7 @@ namespace internal VecWriterProxy( FileStorage* _fs ) : fs(_fs) {} void operator()(const std::vector<_Tp>& vec) const { - int _fmt = DataType<_Tp>::fmt; + int _fmt = traits::SafeFmt<_Tp>::fmt; char fmt[] = { (char)((_fmt >> 8) + '1'), (char)_fmt, '\0' }; fs->writeRaw(fmt, !vec.empty() ? (uchar*)&vec[0] : 0, vec.size() * sizeof(_Tp)); } @@ -804,8 +857,10 @@ namespace internal { size_t remaining = it->remaining; size_t cn = DataType<_Tp>::channels; - int _fmt = DataType<_Tp>::fmt; + int _fmt = traits::SafeFmt<_Tp>::fmt; + CV_Assert((_fmt >> 8) < 9); char fmt[] = { (char)((_fmt >> 8)+'1'), (char)_fmt, '\0' }; + CV_Assert((remaining % cn) == 0); size_t remaining1 = remaining / cn; count = count < remaining1 ? count : remaining1; vec.resize(count); @@ -916,11 +971,10 @@ void write(FileStorage& fs, const Range& r ) template static inline void write( FileStorage& fs, const std::vector<_Tp>& vec ) { - cv::internal::VecWriterProxy<_Tp, DataType<_Tp>::fmt != 0> w(&fs); + cv::internal::VecWriterProxy<_Tp, traits::SafeFmt<_Tp>::fmt != 0> w(&fs); w(vec); } - template static inline void write(FileStorage& fs, const String& name, const Point_<_Tp>& pt ) { @@ -977,13 +1031,65 @@ void write(FileStorage& fs, const String& name, const Range& r ) write(fs, r); } +static inline +void write(FileStorage& fs, const String& name, const KeyPoint& kpt) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, kpt.pt.x); + write(fs, kpt.pt.y); + write(fs, kpt.size); + write(fs, kpt.angle); + write(fs, kpt.response); + write(fs, kpt.octave); + write(fs, kpt.class_id); +} + +static inline +void write(FileStorage& fs, const String& name, const DMatch& m) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, m.queryIdx); + write(fs, m.trainIdx); + write(fs, m.imgIdx); + write(fs, m.distance); +} + template static inline void write( FileStorage& fs, const String& name, const std::vector<_Tp>& vec ) { - cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+(DataType<_Tp>::fmt != 0 ? FileNode::FLOW : 0)); + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+(traits::SafeFmt<_Tp>::fmt != 0 ? FileNode::FLOW : 0)); write(fs, vec); } +template static inline +void write( FileStorage& fs, const String& name, const std::vector< std::vector<_Tp> >& vec ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ); + for(size_t i = 0; i < vec.size(); i++) + { + cv::internal::WriteStructContext ws_(fs, name, FileNode::SEQ+(traits::SafeFmt<_Tp>::fmt != 0 ? FileNode::FLOW : 0)); + write(fs, vec[i]); + } +} + +#ifdef CV__LEGACY_PERSISTENCE +// This code is not needed anymore, but it is preserved here to keep source compatibility +// Implementation is similar to templates instantiations +static inline void write(FileStorage& fs, const KeyPoint& kpt) { write(fs, String(), kpt); } +static inline void write(FileStorage& fs, const DMatch& m) { write(fs, String(), m); } +static inline void write(FileStorage& fs, const std::vector& vec) +{ + cv::internal::VecWriterProxy w(&fs); + w(vec); +} +static inline void write(FileStorage& fs, const std::vector& vec) +{ + cv::internal::VecWriterProxy w(&fs); + w(vec); + +} +#endif + //! @} FileStorage //! @relates cv::FileNode @@ -1032,7 +1138,7 @@ void read(const FileNode& node, short& value, short default_value) template static inline void read( FileNodeIterator& it, std::vector<_Tp>& vec, size_t maxCount = (size_t)INT_MAX ) { - cv::internal::VecReaderProxy<_Tp, DataType<_Tp>::fmt != 0> r(&it); + cv::internal::VecReaderProxy<_Tp, traits::SafeFmt<_Tp>::fmt != 0> r(&it); r(vec, maxCount); } @@ -1048,6 +1154,24 @@ void read( const FileNode& node, std::vector<_Tp>& vec, const std::vector<_Tp>& } } +static inline +void read( const FileNode& node, std::vector& vec, const std::vector& default_value ) +{ + if(!node.node) + vec = default_value; + else + read(node, vec); +} + +static inline +void read( const FileNode& node, std::vector& vec, const std::vector& default_value ) +{ + if(!node.node) + vec = default_value; + else + read(node, vec); +} + //! @} FileNode //! @relates cv::FileStorage @@ -1103,7 +1227,7 @@ FileNodeIterator& operator >> (FileNodeIterator& it, _Tp& value) template static inline FileNodeIterator& operator >> (FileNodeIterator& it, std::vector<_Tp>& vec) { - cv::internal::VecReaderProxy<_Tp, DataType<_Tp>::fmt != 0> r(&it); + cv::internal::VecReaderProxy<_Tp, traits::SafeFmt<_Tp>::fmt != 0> r(&it); r(vec, (size_t)INT_MAX); return it; } @@ -1130,6 +1254,39 @@ void operator >> (const FileNode& n, std::vector<_Tp>& vec) it >> vec; } +/** @brief Reads KeyPoint from a file storage. +*/ +//It needs special handling because it contains two types of fields, int & float. +static inline +void operator >> (const FileNode& n, KeyPoint& kpt) +{ + FileNodeIterator it = n.begin(); + it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id; +} + +#ifdef CV__LEGACY_PERSISTENCE +static inline +void operator >> (const FileNode& n, std::vector& vec) +{ + read(n, vec); +} +static inline +void operator >> (const FileNode& n, std::vector& vec) +{ + read(n, vec); +} +#endif + +/** @brief Reads DMatch from a file storage. +*/ +//It needs special handling because it contains two types of fields, int & float. +static inline +void operator >> (const FileNode& n, DMatch& m) +{ + FileNodeIterator it = n.begin(); + it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance; +} + //! @} FileNode //! @relates cv::FileNodeIterator @@ -1181,6 +1338,9 @@ inline FileNode::operator int() const { int value; read(*this, value, 0); inline FileNode::operator float() const { float value; read(*this, value, 0.f); return value; } inline FileNode::operator double() const { double value; read(*this, value, 0.); return value; } inline FileNode::operator String() const { String value; read(*this, value, value); return value; } +inline double FileNode::real() const { return double(*this); } +inline String FileNode::string() const { return String(*this); } +inline Mat FileNode::mat() const { Mat value; read(*this, value, value); return value; } inline FileNodeIterator FileNode::begin() const { return FileNodeIterator(fs, node); } inline FileNodeIterator FileNode::end() const { return FileNodeIterator(fs, node, size()); } inline void FileNode::readRaw( const String& fmt, uchar* vec, size_t len ) const { begin().readRaw( fmt, vec, len ); } @@ -1190,6 +1350,17 @@ inline String::String(const FileNode& fn): cstr_(0), len_(0) { read(fn, *this, * //! @endcond + +CV_EXPORTS void cvStartWriteRawData_Base64(::CvFileStorage * fs, const char* name, int len, const char* dt); + +CV_EXPORTS void cvWriteRawData_Base64(::CvFileStorage * fs, const void* _data, int len); + +CV_EXPORTS void cvEndWriteRawData_Base64(::CvFileStorage * fs); + +CV_EXPORTS void cvWriteMat_Base64(::CvFileStorage* fs, const char* name, const ::CvMat* mat); + +CV_EXPORTS void cvWriteMatND_Base64(::CvFileStorage* fs, const char* name, const ::CvMatND* mat); + } // cv -#endif // __OPENCV_CORE_PERSISTENCE_HPP__ +#endif // OPENCV_CORE_PERSISTENCE_HPP diff --git a/include/opencv2/core/ptr.inl.hpp b/include/opencv2/core/ptr.inl.hpp index 65c09d1..466f634 100644 --- a/include/opencv2/core/ptr.inl.hpp +++ b/include/opencv2/core/ptr.inl.hpp @@ -39,8 +39,8 @@ // //M*/ -#ifndef __OPENCV_CORE_PTR_INL_HPP__ -#define __OPENCV_CORE_PTR_INL_HPP__ +#ifndef OPENCV_CORE_PTR_INL_HPP +#define OPENCV_CORE_PTR_INL_HPP #include @@ -89,12 +89,12 @@ private: }; template -struct PtrOwnerImpl : PtrOwner +struct PtrOwnerImpl CV_FINAL : PtrOwner { PtrOwnerImpl(Y* p, D d) : owned(p), deleter(d) {} - void deleteSelf() + void deleteSelf() CV_OVERRIDE { deleter(owned); delete this; @@ -252,6 +252,32 @@ Ptr Ptr::dynamicCast() const return Ptr(*this, dynamic_cast(stored)); } +#ifdef CV_CXX_MOVE_SEMANTICS + +template +Ptr::Ptr(Ptr&& o) : owner(o.owner), stored(o.stored) +{ + o.owner = NULL; + o.stored = NULL; +} + +template +Ptr& Ptr::operator = (Ptr&& o) +{ + if (this == &o) + return *this; + + release(); + owner = o.owner; + stored = o.stored; + o.owner = NULL; + o.stored = NULL; + return *this; +} + +#endif + + template void swap(Ptr& ptr1, Ptr& ptr2){ ptr1.swap(ptr2); @@ -335,8 +361,19 @@ Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); } +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10, const A11& a11) +{ + return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10, const A11& a11, const A12& a12) +{ + return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)); +} } // namespace cv //! @endcond -#endif // __OPENCV_CORE_PTR_INL_HPP__ +#endif // OPENCV_CORE_PTR_INL_HPP diff --git a/include/opencv2/core/saturate.hpp b/include/opencv2/core/saturate.hpp new file mode 100644 index 0000000..118599f --- /dev/null +++ b/include/opencv2/core/saturate.hpp @@ -0,0 +1,165 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_SATURATE_HPP +#define OPENCV_CORE_SATURATE_HPP + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/fast_math.hpp" + +namespace cv +{ + +//! @addtogroup core_utils +//! @{ + +/////////////// saturate_cast (used in image & signal processing) /////////////////// + +/** @brief Template function for accurate conversion from one primitive type to another. + + The function saturate_cast resembles the standard C++ cast operations, such as static_cast\() + and others. It perform an efficient and accurate conversion from one primitive type to another + (see the introduction chapter). saturate in the name means that when the input value v is out of the + range of the target type, the result is not formed just by taking low bits of the input, but instead + the value is clipped. For example: + @code + uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN) + short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX) + @endcode + Such clipping is done when the target type is unsigned char , signed char , unsigned short or + signed short . For 32-bit integers, no clipping is done. + + When the parameter is a floating-point value and the target type is an integer (8-, 16- or 32-bit), + the floating-point value is first rounded to the nearest integer and then clipped if needed (when + the target type is 8- or 16-bit). + + This operation is used in the simplest or most complex image processing functions in OpenCV. + + @param v Function parameter. + @sa add, subtract, multiply, divide, Mat::convertTo + */ +template static inline _Tp saturate_cast(uchar v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(schar v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(ushort v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(short v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(unsigned v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(int v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(float v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(double v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(int64 v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(uint64 v) { return _Tp(v); } + +template<> inline uchar saturate_cast(schar v) { return (uchar)std::max((int)v, 0); } +template<> inline uchar saturate_cast(ushort v) { return (uchar)std::min((unsigned)v, (unsigned)UCHAR_MAX); } +template<> inline uchar saturate_cast(int v) { return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } +template<> inline uchar saturate_cast(short v) { return saturate_cast((int)v); } +template<> inline uchar saturate_cast(unsigned v) { return (uchar)std::min(v, (unsigned)UCHAR_MAX); } +template<> inline uchar saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline uchar saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline uchar saturate_cast(int64 v) { return (uchar)((uint64)v <= (uint64)UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } +template<> inline uchar saturate_cast(uint64 v) { return (uchar)std::min(v, (uint64)UCHAR_MAX); } + +template<> inline schar saturate_cast(uchar v) { return (schar)std::min((int)v, SCHAR_MAX); } +template<> inline schar saturate_cast(ushort v) { return (schar)std::min((unsigned)v, (unsigned)SCHAR_MAX); } +template<> inline schar saturate_cast(int v) { return (schar)((unsigned)(v-SCHAR_MIN) <= (unsigned)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } +template<> inline schar saturate_cast(short v) { return saturate_cast((int)v); } +template<> inline schar saturate_cast(unsigned v) { return (schar)std::min(v, (unsigned)SCHAR_MAX); } +template<> inline schar saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline schar saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline schar saturate_cast(int64 v) { return (schar)((uint64)((int64)v-SCHAR_MIN) <= (uint64)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } +template<> inline schar saturate_cast(uint64 v) { return (schar)std::min(v, (uint64)SCHAR_MAX); } + +template<> inline ushort saturate_cast(schar v) { return (ushort)std::max((int)v, 0); } +template<> inline ushort saturate_cast(short v) { return (ushort)std::max((int)v, 0); } +template<> inline ushort saturate_cast(int v) { return (ushort)((unsigned)v <= (unsigned)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } +template<> inline ushort saturate_cast(unsigned v) { return (ushort)std::min(v, (unsigned)USHRT_MAX); } +template<> inline ushort saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline ushort saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline ushort saturate_cast(int64 v) { return (ushort)((uint64)v <= (uint64)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } +template<> inline ushort saturate_cast(uint64 v) { return (ushort)std::min(v, (uint64)USHRT_MAX); } + +template<> inline short saturate_cast(ushort v) { return (short)std::min((int)v, SHRT_MAX); } +template<> inline short saturate_cast(int v) { return (short)((unsigned)(v - SHRT_MIN) <= (unsigned)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } +template<> inline short saturate_cast(unsigned v) { return (short)std::min(v, (unsigned)SHRT_MAX); } +template<> inline short saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline short saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline short saturate_cast(int64 v) { return (short)((uint64)((int64)v - SHRT_MIN) <= (uint64)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } +template<> inline short saturate_cast(uint64 v) { return (short)std::min(v, (uint64)SHRT_MAX); } + +template<> inline int saturate_cast(unsigned v) { return (int)std::min(v, (unsigned)INT_MAX); } +template<> inline int saturate_cast(int64 v) { return (int)((uint64)(v - INT_MIN) <= (uint64)UINT_MAX ? v : v > 0 ? INT_MAX : INT_MIN); } +template<> inline int saturate_cast(uint64 v) { return (int)std::min(v, (uint64)INT_MAX); } +template<> inline int saturate_cast(float v) { return cvRound(v); } +template<> inline int saturate_cast(double v) { return cvRound(v); } + +template<> inline unsigned saturate_cast(schar v) { return (unsigned)std::max(v, (schar)0); } +template<> inline unsigned saturate_cast(short v) { return (unsigned)std::max(v, (short)0); } +template<> inline unsigned saturate_cast(int v) { return (unsigned)std::max(v, (int)0); } +template<> inline unsigned saturate_cast(int64 v) { return (unsigned)((uint64)v <= (uint64)UINT_MAX ? v : v > 0 ? UINT_MAX : 0); } +template<> inline unsigned saturate_cast(uint64 v) { return (unsigned)std::min(v, (uint64)UINT_MAX); } +// we intentionally do not clip negative numbers, to make -1 become 0xffffffff etc. +template<> inline unsigned saturate_cast(float v) { return static_cast(cvRound(v)); } +template<> inline unsigned saturate_cast(double v) { return static_cast(cvRound(v)); } + +template<> inline uint64 saturate_cast(schar v) { return (uint64)std::max(v, (schar)0); } +template<> inline uint64 saturate_cast(short v) { return (uint64)std::max(v, (short)0); } +template<> inline uint64 saturate_cast(int v) { return (uint64)std::max(v, (int)0); } +template<> inline uint64 saturate_cast(int64 v) { return (uint64)std::max(v, (int64)0); } + +template<> inline int64 saturate_cast(uint64 v) { return (int64)std::min(v, (uint64)LLONG_MAX); } + +//! @} + +} // cv + +#endif // OPENCV_CORE_SATURATE_HPP diff --git a/include/opencv2/core/softfloat.hpp b/include/opencv2/core/softfloat.hpp new file mode 100644 index 0000000..5470980 --- /dev/null +++ b/include/opencv2/core/softfloat.hpp @@ -0,0 +1,514 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +// This file is based on files from package issued with the following license: + +/*============================================================================ + +This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3c, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#pragma once +#ifndef softfloat_h +#define softfloat_h 1 + +#include "cvdef.h" + +namespace cv +{ + +/** @addtogroup core_utils_softfloat + + [SoftFloat](http://www.jhauser.us/arithmetic/SoftFloat.html) is a software implementation + of floating-point calculations according to IEEE 754 standard. + All calculations are done in integers, that's why they are machine-independent and bit-exact. + This library can be useful in accuracy-critical parts like look-up tables generation, tests, etc. + OpenCV contains a subset of SoftFloat partially rewritten to C++. + + ### Types + + There are two basic types: @ref softfloat and @ref softdouble. + These types are binary compatible with float and double types respectively + and support conversions to/from them. + Other types from original SoftFloat library like fp16 or fp128 were thrown away + as well as quiet/signaling NaN support, on-the-fly rounding mode switch + and exception flags (though exceptions can be implemented in the future). + + ### Operations + + Both types support the following: + - Construction from signed and unsigned 32-bit and 64 integers, + float/double or raw binary representation + - Conversions between each other, to float or double and to int + using @ref cvRound, @ref cvTrunc, @ref cvFloor, @ref cvCeil or a bunch of + saturate_cast functions + - Add, subtract, multiply, divide, remainder, square root, FMA with absolute precision + - Comparison operations + - Explicit sign, exponent and significand manipulation through get/set methods, + number state indicators (isInf, isNan, isSubnormal) + - Type-specific constants like eps, minimum/maximum value, best pi approximation, etc. + - min(), max(), abs(), exp(), log() and pow() functions + +*/ +//! @{ + +struct softfloat; +struct softdouble; + +struct CV_EXPORTS softfloat +{ +public: + /** @brief Default constructor */ + softfloat() { v = 0; } + /** @brief Copy constructor */ + softfloat( const softfloat& c) { v = c.v; } + /** @brief Assign constructor */ + softfloat& operator=( const softfloat& c ) + { + if(&c != this) v = c.v; + return *this; + } + /** @brief Construct from raw + + Builds new value from raw binary representation + */ + static const softfloat fromRaw( const uint32_t a ) { softfloat x; x.v = a; return x; } + + /** @brief Construct from integer */ + explicit softfloat( const uint32_t ); + explicit softfloat( const uint64_t ); + explicit softfloat( const int32_t ); + explicit softfloat( const int64_t ); + +#ifdef CV_INT32_T_IS_LONG_INT + // for platforms with int32_t = long int + explicit softfloat( const int a ) { *this = softfloat(static_cast(a)); } +#endif + + /** @brief Construct from float */ + explicit softfloat( const float a ) { Cv32suf s; s.f = a; v = s.u; } + + /** @brief Type casts */ + operator softdouble() const; + operator float() const { Cv32suf s; s.u = v; return s.f; } + + /** @brief Basic arithmetics */ + softfloat operator + (const softfloat&) const; + softfloat operator - (const softfloat&) const; + softfloat operator * (const softfloat&) const; + softfloat operator / (const softfloat&) const; + softfloat operator - () const { softfloat x; x.v = v ^ (1U << 31); return x; } + + /** @brief Remainder operator + + A quote from original SoftFloat manual: + + > The IEEE Standard remainder operation computes the value + > a - n * b, where n is the integer closest to a / b. + > If a / b is exactly halfway between two integers, n is the even integer + > closest to a / b. The IEEE Standard’s remainder operation is always exact and so requires no rounding. + > Depending on the relative magnitudes of the operands, the remainder functions + > can take considerably longer to execute than the other SoftFloat functions. + > This is an inherent characteristic of the remainder operation itself and is not a flaw + > in the SoftFloat implementation. + */ + softfloat operator % (const softfloat&) const; + + softfloat& operator += (const softfloat& a) { *this = *this + a; return *this; } + softfloat& operator -= (const softfloat& a) { *this = *this - a; return *this; } + softfloat& operator *= (const softfloat& a) { *this = *this * a; return *this; } + softfloat& operator /= (const softfloat& a) { *this = *this / a; return *this; } + softfloat& operator %= (const softfloat& a) { *this = *this % a; return *this; } + + /** @brief Comparison operations + + - Any operation with NaN produces false + + The only exception is when x is NaN: x != y for any y. + - Positive and negative zeros are equal + */ + bool operator == ( const softfloat& ) const; + bool operator != ( const softfloat& ) const; + bool operator > ( const softfloat& ) const; + bool operator >= ( const softfloat& ) const; + bool operator < ( const softfloat& ) const; + bool operator <= ( const softfloat& ) const; + + /** @brief NaN state indicator */ + inline bool isNaN() const { return (v & 0x7fffffff) > 0x7f800000; } + /** @brief Inf state indicator */ + inline bool isInf() const { return (v & 0x7fffffff) == 0x7f800000; } + /** @brief Subnormal number indicator */ + inline bool isSubnormal() const { return ((v >> 23) & 0xFF) == 0; } + + /** @brief Get sign bit */ + inline bool getSign() const { return (v >> 31) != 0; } + /** @brief Construct a copy with new sign bit */ + inline softfloat setSign(bool sign) const { softfloat x; x.v = (v & ((1U << 31) - 1)) | ((uint32_t)sign << 31); return x; } + /** @brief Get 0-based exponent */ + inline int getExp() const { return ((v >> 23) & 0xFF) - 127; } + /** @brief Construct a copy with new 0-based exponent */ + inline softfloat setExp(int e) const { softfloat x; x.v = (v & 0x807fffff) | (((e + 127) & 0xFF) << 23 ); return x; } + + /** @brief Get a fraction part + + Returns a number 1 <= x < 2 with the same significand + */ + inline softfloat getFrac() const + { + uint_fast32_t vv = (v & 0x007fffff) | (127 << 23); + return softfloat::fromRaw(vv); + } + /** @brief Construct a copy with provided significand + + Constructs a copy of a number with significand taken from parameter + */ + inline softfloat setFrac(const softfloat& s) const + { + softfloat x; + x.v = (v & 0xff800000) | (s.v & 0x007fffff); + return x; + } + + /** @brief Zero constant */ + static softfloat zero() { return softfloat::fromRaw( 0 ); } + /** @brief Positive infinity constant */ + static softfloat inf() { return softfloat::fromRaw( 0xFF << 23 ); } + /** @brief Default NaN constant */ + static softfloat nan() { return softfloat::fromRaw( 0x7fffffff ); } + /** @brief One constant */ + static softfloat one() { return softfloat::fromRaw( 127 << 23 ); } + /** @brief Smallest normalized value */ + static softfloat min() { return softfloat::fromRaw( 0x01 << 23 ); } + /** @brief Difference between 1 and next representable value */ + static softfloat eps() { return softfloat::fromRaw( (127 - 23) << 23 ); } + /** @brief Biggest finite value */ + static softfloat max() { return softfloat::fromRaw( (0xFF << 23) - 1 ); } + /** @brief Correct pi approximation */ + static softfloat pi() { return softfloat::fromRaw( 0x40490fdb ); } + + uint32_t v; +}; + +/*---------------------------------------------------------------------------- +*----------------------------------------------------------------------------*/ + +struct CV_EXPORTS softdouble +{ +public: + /** @brief Default constructor */ + softdouble() : v(0) { } + /** @brief Copy constructor */ + softdouble( const softdouble& c) { v = c.v; } + /** @brief Assign constructor */ + softdouble& operator=( const softdouble& c ) + { + if(&c != this) v = c.v; + return *this; + } + /** @brief Construct from raw + + Builds new value from raw binary representation + */ + static softdouble fromRaw( const uint64_t a ) { softdouble x; x.v = a; return x; } + + /** @brief Construct from integer */ + explicit softdouble( const uint32_t ); + explicit softdouble( const uint64_t ); + explicit softdouble( const int32_t ); + explicit softdouble( const int64_t ); + +#ifdef CV_INT32_T_IS_LONG_INT + // for platforms with int32_t = long int + explicit softdouble( const int a ) { *this = softdouble(static_cast(a)); } +#endif + + /** @brief Construct from double */ + explicit softdouble( const double a ) { Cv64suf s; s.f = a; v = s.u; } + + /** @brief Type casts */ + operator softfloat() const; + operator double() const { Cv64suf s; s.u = v; return s.f; } + + /** @brief Basic arithmetics */ + softdouble operator + (const softdouble&) const; + softdouble operator - (const softdouble&) const; + softdouble operator * (const softdouble&) const; + softdouble operator / (const softdouble&) const; + softdouble operator - () const { softdouble x; x.v = v ^ (1ULL << 63); return x; } + + /** @brief Remainder operator + + A quote from original SoftFloat manual: + + > The IEEE Standard remainder operation computes the value + > a - n * b, where n is the integer closest to a / b. + > If a / b is exactly halfway between two integers, n is the even integer + > closest to a / b. The IEEE Standard’s remainder operation is always exact and so requires no rounding. + > Depending on the relative magnitudes of the operands, the remainder functions + > can take considerably longer to execute than the other SoftFloat functions. + > This is an inherent characteristic of the remainder operation itself and is not a flaw + > in the SoftFloat implementation. + */ + softdouble operator % (const softdouble&) const; + + softdouble& operator += (const softdouble& a) { *this = *this + a; return *this; } + softdouble& operator -= (const softdouble& a) { *this = *this - a; return *this; } + softdouble& operator *= (const softdouble& a) { *this = *this * a; return *this; } + softdouble& operator /= (const softdouble& a) { *this = *this / a; return *this; } + softdouble& operator %= (const softdouble& a) { *this = *this % a; return *this; } + + /** @brief Comparison operations + + - Any operation with NaN produces false + + The only exception is when x is NaN: x != y for any y. + - Positive and negative zeros are equal + */ + bool operator == ( const softdouble& ) const; + bool operator != ( const softdouble& ) const; + bool operator > ( const softdouble& ) const; + bool operator >= ( const softdouble& ) const; + bool operator < ( const softdouble& ) const; + bool operator <= ( const softdouble& ) const; + + /** @brief NaN state indicator */ + inline bool isNaN() const { return (v & 0x7fffffffffffffff) > 0x7ff0000000000000; } + /** @brief Inf state indicator */ + inline bool isInf() const { return (v & 0x7fffffffffffffff) == 0x7ff0000000000000; } + /** @brief Subnormal number indicator */ + inline bool isSubnormal() const { return ((v >> 52) & 0x7FF) == 0; } + + /** @brief Get sign bit */ + inline bool getSign() const { return (v >> 63) != 0; } + /** @brief Construct a copy with new sign bit */ + softdouble setSign(bool sign) const { softdouble x; x.v = (v & ((1ULL << 63) - 1)) | ((uint_fast64_t)(sign) << 63); return x; } + /** @brief Get 0-based exponent */ + inline int getExp() const { return ((v >> 52) & 0x7FF) - 1023; } + /** @brief Construct a copy with new 0-based exponent */ + inline softdouble setExp(int e) const + { + softdouble x; + x.v = (v & 0x800FFFFFFFFFFFFF) | ((uint_fast64_t)((e + 1023) & 0x7FF) << 52); + return x; + } + + /** @brief Get a fraction part + + Returns a number 1 <= x < 2 with the same significand + */ + inline softdouble getFrac() const + { + uint_fast64_t vv = (v & 0x000FFFFFFFFFFFFF) | ((uint_fast64_t)(1023) << 52); + return softdouble::fromRaw(vv); + } + /** @brief Construct a copy with provided significand + + Constructs a copy of a number with significand taken from parameter + */ + inline softdouble setFrac(const softdouble& s) const + { + softdouble x; + x.v = (v & 0xFFF0000000000000) | (s.v & 0x000FFFFFFFFFFFFF); + return x; + } + + /** @brief Zero constant */ + static softdouble zero() { return softdouble::fromRaw( 0 ); } + /** @brief Positive infinity constant */ + static softdouble inf() { return softdouble::fromRaw( (uint_fast64_t)(0x7FF) << 52 ); } + /** @brief Default NaN constant */ + static softdouble nan() { return softdouble::fromRaw( CV_BIG_INT(0x7FFFFFFFFFFFFFFF) ); } + /** @brief One constant */ + static softdouble one() { return softdouble::fromRaw( (uint_fast64_t)( 1023) << 52 ); } + /** @brief Smallest normalized value */ + static softdouble min() { return softdouble::fromRaw( (uint_fast64_t)( 0x01) << 52 ); } + /** @brief Difference between 1 and next representable value */ + static softdouble eps() { return softdouble::fromRaw( (uint_fast64_t)( 1023 - 52 ) << 52 ); } + /** @brief Biggest finite value */ + static softdouble max() { return softdouble::fromRaw( ((uint_fast64_t)(0x7FF) << 52) - 1 ); } + /** @brief Correct pi approximation */ + static softdouble pi() { return softdouble::fromRaw( CV_BIG_INT(0x400921FB54442D18) ); } + + uint64_t v; +}; + +/*---------------------------------------------------------------------------- +*----------------------------------------------------------------------------*/ + +/** @brief Fused Multiplication and Addition + +Computes (a*b)+c with single rounding +*/ +CV_EXPORTS softfloat mulAdd( const softfloat& a, const softfloat& b, const softfloat & c); +CV_EXPORTS softdouble mulAdd( const softdouble& a, const softdouble& b, const softdouble& c); + +/** @brief Square root */ +CV_EXPORTS softfloat sqrt( const softfloat& a ); +CV_EXPORTS softdouble sqrt( const softdouble& a ); +} + +/*---------------------------------------------------------------------------- +| Ported from OpenCV and added for usability +*----------------------------------------------------------------------------*/ + +/** @brief Truncates number to integer with minimum magnitude */ +CV_EXPORTS int cvTrunc(const cv::softfloat& a); +CV_EXPORTS int cvTrunc(const cv::softdouble& a); + +/** @brief Rounds a number to nearest even integer */ +CV_EXPORTS int cvRound(const cv::softfloat& a); +CV_EXPORTS int cvRound(const cv::softdouble& a); + +/** @brief Rounds a number to nearest even long long integer */ +CV_EXPORTS int64_t cvRound64(const cv::softdouble& a); + +/** @brief Rounds a number down to integer */ +CV_EXPORTS int cvFloor(const cv::softfloat& a); +CV_EXPORTS int cvFloor(const cv::softdouble& a); + +/** @brief Rounds number up to integer */ +CV_EXPORTS int cvCeil(const cv::softfloat& a); +CV_EXPORTS int cvCeil(const cv::softdouble& a); + +namespace cv +{ +/** @brief Saturate casts */ +template static inline _Tp saturate_cast(softfloat a) { return _Tp(a); } +template static inline _Tp saturate_cast(softdouble a) { return _Tp(a); } + +template<> inline uchar saturate_cast(softfloat a) { return (uchar)std::max(std::min(cvRound(a), (int)UCHAR_MAX), 0); } +template<> inline uchar saturate_cast(softdouble a) { return (uchar)std::max(std::min(cvRound(a), (int)UCHAR_MAX), 0); } + +template<> inline schar saturate_cast(softfloat a) { return (schar)std::min(std::max(cvRound(a), (int)SCHAR_MIN), (int)SCHAR_MAX); } +template<> inline schar saturate_cast(softdouble a) { return (schar)std::min(std::max(cvRound(a), (int)SCHAR_MIN), (int)SCHAR_MAX); } + +template<> inline ushort saturate_cast(softfloat a) { return (ushort)std::max(std::min(cvRound(a), (int)USHRT_MAX), 0); } +template<> inline ushort saturate_cast(softdouble a) { return (ushort)std::max(std::min(cvRound(a), (int)USHRT_MAX), 0); } + +template<> inline short saturate_cast(softfloat a) { return (short)std::min(std::max(cvRound(a), (int)SHRT_MIN), (int)SHRT_MAX); } +template<> inline short saturate_cast(softdouble a) { return (short)std::min(std::max(cvRound(a), (int)SHRT_MIN), (int)SHRT_MAX); } + +template<> inline int saturate_cast(softfloat a) { return cvRound(a); } +template<> inline int saturate_cast(softdouble a) { return cvRound(a); } + +template<> inline int64_t saturate_cast(softfloat a) { return cvRound(a); } +template<> inline int64_t saturate_cast(softdouble a) { return cvRound64(a); } + +/** @brief Saturate cast to unsigned integer and unsigned long long integer +We intentionally do not clip negative numbers, to make -1 become 0xffffffff etc. +*/ +template<> inline unsigned saturate_cast(softfloat a) { return cvRound(a); } +template<> inline unsigned saturate_cast(softdouble a) { return cvRound(a); } + +template<> inline uint64_t saturate_cast(softfloat a) { return cvRound(a); } +template<> inline uint64_t saturate_cast(softdouble a) { return cvRound64(a); } + +/** @brief Min and Max functions */ +inline softfloat min(const softfloat& a, const softfloat& b) { return (a > b) ? b : a; } +inline softdouble min(const softdouble& a, const softdouble& b) { return (a > b) ? b : a; } + +inline softfloat max(const softfloat& a, const softfloat& b) { return (a > b) ? a : b; } +inline softdouble max(const softdouble& a, const softdouble& b) { return (a > b) ? a : b; } + +/** @brief Absolute value */ +inline softfloat abs( softfloat a) { softfloat x; x.v = a.v & ((1U << 31) - 1); return x; } +inline softdouble abs( softdouble a) { softdouble x; x.v = a.v & ((1ULL << 63) - 1); return x; } + +/** @brief Exponent + +Special cases: +- exp(NaN) is NaN +- exp(-Inf) == 0 +- exp(+Inf) == +Inf +*/ +CV_EXPORTS softfloat exp( const softfloat& a); +CV_EXPORTS softdouble exp( const softdouble& a); + +/** @brief Natural logarithm + +Special cases: +- log(NaN), log(x < 0) are NaN +- log(0) == -Inf +*/ +CV_EXPORTS softfloat log( const softfloat& a ); +CV_EXPORTS softdouble log( const softdouble& a ); + +/** @brief Raising to the power + +Special cases: +- x**NaN is NaN for any x +- ( |x| == 1 )**Inf is NaN +- ( |x| > 1 )**+Inf or ( |x| < 1 )**-Inf is +Inf +- ( |x| > 1 )**-Inf or ( |x| < 1 )**+Inf is 0 +- x ** 0 == 1 for any x +- x ** 1 == 1 for any x +- NaN ** y is NaN for any other y +- Inf**(y < 0) == 0 +- Inf ** y is +Inf for any other y +- (x < 0)**y is NaN for any other y if x can't be correctly rounded to integer +- 0 ** 0 == 1 +- 0 ** (y < 0) is +Inf +- 0 ** (y > 0) is 0 +*/ +CV_EXPORTS softfloat pow( const softfloat& a, const softfloat& b); +CV_EXPORTS softdouble pow( const softdouble& a, const softdouble& b); + +/** @brief Cube root + +Special cases: +- cbrt(NaN) is NaN +- cbrt(+/-Inf) is +/-Inf +*/ +CV_EXPORTS softfloat cbrt( const softfloat& a ); + +/** @brief Sine + +Special cases: +- sin(Inf) or sin(NaN) is NaN +- sin(x) == x when sin(x) is close to zero +*/ +CV_EXPORTS softdouble sin( const softdouble& a ); + +/** @brief Cosine + * +Special cases: +- cos(Inf) or cos(NaN) is NaN +- cos(x) == +/- 1 when cos(x) is close to +/- 1 +*/ +CV_EXPORTS softdouble cos( const softdouble& a ); + +} + +//! @} + +#endif diff --git a/include/opencv2/core/sse_utils.hpp b/include/opencv2/core/sse_utils.hpp index e0283eb..0906583 100644 --- a/include/opencv2/core/sse_utils.hpp +++ b/include/opencv2/core/sse_utils.hpp @@ -39,13 +39,18 @@ // //M*/ -#ifndef __OPENCV_CORE_SSE_UTILS_HPP__ -#define __OPENCV_CORE_SSE_UTILS_HPP__ +#ifndef OPENCV_CORE_SSE_UTILS_HPP +#define OPENCV_CORE_SSE_UTILS_HPP #ifndef __cplusplus # error sse_utils.hpp header must be compiled as C++ #endif +#include "opencv2/core/cvdef.h" + +//! @addtogroup core_utils_sse +//! @{ + #if CV_SSE2 inline void _mm_deinterleave_epi8(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1) @@ -562,7 +567,7 @@ inline void _mm_deinterleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m128 & v_g1) { - const int mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1); + enum { mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1) }; __m128 layer2_chunk0 = _mm_shuffle_ps(v_r0, v_r1, mask_lo); __m128 layer2_chunk2 = _mm_shuffle_ps(v_r0, v_r1, mask_hi); @@ -583,7 +588,7 @@ inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m12 inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m128 & v_g1, __m128 & v_b0, __m128 & v_b1) { - const int mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1); + enum { mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1) }; __m128 layer2_chunk0 = _mm_shuffle_ps(v_r0, v_r1, mask_lo); __m128 layer2_chunk3 = _mm_shuffle_ps(v_r0, v_r1, mask_hi); @@ -610,7 +615,7 @@ inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m128 & v_g1, __m128 & v_b0, __m128 & v_b1, __m128 & v_a0, __m128 & v_a1) { - const int mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1); + enum { mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1) }; __m128 layer2_chunk0 = _mm_shuffle_ps(v_r0, v_r1, mask_lo); __m128 layer2_chunk4 = _mm_shuffle_ps(v_r0, v_r1, mask_hi); @@ -642,4 +647,6 @@ inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m12 #endif // CV_SSE2 -#endif //__OPENCV_CORE_SSE_UTILS_HPP__ +//! @} + +#endif //OPENCV_CORE_SSE_UTILS_HPP diff --git a/include/opencv2/core/traits.hpp b/include/opencv2/core/traits.hpp index 49bc844..6cb10f4 100644 --- a/include/opencv2/core/traits.hpp +++ b/include/opencv2/core/traits.hpp @@ -41,19 +41,23 @@ // //M*/ -#ifndef __OPENCV_CORE_TRAITS_HPP__ -#define __OPENCV_CORE_TRAITS_HPP__ +#ifndef OPENCV_CORE_TRAITS_HPP +#define OPENCV_CORE_TRAITS_HPP #include "opencv2/core/cvdef.h" namespace cv { +//#define OPENCV_TRAITS_ENABLE_DEPRECATED + //! @addtogroup core_basic //! @{ /** @brief Template "trait" class for OpenCV primitive data types. +@note Deprecated. This is replaced by "single purpose" traits: traits::Type and traits::Depth + A primitive OpenCV data type is one of unsigned char, bool, signed char, unsigned short, signed short, int, float, double, or a tuple of values of one of these types, where all the values in the tuple have the same type. Any primitive type from the list can be defined by an identifier in the @@ -102,10 +106,13 @@ So, such traits are used to tell OpenCV which data type you are working with, ev not native to OpenCV. For example, the matrix B initialization above is compiled because OpenCV defines the proper specialized template class DataType\ \> . This mechanism is also useful (and used in OpenCV this way) for generic algorithms implementations. + +@note Default values were dropped to stop confusing developers about using of unsupported types (see #7599) */ template class DataType { public: +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED typedef _Tp value_type; typedef value_type work_type; typedef value_type channel_type; @@ -116,6 +123,7 @@ public: fmt = 0, type = CV_MAKETYPE(depth, channels) }; +#endif }; template<> class DataType @@ -270,11 +278,14 @@ public: }; +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED template class TypeDepth { +#ifdef OPENCV_TRAITS_ENABLE_LEGACY_DEFAULTS enum { depth = CV_USRTYPE1 }; typedef void value_type; +#endif }; template<> class TypeDepth @@ -319,8 +330,68 @@ template<> class TypeDepth typedef double value_type; }; +#endif + //! @} +namespace traits { + +namespace internal { +#define CV_CREATE_MEMBER_CHECK(X) \ +template class CheckMember_##X { \ + struct Fallback { int X; }; \ + struct Derived : T, Fallback { }; \ + template struct Check; \ + typedef char CV_NO[1]; \ + typedef char CV_YES[2]; \ + template static CV_NO & func(Check *); \ + template static CV_YES & func(...); \ +public: \ + typedef CheckMember_##X type; \ + enum { value = sizeof(func(0)) == sizeof(CV_YES) }; \ +}; + +CV_CREATE_MEMBER_CHECK(fmt) +CV_CREATE_MEMBER_CHECK(type) + +} // namespace internal + + +template +struct Depth +{ enum { value = DataType::depth }; }; + +template +struct Type +{ enum { value = DataType::type }; }; + +/** Similar to traits::Type but has value = -1 in case of unknown type (instead of compiler error) */ +template >::value > +struct SafeType {}; + +template +struct SafeType +{ enum { value = -1 }; }; + +template +struct SafeType +{ enum { value = Type::value }; }; + + +template >::value > +struct SafeFmt {}; + +template +struct SafeFmt +{ enum { fmt = 0 }; }; + +template +struct SafeFmt +{ enum { fmt = DataType::fmt }; }; + + +} // namespace + } // cv -#endif // __OPENCV_CORE_TRAITS_HPP__ +#endif // OPENCV_CORE_TRAITS_HPP diff --git a/include/opencv2/core/types.hpp b/include/opencv2/core/types.hpp index e166556..ef9ab59 100644 --- a/include/opencv2/core/types.hpp +++ b/include/opencv2/core/types.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_CORE_TYPES_HPP__ -#define __OPENCV_CORE_TYPES_HPP__ +#ifndef OPENCV_CORE_TYPES_HPP +#define OPENCV_CORE_TYPES_HPP #ifndef __cplusplus # error types.hpp header must be compiled as C++ @@ -51,6 +51,7 @@ #include #include #include +#include #include "opencv2/core/cvdef.h" #include "opencv2/core/cvstd.hpp" @@ -74,7 +75,7 @@ template class Complex { public: - //! constructors + //! default constructor Complex(); Complex( _Tp _re, _Tp _im = 0 ); @@ -97,14 +98,23 @@ public: typedef _Tp channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 2, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) }; + fmt = DataType::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; typedef Vec vec_type; }; +namespace traits { +template +struct Depth< Complex<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Complex<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 2) }; }; +} // namespace //////////////////////////////// Point_ //////////////////////////////// @@ -149,7 +159,7 @@ template class Point_ public: typedef _Tp value_type; - // various constructors + //! default constructor Point_(); Point_(_Tp _x, _Tp _y); Point_(const Point_& pt); @@ -171,11 +181,12 @@ public: double cross(const Point_& pt) const; //! checks whether the point is inside the specified rectangle bool inside(const Rect_<_Tp>& r) const; - - _Tp x, y; //< the point coordinates + _Tp x; //!< x coordinate of the point + _Tp y; //!< y coordinate of the point }; typedef Point_ Point2i; +typedef Point_ Point2l; typedef Point_ Point2f; typedef Point_ Point2d; typedef Point2i Point; @@ -188,15 +199,23 @@ public: typedef _Tp channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 2, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; +namespace traits { +template +struct Depth< Point_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Point_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 2) }; }; +} // namespace //////////////////////////////// Point3_ //////////////////////////////// @@ -220,7 +239,7 @@ template class Point3_ public: typedef _Tp value_type; - // various constructors + //! default constructor Point3_(); Point3_(_Tp _x, _Tp _y, _Tp _z); Point3_(const Point3_& pt); @@ -231,7 +250,11 @@ public: //! conversion to another data type template operator Point3_<_Tp2>() const; //! conversion to cv::Vec<> +#if OPENCV_ABI_COMPATIBILITY > 300 + template operator Vec<_Tp2, 3>() const; +#else operator Vec<_Tp, 3>() const; +#endif //! dot product _Tp dot(const Point3_& pt) const; @@ -239,8 +262,9 @@ public: double ddot(const Point3_& pt) const; //! cross product of the 2 3D points Point3_ cross(const Point3_& pt) const; - - _Tp x, y, z; //< the point coordinates + _Tp x; //!< x coordinate of the 3D point + _Tp y; //!< y coordinate of the 3D point + _Tp z; //!< z coordinate of the 3D point }; typedef Point3_ Point3i; @@ -255,16 +279,23 @@ public: typedef _Tp channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 3, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; - +namespace traits { +template +struct Depth< Point3_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Point3_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 3) }; }; +} // namespace //////////////////////////////// Size_ //////////////////////////////// @@ -286,7 +317,7 @@ template class Size_ public: typedef _Tp value_type; - //! various constructors + //! default constructor Size_(); Size_(_Tp _width, _Tp _height); Size_(const Size_& sz); @@ -295,14 +326,18 @@ public: Size_& operator = (const Size_& sz); //! the area (width*height) _Tp area() const; + //! true if empty + bool empty() const; //! conversion of another data type. template operator Size_<_Tp2>() const; - _Tp width, height; // the width and the height + _Tp width; //!< the width + _Tp height; //!< the height }; typedef Size_ Size2i; +typedef Size_ Size2l; typedef Size_ Size2f; typedef Size_ Size2d; typedef Size2i Size; @@ -315,16 +350,23 @@ public: typedef _Tp channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 2, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = DataType::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; - +namespace traits { +template +struct Depth< Size_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Size_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 2) }; }; +} // namespace //////////////////////////////// Rect_ //////////////////////////////// @@ -376,7 +418,7 @@ template class Rect_ public: typedef _Tp value_type; - //! various constructors + //! default constructor Rect_(); Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height); Rect_(const Rect_& r); @@ -393,6 +435,8 @@ public: Size_<_Tp> size() const; //! area (width*height) of the rectangle _Tp area() const; + //! true if empty + bool empty() const; //! conversion to another data type template operator Rect_<_Tp2>() const; @@ -400,7 +444,10 @@ public: //! checks whether the rectangle contains the point bool contains(const Point_<_Tp>& pt) const; - _Tp x, y, width, height; //< the top-left corner, as well as width and height of the rectangle + _Tp x; //!< x coordinate of the top-left corner + _Tp y; //!< y coordinate of the top-left corner + _Tp width; //!< width of the rectangle + _Tp height; //!< height of the rectangle }; typedef Rect_ Rect2i; @@ -416,40 +463,33 @@ public: typedef _Tp channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 4, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; - +namespace traits { +template +struct Depth< Rect_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Rect_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 4) }; }; +} // namespace ///////////////////////////// RotatedRect ///////////////////////////// /** @brief The class represents rotated (i.e. not up-right) rectangles on a plane. Each rectangle is specified by the center point (mass center), length of each side (represented by -cv::Size2f structure) and the rotation angle in degrees. +#Size2f structure) and the rotation angle in degrees. The sample below demonstrates how to use RotatedRect: -@code - Mat image(200, 200, CV_8UC3, Scalar(0)); - RotatedRect rRect = RotatedRect(Point2f(100,100), Size2f(100,50), 30); - - Point2f vertices[4]; - rRect.points(vertices); - for (int i = 0; i < 4; i++) - line(image, vertices[i], vertices[(i+1)%4], Scalar(0,255,0)); - - Rect brect = rRect.boundingRect(); - rectangle(image, brect, Scalar(255,0,0)); - - imshow("rectangles", image); - waitKey(0); -@endcode +@snippet snippets/core_various.cpp RotatedRect_demo ![image](pics/rotatedrect.png) @sa CamShift, fitEllipse, minAreaRect, CvBox2D @@ -457,9 +497,9 @@ The sample below demonstrates how to use RotatedRect: class CV_EXPORTS RotatedRect { public: - //! various constructors + //! default constructor RotatedRect(); - /** + /** full constructor @param center The rectangle mass center. @param size Width and height of the rectangle. @param angle The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., @@ -473,15 +513,19 @@ public: RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3); /** returns 4 vertices of the rectangle - @param pts The points array for storing rectangle vertices. + @param pts The points array for storing rectangle vertices. The order is bottomLeft, topLeft, topRight, bottomRight. */ void points(Point2f pts[]) const; - //! returns the minimal up-right rectangle containing the rotated rectangle + //! returns the minimal up-right integer rectangle containing the rotated rectangle Rect boundingRect() const; - - Point2f center; //< the rectangle mass center - Size2f size; //< width and height of the rectangle - float angle; //< the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. + //! returns the minimal (exact) floating point rectangle containing the rotated rectangle, not intended for use with images + Rect_ boundingRect2f() const; + //! returns the rectangle mass center + Point2f center; + //! returns width and height of the rectangle + Size2f size; + //! returns the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. + float angle; }; template<> class DataType< RotatedRect > @@ -492,15 +536,23 @@ public: typedef float channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = (int)sizeof(value_type)/sizeof(channel_type), // 5 - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; +namespace traits { +template<> +struct Depth< RotatedRect > { enum { value = Depth::value }; }; +template<> +struct Type< RotatedRect > { enum { value = CV_MAKETYPE(Depth::value, (int)sizeof(RotatedRect)/sizeof(float)) }; }; +} // namespace //////////////////////////////// Range ///////////////////////////////// @@ -548,29 +600,37 @@ public: typedef int channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 2, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; +namespace traits { +template<> +struct Depth< Range > { enum { value = Depth::value }; }; +template<> +struct Type< Range > { enum { value = CV_MAKETYPE(Depth::value, 2) }; }; +} // namespace //////////////////////////////// Scalar_ /////////////////////////////// /** @brief Template class for a 4-element vector derived from Vec. -Being derived from Vec\<_Tp, 4\> , Scalar_ and Scalar can be used just as typical 4-element +Being derived from Vec\<_Tp, 4\> , Scalar\_ and Scalar can be used just as typical 4-element vectors. In addition, they can be converted to/from CvScalar . The type Scalar is widely used in OpenCV to pass pixel values. */ template class Scalar_ : public Vec<_Tp, 4> { public: - //! various constructors + //! default constructor Scalar_(); Scalar_(_Tp v0, _Tp v1, _Tp v2=0, _Tp v3=0); Scalar_(_Tp v0); @@ -587,10 +647,10 @@ public: //! per-element product Scalar_<_Tp> mul(const Scalar_<_Tp>& a, double scale=1 ) const; - // returns (v0, -v1, -v2, -v3) + //! returns (v0, -v1, -v2, -v3) Scalar_<_Tp> conj() const; - // returns true iff v1 == v2 == v3 == 0 + //! returns true iff v1 == v2 == v3 == 0 bool isReal() const; }; @@ -604,15 +664,23 @@ public: typedef _Tp channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = 4, - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; +namespace traits { +template +struct Depth< Scalar_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Scalar_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 4) }; }; +} // namespace /////////////////////////////// KeyPoint //////////////////////////////// @@ -620,14 +688,13 @@ public: /** @brief Data structure for salient point detectors. The class instance stores a keypoint, i.e. a point feature found by one of many available keypoint -detectors, such as Harris corner detector, cv::FAST, cv::StarDetector, cv::SURF, cv::SIFT, -cv::LDetector etc. +detectors, such as Harris corner detector, #FAST, %StarDetector, %SURF, %SIFT etc. The keypoint is characterized by the 2D position, scale (proportional to the diameter of the neighborhood that needs to be taken into account), orientation and some other parameters. The keypoint neighborhood is then analyzed by another algorithm that builds a descriptor (usually represented as a feature vector). The keypoints representing the same object in different images -can then be matched using cv::KDTree or another method. +can then be matched using %KDTree or another method. */ class CV_EXPORTS_W_SIMPLE KeyPoint { @@ -699,6 +766,7 @@ public: CV_PROP_RW int class_id; //!< object class (if the keypoints need to be clustered by an object they belong to) }; +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED template<> class DataType { public: @@ -715,7 +783,7 @@ public: typedef Vec vec_type; }; - +#endif //////////////////////////////// DMatch ///////////////////////////////// @@ -732,9 +800,9 @@ public: CV_WRAP DMatch(int _queryIdx, int _trainIdx, float _distance); CV_WRAP DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance); - CV_PROP_RW int queryIdx; // query descriptor index - CV_PROP_RW int trainIdx; // train descriptor index - CV_PROP_RW int imgIdx; // train image index + CV_PROP_RW int queryIdx; //!< query descriptor index + CV_PROP_RW int trainIdx; //!< train descriptor index + CV_PROP_RW int imgIdx; //!< train image index CV_PROP_RW float distance; @@ -742,6 +810,7 @@ public: bool operator<(const DMatch &m) const; }; +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED template<> class DataType { public: @@ -758,7 +827,7 @@ public: typedef Vec vec_type; }; - +#endif ///////////////////////////// TermCriteria ////////////////////////////// @@ -790,9 +859,16 @@ public: */ TermCriteria(int type, int maxCount, double epsilon); + inline bool isValid() const + { + const bool isCount = (type & COUNT) && maxCount > 0; + const bool isEps = (type & EPS) && !cvIsNaN(epsilon); + return isCount || isEps; + } + int type; //!< the type of termination criteria: COUNT, EPS or COUNT + EPS - int maxCount; // the maximum number of iterations/elements - double epsilon; // the desired accuracy + int maxCount; //!< the maximum number of iterations/elements + double epsilon; //!< the desired accuracy }; @@ -872,15 +948,24 @@ public: typedef double channel_type; enum { generic_type = 0, - depth = DataType::depth, channels = (int)(sizeof(value_type)/sizeof(channel_type)), // 24 - fmt = DataType::fmt + ((channels - 1) << 8), - type = CV_MAKETYPE(depth, channels) + fmt = DataType::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif }; typedef Vec vec_type; }; +namespace traits { +template<> +struct Depth< Moments > { enum { value = Depth::value }; }; +template<> +struct Type< Moments > { enum { value = CV_MAKETYPE(Depth::value, (int)(sizeof(Moments)/sizeof(double))) }; }; +} // namespace + //! @} imgproc_shape //! @cond IGNORED @@ -1031,7 +1116,8 @@ Complex<_Tp> operator / (const Complex<_Tp>& a, const Complex<_Tp>& b) template static inline Complex<_Tp>& operator /= (Complex<_Tp>& a, const Complex<_Tp>& b) { - return (a = a / b); + a = a / b; + return a; } template static inline @@ -1297,6 +1383,20 @@ Point_<_Tp> operator / (const Point_<_Tp>& a, double b) } +template static inline _AccTp normL2Sqr(const Point_& pt); +template static inline _AccTp normL2Sqr(const Point_& pt); +template static inline _AccTp normL2Sqr(const Point_& pt); +template static inline _AccTp normL2Sqr(const Point_& pt); + +template<> inline int normL2Sqr(const Point_& pt) { return pt.dot(pt); } +template<> inline int64 normL2Sqr(const Point_& pt) { return pt.dot(pt); } +template<> inline float normL2Sqr(const Point_& pt) { return pt.dot(pt); } +template<> inline double normL2Sqr(const Point_& pt) { return pt.dot(pt); } + +template<> inline double normL2Sqr(const Point_& pt) { return pt.ddot(pt); } +template<> inline double normL2Sqr(const Point_& pt) { return pt.ddot(pt); } + + //////////////////////////////// 3D Point /////////////////////////////// @@ -1326,11 +1426,19 @@ Point3_<_Tp>::operator Point3_<_Tp2>() const return Point3_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(z)); } +#if OPENCV_ABI_COMPATIBILITY > 300 +template template inline +Point3_<_Tp>::operator Vec<_Tp2, 3>() const +{ + return Vec<_Tp2, 3>(x, y, z); +} +#else template inline Point3_<_Tp>::operator Vec<_Tp, 3>() const { return Vec<_Tp, 3>(x, y, z); } +#endif template inline Point3_<_Tp>& Point3_<_Tp>::operator = (const Point3_& pt) @@ -1575,9 +1683,19 @@ Size_<_Tp>& Size_<_Tp>::operator = (const Size_<_Tp>& sz) template inline _Tp Size_<_Tp>::area() const { - return width * height; + const _Tp result = width * height; + CV_DbgAssert(!std::numeric_limits<_Tp>::is_integer + || width == 0 || result / width == height); // make sure the result fits in the return value + return result; } +template inline +bool Size_<_Tp>::empty() const +{ + return width <= 0 || height <= 0; +} + + template static inline Size_<_Tp>& operator *= (Size_<_Tp>& a, _Tp b) { @@ -1714,7 +1832,16 @@ Size_<_Tp> Rect_<_Tp>::size() const template inline _Tp Rect_<_Tp>::area() const { - return width * height; + const _Tp result = width * height; + CV_DbgAssert(!std::numeric_limits<_Tp>::is_integer + || width == 0 || result / width == height); // make sure the result fits in the return value + return result; +} + +template inline +bool Rect_<_Tp>::empty() const +{ + return width <= 0 || height <= 0; } template template inline @@ -1757,8 +1884,11 @@ Rect_<_Tp>& operator += ( Rect_<_Tp>& a, const Size_<_Tp>& b ) template static inline Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Size_<_Tp>& b ) { - a.width -= b.width; - a.height -= b.height; + const _Tp width = a.width - b.width; + const _Tp height = a.height - b.height; + CV_DbgAssert(width >= 0 && height >= 0); + a.width = width; + a.height = height; return a; } @@ -1779,12 +1909,17 @@ Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) template static inline Rect_<_Tp>& operator |= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) { - _Tp x1 = std::min(a.x, b.x); - _Tp y1 = std::min(a.y, b.y); - a.width = std::max(a.x + a.width, b.x + b.width) - x1; - a.height = std::max(a.y + a.height, b.y + b.height) - y1; - a.x = x1; - a.y = y1; + if (a.empty()) { + a = b; + } + else if (!b.empty()) { + _Tp x1 = std::min(a.x, b.x); + _Tp y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + } return a; } @@ -1818,6 +1953,15 @@ Rect_<_Tp> operator + (const Rect_<_Tp>& a, const Size_<_Tp>& b) return Rect_<_Tp>( a.x, a.y, a.width + b.width, a.height + b.height ); } +template static inline +Rect_<_Tp> operator - (const Rect_<_Tp>& a, const Size_<_Tp>& b) +{ + const _Tp width = a.width - b.width; + const _Tp height = a.height - b.height; + CV_DbgAssert(width >= 0 && height >= 0); + return Rect_<_Tp>( a.x, a.y, width, height ); +} + template static inline Rect_<_Tp> operator & (const Rect_<_Tp>& a, const Rect_<_Tp>& b) { @@ -1832,7 +1976,26 @@ Rect_<_Tp> operator | (const Rect_<_Tp>& a, const Rect_<_Tp>& b) return c |= b; } +/** + * @brief measure dissimilarity between two sample sets + * + * computes the complement of the Jaccard Index as described in . + * For rectangles this reduces to computing the intersection over the union. + */ +template static inline +double jaccardDistance(const Rect_<_Tp>& a, const Rect_<_Tp>& b) { + _Tp Aa = a.area(); + _Tp Ab = b.area(); + if ((Aa + Ab) <= std::numeric_limits<_Tp>::epsilon()) { + // jaccard_index = 1 -> distance = 0 + return 0.0; + } + + double Aab = (a & b).area(); + // distance = 1 - jaccard_index + return 1.0 - Aab / (Aa + Ab - Aab); +} ////////////////////////////// RotatedRect ////////////////////////////// @@ -2225,4 +2388,4 @@ TermCriteria::TermCriteria(int _type, int _maxCount, double _epsilon) } // cv -#endif //__OPENCV_CORE_TYPES_HPP__ +#endif //OPENCV_CORE_TYPES_HPP diff --git a/include/opencv2/core/types_c.h b/include/opencv2/core/types_c.h index cb39587..5f63eb8 100644 --- a/include/opencv2/core/types_c.h +++ b/include/opencv2/core/types_c.h @@ -41,12 +41,35 @@ // //M*/ -#ifndef __OPENCV_CORE_TYPES_H__ -#define __OPENCV_CORE_TYPES_H__ +#ifndef OPENCV_CORE_TYPES_H +#define OPENCV_CORE_TYPES_H + +#if !defined(__OPENCV_BUILD) && !defined(CV__DISABLE_C_API_CTORS) +#define CV__ENABLE_C_API_CTORS // enable C API ctors (must be removed) +#endif + +//#define CV__VALIDATE_UNUNITIALIZED_VARS 1 // C++11 & GCC only + +#ifdef __cplusplus + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#define CV_STRUCT_INITIALIZER {0,} +#else +#if defined(__GNUC__) && __GNUC__ == 4 // GCC 4.x warns on "= {}" initialization, fixed in GCC 5.0 +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif +#define CV_STRUCT_INITIALIZER {} +#endif + +#else +#define CV_STRUCT_INITIALIZER {0} +#endif + #ifdef HAVE_IPL # ifndef __IPL_H__ -# if defined WIN32 || defined _WIN32 +# if defined _WIN32 # include # else # include @@ -65,7 +88,7 @@ #include #endif // SKIP_INCLUDES -#if defined WIN32 || defined _WIN32 +#if defined _WIN32 # define CV_CDECL __cdecl # define CV_STDCALL __stdcall #else @@ -130,24 +153,24 @@ enum { CV_BadImageSize= -10, /**< image size is invalid */ CV_BadOffset= -11, /**< offset is invalid */ CV_BadDataPtr= -12, /**/ - CV_BadStep= -13, /**/ + CV_BadStep= -13, /**< image step is wrong, this may happen for a non-continuous matrix */ CV_BadModelOrChSeq= -14, /**/ - CV_BadNumChannels= -15, /**/ + CV_BadNumChannels= -15, /**< bad number of channels, for example, some functions accept only single channel matrices */ CV_BadNumChannel1U= -16, /**/ - CV_BadDepth= -17, /**/ + CV_BadDepth= -17, /**< input image depth is not supported by the function */ CV_BadAlphaChannel= -18, /**/ - CV_BadOrder= -19, /**/ - CV_BadOrigin= -20, /**/ - CV_BadAlign= -21, /**/ + CV_BadOrder= -19, /**< number of dimensions is out of range */ + CV_BadOrigin= -20, /**< incorrect input origin */ + CV_BadAlign= -21, /**< incorrect input align */ CV_BadCallBack= -22, /**/ CV_BadTileSize= -23, /**/ - CV_BadCOI= -24, /**/ - CV_BadROISize= -25, /**/ + CV_BadCOI= -24, /**< input COI is not supported */ + CV_BadROISize= -25, /**< incorrect input roi */ CV_MaskIsTiled= -26, /**/ CV_StsNullPtr= -27, /**< null pointer */ CV_StsVecLengthErr= -28, /**< incorrect vector length */ - CV_StsFilterStructContentErr= -29, /**< incorr. filter structure content */ - CV_StsKernelStructContentErr= -30, /**< incorr. transform kernel content */ + CV_StsFilterStructContentErr= -29, /**< incorrect filter structure content */ + CV_StsKernelStructContentErr= -30, /**< incorrect transform kernel content */ CV_StsFilterOffsetErr= -31, /**< incorrect filter offset value */ CV_StsBadSize= -201, /**< the input/output structure size is incorrect */ CV_StsDivByZero= -202, /**< division by zero */ @@ -163,14 +186,14 @@ enum { CV_StsParseError= -212, /**< invalid syntax/structure of the parsed file */ CV_StsNotImplemented= -213, /**< the requested function/feature is not implemented */ CV_StsBadMemBlock= -214, /**< an allocated block has been corrupted */ - CV_StsAssert= -215, /**< assertion failed */ - CV_GpuNotSupported= -216, - CV_GpuApiCallError= -217, - CV_OpenGlNotSupported= -218, - CV_OpenGlApiCallError= -219, - CV_OpenCLApiCallError= -220, + CV_StsAssert= -215, /**< assertion failed */ + CV_GpuNotSupported= -216, /**< no CUDA support */ + CV_GpuApiCallError= -217, /**< GPU API call error */ + CV_OpenGlNotSupported= -218, /**< no OpenGL support */ + CV_OpenGlApiCallError= -219, /**< OpenGL API call error */ + CV_OpenCLApiCallError= -220, /**< OpenCL API call error */ CV_OpenCLDoubleNotSupported= -221, - CV_OpenCLInitError= -222, + CV_OpenCLInitError= -222, /**< OpenCL initialization error */ CV_OpenCLNoAMDBlasFft= -223 }; @@ -285,6 +308,11 @@ CV_INLINE double cvRandReal( CvRNG* rng ) #define IPL_BORDER_REFLECT 2 #define IPL_BORDER_WRAP 3 +#ifdef __cplusplus +typedef struct _IplImage IplImage; +CV_EXPORTS _IplImage cvIplImage(const cv::Mat& m); +#endif + /** The IplImage is taken from the Intel Image Processing Library, in which the format is native. OpenCV only supports a subset of possible IplImage formats, as outlined in the parameter list above. @@ -294,9 +322,6 @@ hand, the Intel Image Processing Library processes the area of intersection betw destination images (or ROIs), allowing them to vary independently. */ typedef struct -#ifdef __cplusplus - CV_EXPORTS -#endif _IplImage { int nSize; /**< sizeof(IplImage) */ @@ -330,13 +355,22 @@ _IplImage (not necessarily aligned) - needed for correct deallocation */ -#ifdef __cplusplus +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) _IplImage() {} - _IplImage(const cv::Mat& m); + _IplImage(const cv::Mat& m) { *this = cvIplImage(m); } #endif } IplImage; +CV_INLINE IplImage cvIplImage() +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + IplImage self = CV_STRUCT_INITIALIZER; self.nSize = sizeof(IplImage); return self; +#else + return _IplImage(); +#endif +} + typedef struct _IplTileInfo IplTileInfo; typedef struct _IplROI @@ -409,6 +443,11 @@ IplConvKernelFP; #define CV_MAT_MAGIC_VAL 0x42420000 #define CV_TYPE_NAME_MAT "opencv-matrix" +#ifdef __cplusplus +typedef struct CvMat CvMat; +CV_INLINE CvMat cvMat(const cv::Mat& m); +#endif + /** Matrix elements are stored row by row. Element (i, j) (i - 0-based row index, j - 0-based column index) of a matrix can be retrieved or modified using CV_MAT_ELEM macro: @@ -455,13 +494,10 @@ typedef struct CvMat int cols; #endif - -#ifdef __cplusplus +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvMat() {} - CvMat(const CvMat& m) { memcpy(this, &m, sizeof(CvMat));} - CvMat(const cv::Mat& m); + CvMat(const cv::Mat& m) { *this = cvMat(m); } #endif - } CvMat; @@ -524,14 +560,34 @@ CV_INLINE CvMat cvMat( int rows, int cols, int type, void* data CV_DEFAULT(NULL) } #ifdef __cplusplus -inline CvMat::CvMat(const cv::Mat& m) + +CV_INLINE CvMat cvMat(const cv::Mat& m) { + CvMat self; CV_DbgAssert(m.dims <= 2); - *this = cvMat(m.rows, m.dims == 1 ? 1 : m.cols, m.type(), m.data); - step = (int)m.step[0]; - type = (type & ~cv::Mat::CONTINUOUS_FLAG) | (m.flags & cv::Mat::CONTINUOUS_FLAG); + self = cvMat(m.rows, m.dims == 1 ? 1 : m.cols, m.type(), m.data); + self.step = (int)m.step[0]; + self.type = (self.type & ~cv::Mat::CONTINUOUS_FLAG) | (m.flags & cv::Mat::CONTINUOUS_FLAG); + return self; } +CV_INLINE CvMat cvMat() +{ +#if !defined(CV__ENABLE_C_API_CTORS) + CvMat self = CV_STRUCT_INITIALIZER; return self; +#else + return CvMat(); #endif +} +CV_INLINE CvMat cvMat(const CvMat& m) +{ +#if !defined(CV__ENABLE_C_API_CTORS) + CvMat self = CV_STRUCT_INITIALIZER; memcpy(&self, &m, sizeof(self)); return self; +#else + return CvMat(m); +#endif +} + +#endif // __cplusplus #define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ @@ -614,15 +670,16 @@ CV_INLINE int cvIplDepth( int type ) #define CV_TYPE_NAME_MATND "opencv-nd-matrix" #define CV_MAX_DIM 32 -#define CV_MAX_DIM_HEAP 1024 + +#ifdef __cplusplus +typedef struct CvMatND CvMatND; +CV_EXPORTS CvMatND cvMatND(const cv::Mat& m); +#endif /** @deprecated consider using cv::Mat instead */ typedef struct -#ifdef __cplusplus - CV_EXPORTS -#endif CvMatND { int type; @@ -647,13 +704,23 @@ CvMatND } dim[CV_MAX_DIM]; -#ifdef __cplusplus +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvMatND() {} - CvMatND(const cv::Mat& m); + CvMatND(const cv::Mat& m) { *this = cvMatND(m); } #endif } CvMatND; + +CV_INLINE CvMatND cvMatND() +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvMatND self = CV_STRUCT_INITIALIZER; return self; +#else + return CvMatND(); +#endif +} + #define CV_IS_MATND_HDR(mat) \ ((mat) != NULL && (((const CvMatND*)(mat))->type & CV_MAGIC_MASK) == CV_MATND_MAGIC_VAL) @@ -670,11 +737,7 @@ CvMatND; struct CvSet; -typedef struct -#ifdef __cplusplus - CV_EXPORTS -#endif -CvSparseMat +typedef struct CvSparseMat { int type; int dims; @@ -689,13 +752,13 @@ CvSparseMat int size[CV_MAX_DIM]; #ifdef __cplusplus - void copyToSparseMat(cv::SparseMat& m) const; + CV_EXPORTS void copyToSparseMat(cv::SparseMat& m) const; #endif } CvSparseMat; #ifdef __cplusplus - CV_EXPORTS CvSparseMat* cvCreateSparseMat(const cv::SparseMat& m); +CV_EXPORTS CvSparseMat* cvCreateSparseMat(const cv::SparseMat& m); #endif #define CV_IS_SPARSE_MAT_HDR(mat) \ @@ -782,10 +845,23 @@ typedef struct CvRect int width; int height; -#ifdef __cplusplus +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvRect() __attribute__(( warning("Non-initialized variable") )) {}; + template CvRect(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 4); + x = y = width = height = 0; + if (list.size() == 4) + { + x = list.begin()[0]; y = list.begin()[1]; width = list.begin()[2]; height = list.begin()[3]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvRect(int _x = 0, int _y = 0, int w = 0, int h = 0): x(_x), y(_y), width(w), height(h) {} template CvRect(const cv::Rect_<_Tp>& r): x(cv::saturate_cast(r.x)), y(cv::saturate_cast(r.y)), width(cv::saturate_cast(r.width)), height(cv::saturate_cast(r.height)) {} +#endif +#ifdef __cplusplus template operator cv::Rect_<_Tp>() const { return cv::Rect_<_Tp>((_Tp)x, (_Tp)y, (_Tp)width, (_Tp)height); } #endif @@ -795,16 +871,16 @@ CvRect; /** constructs CvRect structure. */ CV_INLINE CvRect cvRect( int x, int y, int width, int height ) { - CvRect r; - - r.x = x; - r.y = y; - r.width = width; - r.height = height; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvRect r = {x, y, width, height}; +#else + CvRect r(x, y , width, height); +#endif return r; } - +#ifdef __cplusplus +CV_INLINE CvRect cvRect(const cv::Rect& rc) { return cvRect(rc.x, rc.y, rc.width, rc.height); } +#endif CV_INLINE IplROI cvRectToROI( CvRect rect, int coi ) { @@ -839,26 +915,28 @@ typedef struct CvTermCriteria CV_TERMCRIT_EPS */ int max_iter; double epsilon; - -#ifdef __cplusplus +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvTermCriteria(int _type = 0, int _iter = 0, double _eps = 0) : type(_type), max_iter(_iter), epsilon(_eps) {} CvTermCriteria(const cv::TermCriteria& t) : type(t.type), max_iter(t.maxCount), epsilon(t.epsilon) {} +#endif +#ifdef __cplusplus operator cv::TermCriteria() const { return cv::TermCriteria(type, max_iter, epsilon); } #endif - } CvTermCriteria; CV_INLINE CvTermCriteria cvTermCriteria( int type, int max_iter, double epsilon ) { - CvTermCriteria t; - - t.type = type; - t.max_iter = max_iter; - t.epsilon = (float)epsilon; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvTermCriteria t = { type, max_iter, (float)epsilon}; +#else + CvTermCriteria t(type, max_iter, epsilon); +#endif return t; } +#ifdef __cplusplus +CV_INLINE CvTermCriteria cvTermCriteria(const cv::TermCriteria& t) { return cvTermCriteria(t.type, t.maxCount, t.epsilon); } +#endif /******************************* CvPoint and variants ***********************************/ @@ -868,10 +946,23 @@ typedef struct CvPoint int x; int y; -#ifdef __cplusplus +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + x = y = 0; + if (list.size() == 2) + { + x = list.begin()[0]; y = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvPoint(int _x = 0, int _y = 0): x(_x), y(_y) {} template CvPoint(const cv::Point_<_Tp>& pt): x((int)pt.x), y((int)pt.y) {} +#endif +#ifdef __cplusplus template operator cv::Point_<_Tp>() const { return cv::Point_<_Tp>(cv::saturate_cast<_Tp>(x), cv::saturate_cast<_Tp>(y)); } #endif @@ -881,24 +972,39 @@ CvPoint; /** constructs CvPoint structure. */ CV_INLINE CvPoint cvPoint( int x, int y ) { - CvPoint p; - - p.x = x; - p.y = y; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint p = {x, y}; +#else + CvPoint p(x, y); +#endif return p; } - +#ifdef __cplusplus +CV_INLINE CvPoint cvPoint(const cv::Point& pt) { return cvPoint(pt.x, pt.y); } +#endif typedef struct CvPoint2D32f { float x; float y; -#ifdef __cplusplus +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint2D32f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint2D32f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + x = y = 0; + if (list.size() == 2) + { + x = list.begin()[0]; y = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvPoint2D32f(float _x = 0, float _y = 0): x(_x), y(_y) {} template CvPoint2D32f(const cv::Point_<_Tp>& pt): x((float)pt.x), y((float)pt.y) {} +#endif +#ifdef __cplusplus template operator cv::Point_<_Tp>() const { return cv::Point_<_Tp>(cv::saturate_cast<_Tp>(x), cv::saturate_cast<_Tp>(y)); } #endif @@ -908,14 +1014,27 @@ CvPoint2D32f; /** constructs CvPoint2D32f structure. */ CV_INLINE CvPoint2D32f cvPoint2D32f( double x, double y ) { - CvPoint2D32f p; - - p.x = (float)x; - p.y = (float)y; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint2D32f p = { (float)x, (float)y }; +#else + CvPoint2D32f p((float)x, (float)y); +#endif return p; } +#ifdef __cplusplus +template +CvPoint2D32f cvPoint2D32f(const cv::Point_<_Tp>& pt) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint2D32f p = { (float)pt.x, (float)pt.y }; +#else + CvPoint2D32f p((float)pt.x, (float)pt.y); +#endif + return p; +} +#endif + /** converts CvPoint to CvPoint2D32f. */ CV_INLINE CvPoint2D32f cvPointTo32f( CvPoint point ) { @@ -925,10 +1044,11 @@ CV_INLINE CvPoint2D32f cvPointTo32f( CvPoint point ) /** converts CvPoint2D32f to CvPoint. */ CV_INLINE CvPoint cvPointFrom32f( CvPoint2D32f point ) { - CvPoint ipt; - ipt.x = cvRound(point.x); - ipt.y = cvRound(point.y); - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint ipt = { cvRound(point.x), cvRound(point.y) }; +#else + CvPoint ipt(cvRound(point.x), cvRound(point.y)); +#endif return ipt; } @@ -939,10 +1059,23 @@ typedef struct CvPoint3D32f float y; float z; -#ifdef __cplusplus +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint3D32f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint3D32f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 3); + x = y = z = 0; + if (list.size() == 3) + { + x = list.begin()[0]; y = list.begin()[1]; z = list.begin()[2]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvPoint3D32f(float _x = 0, float _y = 0, float _z = 0): x(_x), y(_y), z(_z) {} template CvPoint3D32f(const cv::Point3_<_Tp>& pt): x((float)pt.x), y((float)pt.y), z((float)pt.z) {} +#endif +#ifdef __cplusplus template operator cv::Point3_<_Tp>() const { return cv::Point3_<_Tp>(cv::saturate_cast<_Tp>(x), cv::saturate_cast<_Tp>(y), cv::saturate_cast<_Tp>(z)); } #endif @@ -952,31 +1085,51 @@ CvPoint3D32f; /** constructs CvPoint3D32f structure. */ CV_INLINE CvPoint3D32f cvPoint3D32f( double x, double y, double z ) { - CvPoint3D32f p; - - p.x = (float)x; - p.y = (float)y; - p.z = (float)z; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint3D32f p = { (float)x, (float)y, (float)z }; +#else + CvPoint3D32f p((float)x, (float)y, (float)z); +#endif return p; } +#ifdef __cplusplus +template +CvPoint3D32f cvPoint3D32f(const cv::Point3_<_Tp>& pt) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint3D32f p = { (float)pt.x, (float)pt.y, (float)pt.z }; +#else + CvPoint3D32f p((float)pt.x, (float)pt.y, (float)pt.z); +#endif + return p; +} +#endif + typedef struct CvPoint2D64f { double x; double y; +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint2D64f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint2D64f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + x = y = 0; + if (list.size() == 2) + { + x = list.begin()[0]; y = list.begin()[1]; + } + }; +#endif } CvPoint2D64f; /** constructs CvPoint2D64f structure.*/ CV_INLINE CvPoint2D64f cvPoint2D64f( double x, double y ) { - CvPoint2D64f p; - - p.x = x; - p.y = y; - + CvPoint2D64f p = { x, y }; return p; } @@ -986,18 +1139,25 @@ typedef struct CvPoint3D64f double x; double y; double z; +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint3D64f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint3D64f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 3); + x = y = z = 0; + if (list.size() == 3) + { + x = list.begin()[0]; y = list.begin()[1]; z = list.begin()[2]; + } + }; +#endif } CvPoint3D64f; /** constructs CvPoint3D64f structure. */ CV_INLINE CvPoint3D64f cvPoint3D64f( double x, double y, double z ) { - CvPoint3D64f p; - - p.x = x; - p.y = y; - p.z = z; - + CvPoint3D64f p = { x, y, z }; return p; } @@ -1009,10 +1169,23 @@ typedef struct CvSize int width; int height; -#ifdef __cplusplus +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvSize() __attribute__(( warning("Non-initialized variable") )) {} + template CvSize(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + width = 0; height = 0; + if (list.size() == 2) + { + width = list.begin()[0]; height = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvSize(int w = 0, int h = 0): width(w), height(h) {} template CvSize(const cv::Size_<_Tp>& sz): width(cv::saturate_cast(sz.width)), height(cv::saturate_cast(sz.height)) {} +#endif +#ifdef __cplusplus template operator cv::Size_<_Tp>() const { return cv::Size_<_Tp>(cv::saturate_cast<_Tp>(width), cv::saturate_cast<_Tp>(height)); } #endif @@ -1022,23 +1195,48 @@ CvSize; /** constructs CvSize structure. */ CV_INLINE CvSize cvSize( int width, int height ) { - CvSize s; - - s.width = width; - s.height = height; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize s = { width, height }; +#else + CvSize s(width, height); +#endif return s; } +#ifdef __cplusplus +CV_INLINE CvSize cvSize(const cv::Size& sz) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize s = { sz.width, sz.height }; +#else + CvSize s(sz.width, sz.height); +#endif + return s; +} +#endif + typedef struct CvSize2D32f { float width; float height; -#ifdef __cplusplus +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvSize2D32f() __attribute__(( warning("Non-initialized variable") )) {} + template CvSize2D32f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + width = 0; height = 0; + if (list.size() == 2) + { + width = list.begin()[0]; height = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvSize2D32f(float w = 0, float h = 0): width(w), height(h) {} template CvSize2D32f(const cv::Size_<_Tp>& sz): width(cv::saturate_cast(sz.width)), height(cv::saturate_cast(sz.height)) {} +#endif +#ifdef __cplusplus template operator cv::Size_<_Tp>() const { return cv::Size_<_Tp>(cv::saturate_cast<_Tp>(width), cv::saturate_cast<_Tp>(height)); } #endif @@ -1048,13 +1246,25 @@ CvSize2D32f; /** constructs CvSize2D32f structure. */ CV_INLINE CvSize2D32f cvSize2D32f( double width, double height ) { - CvSize2D32f s; - - s.width = (float)width; - s.height = (float)height; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize2D32f s = { (float)width, (float)height }; +#else + CvSize2D32f s((float)width, (float)height); +#endif return s; } +#ifdef __cplusplus +template +CvSize2D32f cvSize2D32f(const cv::Size_<_Tp>& sz) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize2D32f s = { (float)sz.width, (float)sz.height }; +#else + CvSize2D32f s((float)sz.width, (float)sz.height); +#endif + return s; +} +#endif /** @sa RotatedRect */ @@ -1065,15 +1275,37 @@ typedef struct CvBox2D float angle; /**< Angle between the horizontal axis */ /**< and the first side (i.e. length) in degrees */ -#ifdef __cplusplus +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvBox2D(CvPoint2D32f c = CvPoint2D32f(), CvSize2D32f s = CvSize2D32f(), float a = 0) : center(c), size(s), angle(a) {} CvBox2D(const cv::RotatedRect& rr) : center(rr.center), size(rr.size), angle(rr.angle) {} +#endif +#ifdef __cplusplus operator cv::RotatedRect() const { return cv::RotatedRect(center, size, angle); } #endif } CvBox2D; +#ifdef __cplusplus +CV_INLINE CvBox2D cvBox2D(CvPoint2D32f c = CvPoint2D32f(), CvSize2D32f s = CvSize2D32f(), float a = 0) +{ + CvBox2D self; + self.center = c; + self.size = s; + self.angle = a; + return self; +} +CV_INLINE CvBox2D cvBox2D(const cv::RotatedRect& rr) +{ + CvBox2D self; + self.center = cvPoint2D32f(rr.center); + self.size = cvSize2D32f(rr.size); + self.angle = rr.angle; + return self; +} +#endif + + /** Line iterator state: */ typedef struct CvLineIterator { @@ -1099,7 +1331,19 @@ typedef struct CvSlice { int start_index, end_index; -#if defined(__cplusplus) && !defined(__CUDACC__) +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvSlice() __attribute__(( warning("Non-initialized variable") )) {} + template CvSlice(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + start_index = end_index = 0; + if (list.size() == 2) + { + start_index = list.begin()[0]; end_index = list.begin()[1]; + } + }; +#endif +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) && !defined(__CUDACC__) CvSlice(int start = 0, int end = 0) : start_index(start), end_index(end) {} CvSlice(const cv::Range& r) { *this = (r.start != INT_MIN && r.end != INT_MAX) ? CvSlice(r.start, r.end) : CvSlice(0, CV_WHOLE_SEQ_END_INDEX); } operator cv::Range() const { return (start_index == 0 && end_index == CV_WHOLE_SEQ_END_INDEX ) ? cv::Range::all() : cv::Range(start_index, end_index); } @@ -1109,13 +1353,21 @@ CvSlice; CV_INLINE CvSlice cvSlice( int start, int end ) { - CvSlice slice; - slice.start_index = start; - slice.end_index = end; - +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) && !defined(__CUDACC__)) + CvSlice slice = { start, end }; +#else + CvSlice slice(start, end); +#endif return slice; } +#if defined(__cplusplus) +CV_INLINE CvSlice cvSlice(const cv::Range& r) +{ + CvSlice slice = (r.start != INT_MIN && r.end != INT_MAX) ? cvSlice(r.start, r.end) : cvSlice(0, CV_WHOLE_SEQ_END_INDEX); + return slice; +} +#endif /************************************* CvScalar *****************************************/ @@ -1125,13 +1377,22 @@ typedef struct CvScalar { double val[4]; -#ifdef __cplusplus +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvScalar() __attribute__(( warning("Non-initialized variable") )) {} + CvScalar(const std::initializer_list list) + { + CV_Assert(list.size() == 0 || list.size() == 4); + val[0] = val[1] = val[2] = val[3] = 0; + if (list.size() == 4) + { + val[0] = list.begin()[0]; val[1] = list.begin()[1]; val[2] = list.begin()[2]; val[3] = list.begin()[3]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvScalar() {} CvScalar(double d0, double d1 = 0, double d2 = 0, double d3 = 0) { val[0] = d0; val[1] = d1; val[2] = d2; val[3] = d3; } template CvScalar(const cv::Scalar_<_Tp>& s) { val[0] = s.val[0]; val[1] = s.val[1]; val[2] = s.val[2]; val[3] = s.val[3]; } - template - operator cv::Scalar_<_Tp>() const { return cv::Scalar_<_Tp>(cv::saturate_cast<_Tp>(val[0]), cv::saturate_cast<_Tp>(val[1]), cv::saturate_cast<_Tp>(val[2]), cv::saturate_cast<_Tp>(val[3])); } template CvScalar(const cv::Vec<_Tp, cn>& v) { @@ -1140,22 +1401,59 @@ typedef struct CvScalar for( ; i < 4; i++ ) val[i] = 0; } #endif +#ifdef __cplusplus + template + operator cv::Scalar_<_Tp>() const { return cv::Scalar_<_Tp>(cv::saturate_cast<_Tp>(val[0]), cv::saturate_cast<_Tp>(val[1]), cv::saturate_cast<_Tp>(val[2]), cv::saturate_cast<_Tp>(val[3])); } +#endif } CvScalar; CV_INLINE CvScalar cvScalar( double val0, double val1 CV_DEFAULT(0), double val2 CV_DEFAULT(0), double val3 CV_DEFAULT(0)) { +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else CvScalar scalar; +#endif scalar.val[0] = val0; scalar.val[1] = val1; scalar.val[2] = val2; scalar.val[3] = val3; return scalar; } +#ifdef __cplusplus +CV_INLINE CvScalar cvScalar() +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else + CvScalar scalar; +#endif + scalar.val[0] = scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; + return scalar; +} +CV_INLINE CvScalar cvScalar(const cv::Scalar& s) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else + CvScalar scalar; +#endif + scalar.val[0] = s.val[0]; + scalar.val[1] = s.val[1]; + scalar.val[2] = s.val[2]; + scalar.val[3] = s.val[3]; + return scalar; +} +#endif CV_INLINE CvScalar cvRealScalar( double val0 ) { +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else CvScalar scalar; +#endif scalar.val[0] = val0; scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; return scalar; @@ -1163,7 +1461,11 @@ CV_INLINE CvScalar cvRealScalar( double val0 ) CV_INLINE CvScalar cvScalarAll( double val0123 ) { +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else CvScalar scalar; +#endif scalar.val[0] = val0123; scalar.val[1] = val0123; scalar.val[2] = val0123; @@ -1216,7 +1518,7 @@ typedef struct CvSeqBlock { struct CvSeqBlock* prev; /**< Previous sequence block. */ struct CvSeqBlock* next; /**< Next sequence block. */ - int start_index; /**< Index of the first element in the block + */ + int start_index; /**< Index of the first element in the block + */ /**< sequence->first->start_index. */ int count; /**< Number of elements in the block. */ schar* data; /**< Pointer to the first element of the block. */ @@ -1361,7 +1663,7 @@ CvGraph; /** @} */ -/*********************************** Chain/Countour *************************************/ +/*********************************** Chain/Contour *************************************/ typedef struct CvChain { @@ -1669,6 +1971,9 @@ typedef struct CvFileStorage CvFileStorage; #define CV_STORAGE_FORMAT_AUTO 0 #define CV_STORAGE_FORMAT_XML 8 #define CV_STORAGE_FORMAT_YAML 16 +#define CV_STORAGE_FORMAT_JSON 24 +#define CV_STORAGE_BASE64 64 +#define CV_STORAGE_WRITE_BASE64 (CV_STORAGE_BASE64 | CV_STORAGE_WRITE) /** @brief List of attributes. : @@ -1738,7 +2043,7 @@ typedef struct CvString } CvString; -/** All the keys (names) of elements in the readed file storage +/** All the keys (names) of elements in the read file storage are stored in the hash to speed up the lookup operations: */ typedef struct CvStringHashNode { @@ -1829,6 +2134,6 @@ CvModuleInfo; /** @} */ -#endif /*__OPENCV_CORE_TYPES_H__*/ +#endif /*OPENCV_CORE_TYPES_H*/ /* End of file. */ diff --git a/include/opencv2/core/utility.hpp b/include/opencv2/core/utility.hpp index 3ec0660..7a7158f 100644 --- a/include/opencv2/core/utility.hpp +++ b/include/opencv2/core/utility.hpp @@ -42,14 +42,23 @@ // //M*/ -#ifndef __OPENCV_CORE_UTILITY_H__ -#define __OPENCV_CORE_UTILITY_H__ +#ifndef OPENCV_CORE_UTILITY_H +#define OPENCV_CORE_UTILITY_H #ifndef __cplusplus # error utility.hpp header must be compiled as C++ #endif +#if defined(check) +# warning Detected Apple 'check' macro definition, it can cause build conflicts. Please, include this header before any Apple headers. +#endif + #include "opencv2/core.hpp" +#include + +#ifdef CV_CXX11 +#include +#endif namespace cv { @@ -57,8 +66,8 @@ namespace cv #ifdef CV_COLLECT_IMPL_DATA CV_EXPORTS void setImpl(int flags); // set implementation flags and reset storage arrays CV_EXPORTS void addImpl(int flag, const char* func = 0); // add implementation and function name to storage arrays -// Get stored implementation flags and fucntions names arrays -// Each implementation entry correspond to function name entry, so you can find which implementation was executed in which fucntion +// Get stored implementation flags and functions names arrays +// Each implementation entry correspond to function name entry, so you can find which implementation was executed in which function CV_EXPORTS int getImpl(std::vector &impl, std::vector &funName); CV_EXPORTS bool useCollection(); // return implementation collection state @@ -98,7 +107,7 @@ CV_EXPORTS void setUseCollection(bool flag); // set implementation collection st \code void my_func(const cv::Mat& m) { - cv::AutoBuffer buf; // create automatic buffer containing 1000 floats + cv::AutoBuffer buf(1000); // create automatic buffer containing 1000 floats buf.allocate(m.rows); // if m.rows <= 1000, the pre-allocated buffer is used, // otherwise the buffer of "m.rows" floats will be allocated @@ -115,7 +124,7 @@ public: //! the default constructor AutoBuffer(); //! constructor taking the real buffer size - AutoBuffer(size_t _size); + explicit AutoBuffer(size_t _size); //! the copy constructor AutoBuffer(const AutoBuffer<_Tp, fixed_size>& buf); @@ -133,17 +142,29 @@ public: void resize(size_t _size); //! returns the current buffer size size_t size() const; - //! returns pointer to the real buffer, stack-allocated or head-allocated - operator _Tp* (); - //! returns read-only pointer to the real buffer, stack-allocated or head-allocated - operator const _Tp* () const; + //! returns pointer to the real buffer, stack-allocated or heap-allocated + inline _Tp* data() { return ptr; } + //! returns read-only pointer to the real buffer, stack-allocated or heap-allocated + inline const _Tp* data() const { return ptr; } + +#if !defined(OPENCV_DISABLE_DEPRECATED_COMPATIBILITY) // use to .data() calls instead + //! returns pointer to the real buffer, stack-allocated or heap-allocated + operator _Tp* () { return ptr; } + //! returns read-only pointer to the real buffer, stack-allocated or heap-allocated + operator const _Tp* () const { return ptr; } +#else + //! returns a reference to the element at specified location. No bounds checking is performed in Release builds. + inline _Tp& operator[] (size_t i) { CV_DbgCheckLT(i, sz, "out of range"); return ptr[i]; } + //! returns a reference to the element at specified location. No bounds checking is performed in Release builds. + inline const _Tp& operator[] (size_t i) const { CV_DbgCheckLT(i, sz, "out of range"); return ptr[i]; } +#endif protected: //! pointer to the real buffer, can point to buf if the buffer is small enough _Tp* ptr; //! size of the real buffer size_t sz; - //! pre-allocated buffer. At least 1 element to confirm C++ standard reqirements + //! pre-allocated buffer. At least 1 element to confirm C++ standard requirements _Tp buf[(fixed_size > 0) ? fixed_size : 1]; }; @@ -173,13 +194,6 @@ extern "C" typedef int (*ErrorCallback)( int status, const char* func_name, */ CV_EXPORTS ErrorCallback redirectError( ErrorCallback errCallback, void* userdata=0, void** prevUserdata=0); -/** @brief Returns a text string formatted using the printf-like expression. - -The function acts like sprintf but forms and returns an STL string. It can be used to form an error -message in the Exception constructor. -@param fmt printf-compatible formatting specifiers. - */ -CV_EXPORTS String format( const char* fmt, ... ); CV_EXPORTS String tempfile( const char* suffix = 0); CV_EXPORTS void glob(String pattern, std::vector& result, bool recursive = false); @@ -189,51 +203,53 @@ If threads == 0, OpenCV will disable threading optimizations and run all it's fu sequentially. Passing threads \< 0 will reset threads number to system default. This function must be called outside of parallel region. -OpenCV will try to run it's functions with specified threads number, but some behaviour differs from +OpenCV will try to run its functions with specified threads number, but some behaviour differs from framework: -- `TBB` – User-defined parallel constructions will run with the same threads number, if - another does not specified. If late on user creates own scheduler, OpenCV will be use it. -- `OpenMP` – No special defined behaviour. -- `Concurrency` – If threads == 1, OpenCV will disable threading optimizations and run it's +- `TBB` - User-defined parallel constructions will run with the same threads number, if + another is not specified. If later on user creates his own scheduler, OpenCV will use it. +- `OpenMP` - No special defined behaviour. +- `Concurrency` - If threads == 1, OpenCV will disable threading optimizations and run its functions sequentially. -- `GCD` – Supports only values \<= 0. -- `C=` – No special defined behaviour. +- `GCD` - Supports only values \<= 0. +- `C=` - No special defined behaviour. @param nthreads Number of threads used by OpenCV. @sa getNumThreads, getThreadNum */ -CV_EXPORTS void setNumThreads(int nthreads); +CV_EXPORTS_W void setNumThreads(int nthreads); /** @brief Returns the number of threads used by OpenCV for parallel regions. Always returns 1 if OpenCV is built without threading support. The exact meaning of return value depends on the threading framework used by OpenCV library: -- `TBB` – The number of threads, that OpenCV will try to use for parallel regions. If there is +- `TBB` - The number of threads, that OpenCV will try to use for parallel regions. If there is any tbb::thread_scheduler_init in user code conflicting with OpenCV, then function returns default number of threads used by TBB library. -- `OpenMP` – An upper bound on the number of threads that could be used to form a new team. -- `Concurrency` – The number of threads, that OpenCV will try to use for parallel regions. -- `GCD` – Unsupported; returns the GCD thread pool limit (512) for compatibility. -- `C=` – The number of threads, that OpenCV will try to use for parallel regions, if before +- `OpenMP` - An upper bound on the number of threads that could be used to form a new team. +- `Concurrency` - The number of threads, that OpenCV will try to use for parallel regions. +- `GCD` - Unsupported; returns the GCD thread pool limit (512) for compatibility. +- `C=` - The number of threads, that OpenCV will try to use for parallel regions, if before called setNumThreads with threads \> 0, otherwise returns the number of logical CPUs, available for the process. @sa setNumThreads, getThreadNum */ -CV_EXPORTS int getNumThreads(); +CV_EXPORTS_W int getNumThreads(); /** @brief Returns the index of the currently executed thread within the current parallel region. Always returns 0 if called outside of parallel region. -The exact meaning of return value depends on the threading framework used by OpenCV library: -- `TBB` – Unsupported with current 4.1 TBB release. May be will be supported in future. -- `OpenMP` – The thread number, within the current team, of the calling thread. -- `Concurrency` – An ID for the virtual processor that the current context is executing on (0 +@deprecated Current implementation doesn't corresponding to this documentation. + +The exact meaning of the return value depends on the threading framework used by OpenCV library: +- `TBB` - Unsupported with current 4.1 TBB release. Maybe will be supported in future. +- `OpenMP` - The thread number, within the current team, of the calling thread. +- `Concurrency` - An ID for the virtual processor that the current context is executing on (0 for master thread and unique number for others, but not necessary 1,2,3,...). -- `GCD` – System calling thread's ID. Never returns 0 inside parallel region. -- `C=` – The index of the current parallel task. +- `GCD` - System calling thread's ID. Never returns 0 inside parallel region. +- `C=` - The index of the current parallel task. @sa setNumThreads, getNumThreads */ -CV_EXPORTS int getThreadNum(); +CV_EXPORTS_W int getThreadNum(); /** @brief Returns full configuration time cmake output. @@ -243,11 +259,29 @@ architecture. */ CV_EXPORTS_W const String& getBuildInformation(); +/** @brief Returns library version string + +For example "3.4.1-dev". + +@sa getMajorVersion, getMinorVersion, getRevisionVersion +*/ +CV_EXPORTS_W String getVersionString(); + +/** @brief Returns major library version */ +CV_EXPORTS_W int getVersionMajor(); + +/** @brief Returns minor library version */ +CV_EXPORTS_W int getVersionMinor(); + +/** @brief Returns revision field of the library version */ +CV_EXPORTS_W int getVersionRevision(); + /** @brief Returns the number of ticks. The function returns the number of ticks after the certain event (for example, when the machine was turned on). It can be used to initialize RNG or to measure a function execution time by reading the -tick count before and after the function call. See also the tick frequency. +tick count before and after the function call. +@sa getTickFrequency, TickMeter */ CV_EXPORTS_W int64 getTickCount(); @@ -260,9 +294,139 @@ execution time in seconds: // do something ... t = ((double)getTickCount() - t)/getTickFrequency(); @endcode +@sa getTickCount, TickMeter */ CV_EXPORTS_W double getTickFrequency(); +/** @brief a Class to measure passing time. + +The class computes passing time by counting the number of ticks per second. That is, the following code computes the +execution time in seconds: +@code +TickMeter tm; +tm.start(); +// do something ... +tm.stop(); +std::cout << tm.getTimeSec(); +@endcode + +It is also possible to compute the average time over multiple runs: +@code +TickMeter tm; +for (int i = 0; i < 100; i++) +{ + tm.start(); + // do something ... + tm.stop(); +} +double average_time = tm.getTimeSec() / tm.getCounter(); +std::cout << "Average time in second per iteration is: " << average_time << std::endl; +@endcode +@sa getTickCount, getTickFrequency +*/ + +class CV_EXPORTS_W TickMeter +{ +public: + //! the default constructor + CV_WRAP TickMeter() + { + reset(); + } + + /** + starts counting ticks. + */ + CV_WRAP void start() + { + startTime = cv::getTickCount(); + } + + /** + stops counting ticks. + */ + CV_WRAP void stop() + { + int64 time = cv::getTickCount(); + if (startTime == 0) + return; + ++counter; + sumTime += (time - startTime); + startTime = 0; + } + + /** + returns counted ticks. + */ + CV_WRAP int64 getTimeTicks() const + { + return sumTime; + } + + /** + returns passed time in microseconds. + */ + CV_WRAP double getTimeMicro() const + { + return getTimeMilli()*1e3; + } + + /** + returns passed time in milliseconds. + */ + CV_WRAP double getTimeMilli() const + { + return getTimeSec()*1e3; + } + + /** + returns passed time in seconds. + */ + CV_WRAP double getTimeSec() const + { + return (double)getTimeTicks() / getTickFrequency(); + } + + /** + returns internal counter value. + */ + CV_WRAP int64 getCounter() const + { + return counter; + } + + /** + resets internal values. + */ + CV_WRAP void reset() + { + startTime = 0; + sumTime = 0; + counter = 0; + } + +private: + int64 counter; + int64 sumTime; + int64 startTime; +}; + +/** @brief output operator +@code +TickMeter tm; +tm.start(); +// do something ... +tm.stop(); +std::cout << tm; +@endcode +*/ + +static inline +std::ostream& operator << (std::ostream& out, const TickMeter& tm) +{ + return out << tm.getTimeSec() << "sec"; +} + /** @brief Returns the number of CPU ticks. The function returns the current number of CPU ticks on some architectures (such as x86, x64, @@ -277,37 +441,6 @@ execution time. */ CV_EXPORTS_W int64 getCPUTickCount(); -/** @brief Available CPU features. - -remember to keep this list identical to the one in cvdef.h -*/ -enum CpuFeatures { - CPU_MMX = 1, - CPU_SSE = 2, - CPU_SSE2 = 3, - CPU_SSE3 = 4, - CPU_SSSE3 = 5, - CPU_SSE4_1 = 6, - CPU_SSE4_2 = 7, - CPU_POPCNT = 8, - - CPU_AVX = 10, - CPU_AVX2 = 11, - CPU_FMA3 = 12, - - CPU_AVX_512F = 13, - CPU_AVX_512BW = 14, - CPU_AVX_512CD = 15, - CPU_AVX_512DQ = 16, - CPU_AVX_512ER = 17, - CPU_AVX_512IFMA512 = 18, - CPU_AVX_512PF = 19, - CPU_AVX_512VBMI = 20, - CPU_AVX_512VL = 21, - - CPU_NEON = 100 -}; - /** @brief Returns true if the specified feature is supported by the host hardware. The function returns true if the host hardware supports the specified feature. When user calls @@ -318,6 +451,24 @@ in OpenCV. */ CV_EXPORTS_W bool checkHardwareSupport(int feature); +/** @brief Returns feature name by ID + +Returns empty string if feature is not defined +*/ +CV_EXPORTS_W String getHardwareFeatureName(int feature); + +/** @brief Returns list of CPU features enabled during compilation. + +Returned value is a string containing space separated list of CPU features with following markers: + +- no markers - baseline features +- prefix `*` - features enabled in dispatcher +- suffix `?` - features enabled but not available in HW + +Example: `SSE SSE2 SSE3 *SSE4.1 *SSE4.2 *FP16 *AVX *AVX2 *AVX512-SKX?` +*/ +CV_EXPORTS std::string getCPUFeaturesLine(); + /** @brief Returns the number of logical CPUs available for the process. */ CV_EXPORTS_W int getNumberOfCPUs(); @@ -326,19 +477,20 @@ CV_EXPORTS_W int getNumberOfCPUs(); /** @brief Aligns a pointer to the specified number of bytes. The function returns the aligned pointer of the same type as the input pointer: -\f[\texttt{(\_Tp*)(((size\_t)ptr + n-1) \& -n)}\f] +\f[\texttt{(_Tp*)(((size_t)ptr + n-1) & -n)}\f] @param ptr Aligned pointer. @param n Alignment size that must be a power of two. */ template static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp)) { + CV_DbgAssert((n & (n - 1)) == 0); // n is a power of 2 return (_Tp*)(((size_t)ptr + n-1) & -n); } /** @brief Aligns a buffer size to the specified number of bytes. -The function returns the minimum number that is greater or equal to sz and is divisible by n : -\f[\texttt{(sz + n-1) \& -n}\f] +The function returns the minimum number that is greater than or equal to sz and is divisible by n : +\f[\texttt{(sz + n-1) & -n}\f] @param sz Buffer size to align. @param n Alignment size that must be a power of two. */ @@ -348,9 +500,43 @@ static inline size_t alignSize(size_t sz, int n) return (sz + n-1) & -n; } +/** @brief Integer division with result round up. + +Use this function instead of `ceil((float)a / b)` expressions. + +@sa alignSize +*/ +static inline int divUp(int a, unsigned int b) +{ + CV_DbgAssert(a >= 0); + return (a + b - 1) / b; +} +/** @overload */ +static inline size_t divUp(size_t a, unsigned int b) +{ + return (a + b - 1) / b; +} + +/** @brief Round first value up to the nearest multiple of second value. + +Use this function instead of `ceil((float)a / b) * b` expressions. + +@sa divUp +*/ +static inline int roundUp(int a, unsigned int b) +{ + CV_DbgAssert(a >= 0); + return a + b - 1 - (a + b -1) % b; +} +/** @overload */ +static inline size_t roundUp(size_t a, unsigned int b) +{ + return a + b - 1 - (a + b - 1) % b; +} + /** @brief Enables or disables the optimized code. -The function can be used to dynamically turn on and off optimized code (code that uses SSE2, AVX, +The function can be used to dynamically turn on and off optimized dispatched code (code that uses SSE4.2, AVX/AVX2, and other instructions on the platforms that support it). It sets a global flag that is further checked by OpenCV functions. Since the flag is not checked in the inner OpenCV loops, it is only safe to call the function on the very top level in your application where you can be sure that no @@ -369,7 +555,7 @@ The function returns true if the optimized code is enabled. Otherwise, it return */ CV_EXPORTS_W bool useOptimized(); -static inline size_t getElemSize(int type) { return CV_ELEM_SIZE(type); } +static inline size_t getElemSize(int type) { return (size_t)CV_ELEM_SIZE(type); } /////////////////////////////// Parallel Primitives ////////////////////////////////// @@ -386,15 +572,37 @@ public: */ CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.); +#ifdef CV_CXX11 +class ParallelLoopBodyLambdaWrapper : public ParallelLoopBody +{ +private: + std::function m_functor; +public: + ParallelLoopBodyLambdaWrapper(std::function functor) : + m_functor(functor) + { } + + virtual void operator() (const cv::Range& range) const CV_OVERRIDE + { + m_functor(range); + } +}; + +inline void parallel_for_(const Range& range, std::function functor, double nstripes=-1.) +{ + parallel_for_(range, ParallelLoopBodyLambdaWrapper(functor), nstripes); +} +#endif + /////////////////////////////// forEach method of cv::Mat //////////////////////////// template inline void Mat::forEach_impl(const Functor& operation) { if (false) { - operation(*reinterpret_cast<_Tp*>(0), reinterpret_cast(NULL)); - // If your compiler fail in this line. + operation(*reinterpret_cast<_Tp*>(0), reinterpret_cast(0)); + // If your compiler fails in this line. // Please check that your functor signature is - // (_Tp&, const int*) <- multidimential - // or (_Tp&, void*) <- in case of you don't need current idx. + // (_Tp&, const int*) <- multi-dimensional + // or (_Tp&, void*) <- in case you don't need current idx. } CV_Assert(this->total() / this->size[this->dims - 1] <= INT_MAX); @@ -404,11 +612,12 @@ void Mat::forEach_impl(const Functor& operation) { { public: PixelOperationWrapper(Mat_<_Tp>* const frame, const Functor& _operation) - : mat(frame), op(_operation) {}; - virtual ~PixelOperationWrapper(){}; + : mat(frame), op(_operation) {} + virtual ~PixelOperationWrapper(){} // ! Overloaded virtual operator // convert range call to row call. - virtual void operator()(const Range &range) const { + virtual void operator()(const Range &range) const CV_OVERRIDE + { const int DIMS = mat->dims; const int COLS = mat->size[DIMS - 1]; if (DIMS <= 2) { @@ -416,7 +625,7 @@ void Mat::forEach_impl(const Functor& operation) { this->rowCall2(row, COLS); } } else { - std::vector idx(COLS); /// idx is modified in this->rowCall + std::vector idx(DIMS); /// idx is modified in this->rowCall idx[DIMS - 2] = range.start - 1; for (int line_num = range.start; line_num < range.end; ++line_num) { @@ -434,7 +643,7 @@ void Mat::forEach_impl(const Functor& operation) { this->rowCall(&idx[0], COLS, DIMS); } } - }; + } private: Mat_<_Tp>* const mat; const Functor op; @@ -471,12 +680,12 @@ void Mat::forEach_impl(const Functor& operation) { op(*pixel++, static_cast(idx)); idx[1]++; } - }; + } PixelOperationWrapper& operator=(const PixelOperationWrapper &) { CV_Assert(false); // We can not remove this implementation because Visual Studio warning C4822. return *this; - }; + } }; parallel_for_(cv::Range(0, LINES), PixelOperationWrapper(reinterpret_cast*>(this), operation)); @@ -513,30 +722,60 @@ private: AutoLock& operator = (const AutoLock&); }; +// TLS interface class CV_EXPORTS TLSDataContainer { -private: - int key_; protected: TLSDataContainer(); virtual ~TLSDataContainer(); -public: - virtual void* createDataInstance() const = 0; - virtual void deleteDataInstance(void* data) const = 0; + void gatherData(std::vector &data) const; +#if OPENCV_ABI_COMPATIBILITY > 300 void* getData() const; + void release(); + +private: +#else + void release(); + +public: + void* getData() const; +#endif + virtual void* createDataInstance() const = 0; + virtual void deleteDataInstance(void* pData) const = 0; + + int key_; + +public: + void cleanup(); //! Release created TLS data container objects. It is similar to release() call, but it keeps TLS container valid. }; +// Main TLS data class template class TLSData : protected TLSDataContainer { public: - inline TLSData() {} - inline ~TLSData() {} - inline T* get() const { return (T*)getData(); } + inline TLSData() {} + inline ~TLSData() { release(); } // Release key and delete associated data + inline T* get() const { return (T*)getData(); } // Get data associated with key + inline T& getRef() const { T* ptr = (T*)getData(); CV_Assert(ptr); return *ptr; } // Get data associated with key + + // Get data from all threads + inline void gather(std::vector &data) const + { + std::vector &dataVoid = reinterpret_cast&>(data); + gatherData(dataVoid); + } + + inline void cleanup() { TLSDataContainer::cleanup(); } + private: - virtual void* createDataInstance() const { return new T; } - virtual void deleteDataInstance(void* data) const { delete (T*)data; } + virtual void* createDataInstance() const CV_OVERRIDE {return new T;} // Wrapper to allocate data by template + virtual void deleteDataInstance(void* pData) const CV_OVERRIDE {delete (T*)pData;} // Wrapper to release data by template + + // Disable TLS copy operations + TLSData(TLSData &) {} + TLSData& operator =(const TLSData &) {return *this;} }; /** @brief Designed for command line parsing @@ -572,7 +811,7 @@ The sample below demonstrates how to use CommandLineParser: ### Keys syntax -The keys parameter is a string containing several blocks, each one is enclosed in curley braces and +The keys parameter is a string containing several blocks, each one is enclosed in curly braces and describes one argument. Each argument contains three parts separated by the `|` symbol: -# argument names is a space-separated list of option synonyms (to mark argument as positional, prefix it with the `@` symbol) @@ -585,7 +824,7 @@ For example: const String keys = "{help h usage ? | | print this message }" "{@image1 | | image1 for compare }" - "{@image2 | | image2 for compare }" + "{@image2 || image2 for compare }" "{@repeat |1 | number }" "{path |. | path to file }" "{fps | -1.0 | fps for output video }" @@ -595,6 +834,13 @@ For example: } @endcode +Note that there are no default values for `help` and `timestamp` so we can check their presence using the `has()` method. +Arguments with default values are considered to be always present. Use the `get()` method in these cases to check their +actual value instead. + +String keys like `get("@image1")` return the empty string `""` by default - even with an empty default value. +Use the special `` default value to enforce that the returned string must not be empty. (like in `get("@image2")`) + ### Usage For the described keys: @@ -606,7 +852,7 @@ For the described keys: # Bad call $ ./app -fps=aaa ERRORS: - Exception: can not convert: [aaa] to [double] + Parameter 'fps': can not convert: [aaa] to [double] @endcode */ class CV_EXPORTS CommandLineParser @@ -636,7 +882,7 @@ public: This method returns the path to the executable from the command line (`argv[0]`). - For example, if the application has been started with such command: + For example, if the application has been started with such a command: @code{.sh} $ ./bin/my-executable @endcode @@ -723,7 +969,7 @@ public: /** @brief Check for parsing errors - Returns true if error occured while accessing the parameters (bad conversion, missing arguments, + Returns false if error occurred while accessing the parameters (bad conversion, missing arguments, etc.). Call @ref printErrors to print error messages list. */ bool check() const; @@ -742,7 +988,7 @@ public: */ void printMessage() const; - /** @brief Print list of errors occured + /** @brief Print list of errors occurred @sa check */ @@ -813,10 +1059,10 @@ AutoBuffer<_Tp, fixed_size>::allocate(size_t _size) return; } deallocate(); + sz = _size; if(_size > fixed_size) { ptr = new _Tp[_size]; - sz = _size; } } @@ -859,15 +1105,6 @@ template inline size_t AutoBuffer<_Tp, fixed_size>::size() const { return sz; } -template inline -AutoBuffer<_Tp, fixed_size>::operator _Tp* () -{ return ptr; } - -template inline -AutoBuffer<_Tp, fixed_size>::operator const _Tp* () const -{ return ptr; } - -#ifndef OPENCV_NOSTL template<> inline std::string CommandLineParser::get(int index, bool space_delete) const { return get(index, space_delete); @@ -876,14 +1113,246 @@ template<> inline std::string CommandLineParser::get(const String& { return get(name, space_delete); } -#endif // OPENCV_NOSTL //! @endcond + +// Basic Node class for tree building +template +class CV_EXPORTS Node +{ +public: + Node() + { + m_pParent = 0; + } + Node(OBJECT& payload) : m_payload(payload) + { + m_pParent = 0; + } + ~Node() + { + removeChilds(); + if (m_pParent) + { + int idx = m_pParent->findChild(this); + if (idx >= 0) + m_pParent->m_childs.erase(m_pParent->m_childs.begin() + idx); + } + } + + Node* findChild(OBJECT& payload) const + { + for(size_t i = 0; i < this->m_childs.size(); i++) + { + if(this->m_childs[i]->m_payload == payload) + return this->m_childs[i]; + } + return NULL; + } + + int findChild(Node *pNode) const + { + for (size_t i = 0; i < this->m_childs.size(); i++) + { + if(this->m_childs[i] == pNode) + return (int)i; + } + return -1; + } + + void addChild(Node *pNode) + { + if(!pNode) + return; + + CV_Assert(pNode->m_pParent == 0); + pNode->m_pParent = this; + this->m_childs.push_back(pNode); + } + + void removeChilds() + { + for(size_t i = 0; i < m_childs.size(); i++) + { + m_childs[i]->m_pParent = 0; // avoid excessive parent vector trimming + delete m_childs[i]; + } + m_childs.clear(); + } + + int getDepth() + { + int count = 0; + Node *pParent = m_pParent; + while(pParent) count++, pParent = pParent->m_pParent; + return count; + } + +public: + OBJECT m_payload; + Node* m_pParent; + std::vector*> m_childs; +}; + +// Instrumentation external interface +namespace instr +{ + +#if !defined OPENCV_ABI_CHECK + +enum TYPE +{ + TYPE_GENERAL = 0, // OpenCV API function, e.g. exported function + TYPE_MARKER, // Information marker + TYPE_WRAPPER, // Wrapper function for implementation + TYPE_FUN, // Simple function call +}; + +enum IMPL +{ + IMPL_PLAIN = 0, + IMPL_IPP, + IMPL_OPENCL, +}; + +struct NodeDataTls +{ + NodeDataTls() + { + m_ticksTotal = 0; + } + uint64 m_ticksTotal; +}; + +class CV_EXPORTS NodeData +{ +public: + NodeData(const char* funName = 0, const char* fileName = NULL, int lineNum = 0, void* retAddress = NULL, bool alwaysExpand = false, cv::instr::TYPE instrType = TYPE_GENERAL, cv::instr::IMPL implType = IMPL_PLAIN); + NodeData(NodeData &ref); + ~NodeData(); + NodeData& operator=(const NodeData&); + + cv::String m_funName; + cv::instr::TYPE m_instrType; + cv::instr::IMPL m_implType; + const char* m_fileName; + int m_lineNum; + void* m_retAddress; + bool m_alwaysExpand; + bool m_funError; + + volatile int m_counter; + volatile uint64 m_ticksTotal; + TLSData m_tls; + int m_threads; + + // No synchronization + double getTotalMs() const { return ((double)m_ticksTotal / cv::getTickFrequency()) * 1000; } + double getMeanMs() const { return (((double)m_ticksTotal/m_counter) / cv::getTickFrequency()) * 1000; } +}; +bool operator==(const NodeData& lhs, const NodeData& rhs); + +typedef Node InstrNode; + +CV_EXPORTS InstrNode* getTrace(); + +#endif // !defined OPENCV_ABI_CHECK + + +CV_EXPORTS bool useInstrumentation(); +CV_EXPORTS void setUseInstrumentation(bool flag); +CV_EXPORTS void resetTrace(); + +enum FLAGS +{ + FLAGS_NONE = 0, + FLAGS_MAPPING = 0x01, + FLAGS_EXPAND_SAME_NAMES = 0x02, +}; + +CV_EXPORTS void setFlags(FLAGS modeFlags); +static inline void setFlags(int modeFlags) { setFlags((FLAGS)modeFlags); } +CV_EXPORTS FLAGS getFlags(); + +} // namespace instr + + +namespace samples { + +//! @addtogroup core_utils_samples +// This section describes utility functions for OpenCV samples. +// +// @note Implementation of these utilities is not thread-safe. +// +//! @{ + +/** @brief Try to find requested data file + +Search directories: + +1. Directories passed via `addSamplesDataSearchPath()` +2. OPENCV_SAMPLES_DATA_PATH_HINT environment variable +3. OPENCV_SAMPLES_DATA_PATH environment variable + If parameter value is not empty and nothing is found then stop searching. +4. Detects build/install path based on: + a. current working directory (CWD) + b. and/or binary module location (opencv_core/opencv_world, doesn't work with static linkage) +5. Scan `/{,data,samples/data}` directories if build directory is detected or the current directory is in source tree. +6. Scan `/share/OpenCV` directory if install directory is detected. + +@see cv::utils::findDataFile + +@param relative_path Relative path to data file +@param required Specify "file not found" handling. + If true, function prints information message and raises cv::Exception. + If false, function returns empty result +@param silentMode Disables messages +@return Returns path (absolute or relative to the current directory) or empty string if file is not found +*/ +CV_EXPORTS_W cv::String findFile(const cv::String& relative_path, bool required = true, bool silentMode = false); + +CV_EXPORTS_W cv::String findFileOrKeep(const cv::String& relative_path, bool silentMode = false); + +inline cv::String findFileOrKeep(const cv::String& relative_path, bool silentMode) +{ + cv::String res = findFile(relative_path, false, silentMode); + if (res.empty()) + return relative_path; + return res; +} + +/** @brief Override search data path by adding new search location + +Use this only to override default behavior +Passed paths are used in LIFO order. + +@param path Path to used samples data +*/ +CV_EXPORTS_W void addSamplesDataSearchPath(const cv::String& path); + +/** @brief Append samples search data sub directory + +General usage is to add OpenCV modules name (`/modules//samples/data` -> `/samples/data` + `modules//samples/data`). +Passed subdirectories are used in LIFO order. + +@param subdir samples data sub directory +*/ +CV_EXPORTS_W void addSamplesDataSearchSubDirectory(const cv::String& subdir); + +//! @} +} // namespace samples + +namespace utils { + +CV_EXPORTS int getThreadID(); + +} // namespace + } //namespace cv #ifndef DISABLE_OPENCV_24_COMPATIBILITY #include "opencv2/core/core_c.h" #endif -#endif //__OPENCV_CORE_UTILITY_H__ +#endif //OPENCV_CORE_UTILITY_H diff --git a/include/opencv2/core/utils/filesystem.hpp b/include/opencv2/core/utils/filesystem.hpp new file mode 100644 index 0000000..00b0dd1 --- /dev/null +++ b/include/opencv2/core/utils/filesystem.hpp @@ -0,0 +1,78 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_UTILS_FILESYSTEM_HPP +#define OPENCV_UTILS_FILESYSTEM_HPP + +namespace cv { namespace utils { namespace fs { + + +CV_EXPORTS bool exists(const cv::String& path); +CV_EXPORTS bool isDirectory(const cv::String& path); + +CV_EXPORTS void remove_all(const cv::String& path); + + +CV_EXPORTS cv::String getcwd(); + +/** @brief Converts path p to a canonical absolute path + * Symlinks are processed if there is support for them on running platform. + * + * @param path input path. Target file/directory should exist. + */ +CV_EXPORTS cv::String canonical(const cv::String& path); + +/** Join path components */ +CV_EXPORTS cv::String join(const cv::String& base, const cv::String& path); + +/** + * Generate a list of all files that match the globbing pattern. + * + * Result entries are prefixed by base directory path. + * + * @param directory base directory + * @param pattern filter pattern (based on '*'/'?' symbols). Use empty string to disable filtering and return all results + * @param[out] result result of globing. + * @param recursive scan nested directories too + * @param includeDirectories include directories into results list + */ +CV_EXPORTS void glob(const cv::String& directory, const cv::String& pattern, + CV_OUT std::vector& result, + bool recursive = false, bool includeDirectories = false); + +/** + * Generate a list of all files that match the globbing pattern. + * + * @param directory base directory + * @param pattern filter pattern (based on '*'/'?' symbols). Use empty string to disable filtering and return all results + * @param[out] result globbing result with relative paths from base directory + * @param recursive scan nested directories too + * @param includeDirectories include directories into results list + */ +CV_EXPORTS void glob_relative(const cv::String& directory, const cv::String& pattern, + CV_OUT std::vector& result, + bool recursive = false, bool includeDirectories = false); + + +CV_EXPORTS bool createDirectory(const cv::String& path); +CV_EXPORTS bool createDirectories(const cv::String& path); + +#ifdef __OPENCV_BUILD +// TODO +//CV_EXPORTS cv::String getTempDirectory(); + +/** + * @brief Returns directory to store OpenCV cache files + * Create sub-directory in common OpenCV cache directory if it doesn't exist. + * @param sub_directory_name name of sub-directory. NULL or "" value asks to return root cache directory. + * @param configuration_name optional name of configuration parameter name which overrides default behavior. + * @return Path to cache directory. Returns empty string if cache directories support is not available. Returns "disabled" if cache disabled by user. + */ +CV_EXPORTS cv::String getCacheDirectory(const char* sub_directory_name, const char* configuration_name = NULL); + +#endif + +}}} // namespace + +#endif // OPENCV_UTILS_FILESYSTEM_HPP diff --git a/include/opencv2/core/utils/logger.defines.hpp b/include/opencv2/core/utils/logger.defines.hpp new file mode 100644 index 0000000..b2dfc41 --- /dev/null +++ b/include/opencv2/core/utils/logger.defines.hpp @@ -0,0 +1,22 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_LOGGER_DEFINES_HPP +#define OPENCV_LOGGER_DEFINES_HPP + +//! @addtogroup core_logging +//! @{ + +// Supported logging levels and their semantic +#define CV_LOG_LEVEL_SILENT 0 //!< for using in setLogLevel() call +#define CV_LOG_LEVEL_FATAL 1 //!< Fatal (critical) error (unrecoverable internal error) +#define CV_LOG_LEVEL_ERROR 2 //!< Error message +#define CV_LOG_LEVEL_WARN 3 //!< Warning message +#define CV_LOG_LEVEL_INFO 4 //!< Info message +#define CV_LOG_LEVEL_DEBUG 5 //!< Debug message. Disabled in the "Release" build. +#define CV_LOG_LEVEL_VERBOSE 6 //!< Verbose (trace) messages. Requires verbosity level. Disabled in the "Release" build. + +//! @} + +#endif // OPENCV_LOGGER_DEFINES_HPP diff --git a/include/opencv2/core/utils/logger.hpp b/include/opencv2/core/utils/logger.hpp new file mode 100644 index 0000000..47094f9 --- /dev/null +++ b/include/opencv2/core/utils/logger.hpp @@ -0,0 +1,87 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_LOGGER_HPP +#define OPENCV_LOGGER_HPP + +#include +#include +#include // INT_MAX + +#include "logger.defines.hpp" + +//! @addtogroup core_logging +// This section describes OpenCV logging utilities. +// +//! @{ + +namespace cv { +namespace utils { +namespace logging { + +//! Supported logging levels and their semantic +enum LogLevel { + LOG_LEVEL_SILENT = 0, //!< for using in setLogVevel() call + LOG_LEVEL_FATAL = 1, //!< Fatal (critical) error (unrecoverable internal error) + LOG_LEVEL_ERROR = 2, //!< Error message + LOG_LEVEL_WARNING = 3, //!< Warning message + LOG_LEVEL_INFO = 4, //!< Info message + LOG_LEVEL_DEBUG = 5, //!< Debug message. Disabled in the "Release" build. + LOG_LEVEL_VERBOSE = 6, //!< Verbose (trace) messages. Requires verbosity level. Disabled in the "Release" build. +#ifndef CV_DOXYGEN + ENUM_LOG_LEVEL_FORCE_INT = INT_MAX +#endif +}; + +/** Set global logging level +@return previous logging level +*/ +CV_EXPORTS LogLevel setLogLevel(LogLevel logLevel); +/** Get global logging level */ +CV_EXPORTS LogLevel getLogLevel(); + +namespace internal { +/** Write log message */ +CV_EXPORTS void writeLogMessage(LogLevel logLevel, const char* message); +} // namespace + +/** + * \def CV_LOG_STRIP_LEVEL + * + * Define CV_LOG_STRIP_LEVEL=CV_LOG_LEVEL_[DEBUG|INFO|WARN|ERROR|FATAL|DISABLED] to compile out anything at that and before that logging level + */ +#ifndef CV_LOG_STRIP_LEVEL +# if defined NDEBUG +# define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG +# else +# define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE +# endif +#endif + + +#define CV_LOG_FATAL(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_FATAL) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_FATAL, ss.str().c_str()); break; } +#define CV_LOG_ERROR(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_ERROR) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_ERROR, ss.str().c_str()); break; } +#define CV_LOG_WARNING(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_WARNING) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_WARNING, ss.str().c_str()); break; } +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO +#define CV_LOG_INFO(tag, ...) +#else +#define CV_LOG_INFO(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_INFO) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_INFO, ss.str().c_str()); break; } +#endif +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG +#define CV_LOG_DEBUG(tag, ...) +#else +#define CV_LOG_DEBUG(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_DEBUG) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_DEBUG, ss.str().c_str()); break; } +#endif +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE +#define CV_LOG_VERBOSE(tag, v, ...) +#else +#define CV_LOG_VERBOSE(tag, v, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_VERBOSE) break; std::stringstream ss; ss << "[VERB" << v << ":" << cv::utils::getThreadID() << "] " << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_VERBOSE, ss.str().c_str()); break; } +#endif + + +}}} // namespace + +//! @} + +#endif // OPENCV_LOGGER_HPP diff --git a/include/opencv2/core/utils/trace.hpp b/include/opencv2/core/utils/trace.hpp new file mode 100644 index 0000000..858e973 --- /dev/null +++ b/include/opencv2/core/utils/trace.hpp @@ -0,0 +1,254 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_TRACE_HPP +#define OPENCV_TRACE_HPP + +#include + +//! @addtogroup core_logging +// This section describes OpenCV tracing utilities. +// +//! @{ + +namespace cv { +namespace utils { +namespace trace { + +//! Macro to trace function +#define CV_TRACE_FUNCTION() + +#define CV_TRACE_FUNCTION_SKIP_NESTED() + +//! Trace code scope. +//! @note Dynamic names are not supported in this macro (on stack or heap). Use string literals here only, like "initialize". +#define CV_TRACE_REGION(name_as_static_string_literal) +//! mark completed of the current opened region and create new one +//! @note Dynamic names are not supported in this macro (on stack or heap). Use string literals here only, like "step1". +#define CV_TRACE_REGION_NEXT(name_as_static_string_literal) + +//! Macro to trace argument value +#define CV_TRACE_ARG(arg_id) + +//! Macro to trace argument value (expanded version) +#define CV_TRACE_ARG_VALUE(arg_id, arg_name, value) + +//! @cond IGNORED +#define CV_TRACE_NS cv::utils::trace + +#if !defined(OPENCV_DISABLE_TRACE) && defined(__EMSCRIPTEN__) +#define OPENCV_DISABLE_TRACE 1 +#endif + +namespace details { + +#ifndef __OPENCV_TRACE +# if defined __OPENCV_BUILD && !defined __OPENCV_TESTS && !defined __OPENCV_APPS +# define __OPENCV_TRACE 1 +# else +# define __OPENCV_TRACE 0 +# endif +#endif + +#ifndef CV_TRACE_FILENAME +# define CV_TRACE_FILENAME __FILE__ +#endif + +#ifndef CV__TRACE_FUNCTION +# if defined _MSC_VER +# define CV__TRACE_FUNCTION __FUNCSIG__ +# elif defined __GNUC__ +# define CV__TRACE_FUNCTION __PRETTY_FUNCTION__ +# else +# define CV__TRACE_FUNCTION "" +# endif +#endif + +//! Thread-local instance (usually allocated on stack) +class CV_EXPORTS Region +{ +public: + struct LocationExtraData; + struct LocationStaticStorage + { + LocationExtraData** ppExtra; //< implementation specific data + const char* name; //< region name (function name or other custom name) + const char* filename; //< source code filename + int line; //< source code line + int flags; //< flags (implementation code path: Plain, IPP, OpenCL) + }; + + Region(const LocationStaticStorage& location); + inline ~Region() + { + if (implFlags != 0) + destroy(); + CV_DbgAssert(implFlags == 0); + CV_DbgAssert(pImpl == NULL); + } + + class Impl; + Impl* pImpl; // NULL if current region is not active + int implFlags; // see RegionFlag, 0 if region is ignored + + bool isActive() const { return pImpl != NULL; } + + void destroy(); +private: + Region(const Region&); // disabled + Region& operator= (const Region&); // disabled +}; + +//! Specify region flags +enum RegionLocationFlag { + REGION_FLAG_FUNCTION = (1 << 0), //< region is function (=1) / nested named region (=0) + REGION_FLAG_APP_CODE = (1 << 1), //< region is Application code (=1) / OpenCV library code (=0) + REGION_FLAG_SKIP_NESTED = (1 << 2), //< avoid processing of nested regions + + REGION_FLAG_IMPL_IPP = (1 << 16), //< region is part of IPP code path + REGION_FLAG_IMPL_OPENCL = (2 << 16), //< region is part of OpenCL code path + REGION_FLAG_IMPL_OPENVX = (3 << 16), //< region is part of OpenVX code path + + REGION_FLAG_IMPL_MASK = (15 << 16), + + REGION_FLAG_REGION_FORCE = (1 << 30), + REGION_FLAG_REGION_NEXT = (1 << 31), //< close previous region (see #CV_TRACE_REGION_NEXT macro) + + ENUM_REGION_FLAG_FORCE_INT = INT_MAX +}; + +struct CV_EXPORTS TraceArg { +public: + struct ExtraData; + ExtraData** ppExtra; + const char* name; + int flags; +}; +/** @brief Add meta information to current region (function) + * See CV_TRACE_ARG macro + * @param arg argument information structure (global static cache) + * @param value argument value (can by dynamic string literal in case of string, static allocation is not required) + */ +CV_EXPORTS void traceArg(const TraceArg& arg, const char* value); +//! @overload +CV_EXPORTS void traceArg(const TraceArg& arg, int value); +//! @overload +CV_EXPORTS void traceArg(const TraceArg& arg, int64 value); +//! @overload +CV_EXPORTS void traceArg(const TraceArg& arg, double value); + +#define CV__TRACE_LOCATION_VARNAME(loc_id) CVAUX_CONCAT(CVAUX_CONCAT(__cv_trace_location_, loc_id), __LINE__) +#define CV__TRACE_LOCATION_EXTRA_VARNAME(loc_id) CVAUX_CONCAT(CVAUX_CONCAT(__cv_trace_location_extra_, loc_id) , __LINE__) + +#define CV__TRACE_DEFINE_LOCATION_(loc_id, name, flags) \ + static CV_TRACE_NS::details::Region::LocationExtraData* CV__TRACE_LOCATION_EXTRA_VARNAME(loc_id) = 0; \ + static const CV_TRACE_NS::details::Region::LocationStaticStorage \ + CV__TRACE_LOCATION_VARNAME(loc_id) = { &(CV__TRACE_LOCATION_EXTRA_VARNAME(loc_id)), name, CV_TRACE_FILENAME, __LINE__, flags}; + +#define CV__TRACE_DEFINE_LOCATION_FN(name, flags) CV__TRACE_DEFINE_LOCATION_(fn, name, ((flags) | CV_TRACE_NS::details::REGION_FLAG_FUNCTION)) + + +#define CV__TRACE_OPENCV_FUNCTION() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, 0); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_OPENCV_FUNCTION_NAME(name) \ + CV__TRACE_DEFINE_LOCATION_FN(name, 0); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_APP_FUNCTION() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, CV_TRACE_NS::details::REGION_FLAG_APP_CODE); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_APP_FUNCTION_NAME(name) \ + CV__TRACE_DEFINE_LOCATION_FN(name, CV_TRACE_NS::details::REGION_FLAG_APP_CODE); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + + +#define CV__TRACE_OPENCV_FUNCTION_SKIP_NESTED() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, CV_TRACE_NS::details::REGION_FLAG_SKIP_NESTED); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_OPENCV_FUNCTION_NAME_SKIP_NESTED(name) \ + CV__TRACE_DEFINE_LOCATION_FN(name, CV_TRACE_NS::details::REGION_FLAG_SKIP_NESTED); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_APP_FUNCTION_SKIP_NESTED() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, CV_TRACE_NS::details::REGION_FLAG_SKIP_NESTED | CV_TRACE_NS::details::REGION_FLAG_APP_CODE); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + + +#define CV__TRACE_REGION_(name_as_static_string_literal, flags) \ + CV__TRACE_DEFINE_LOCATION_(region, name_as_static_string_literal, flags); \ + CV_TRACE_NS::details::Region CVAUX_CONCAT(__region_, __LINE__)(CV__TRACE_LOCATION_VARNAME(region)); + +#define CV__TRACE_REGION(name_as_static_string_literal) CV__TRACE_REGION_(name_as_static_string_literal, 0) +#define CV__TRACE_REGION_NEXT(name_as_static_string_literal) CV__TRACE_REGION_(name_as_static_string_literal, CV_TRACE_NS::details::REGION_FLAG_REGION_NEXT) + +#define CV__TRACE_ARG_VARNAME(arg_id) CVAUX_CONCAT(__cv_trace_arg_ ## arg_id, __LINE__) +#define CV__TRACE_ARG_EXTRA_VARNAME(arg_id) CVAUX_CONCAT(__cv_trace_arg_extra_ ## arg_id, __LINE__) + +#define CV__TRACE_DEFINE_ARG_(arg_id, name, flags) \ + static CV_TRACE_NS::details::TraceArg::ExtraData* CV__TRACE_ARG_EXTRA_VARNAME(arg_id) = 0; \ + static const CV_TRACE_NS::details::TraceArg \ + CV__TRACE_ARG_VARNAME(arg_id) = { &(CV__TRACE_ARG_EXTRA_VARNAME(arg_id)), name, flags }; + +#define CV__TRACE_ARG_VALUE(arg_id, arg_name, value) \ + CV__TRACE_DEFINE_ARG_(arg_id, arg_name, 0); \ + CV_TRACE_NS::details::traceArg((CV__TRACE_ARG_VARNAME(arg_id)), value); + +#define CV__TRACE_ARG(arg_id) CV_TRACE_ARG_VALUE(arg_id, #arg_id, (arg_id)) + +} // namespace + +#ifndef OPENCV_DISABLE_TRACE +#undef CV_TRACE_FUNCTION +#undef CV_TRACE_FUNCTION_SKIP_NESTED +#if __OPENCV_TRACE +#define CV_TRACE_FUNCTION CV__TRACE_OPENCV_FUNCTION +#define CV_TRACE_FUNCTION_SKIP_NESTED CV__TRACE_OPENCV_FUNCTION_SKIP_NESTED +#else +#define CV_TRACE_FUNCTION CV__TRACE_APP_FUNCTION +#define CV_TRACE_FUNCTION_SKIP_NESTED CV__TRACE_APP_FUNCTION_SKIP_NESTED +#endif + +#undef CV_TRACE_REGION +#define CV_TRACE_REGION CV__TRACE_REGION + +#undef CV_TRACE_REGION_NEXT +#define CV_TRACE_REGION_NEXT CV__TRACE_REGION_NEXT + +#undef CV_TRACE_ARG_VALUE +#define CV_TRACE_ARG_VALUE(arg_id, arg_name, value) \ + if (__region_fn.isActive()) \ + { \ + CV__TRACE_ARG_VALUE(arg_id, arg_name, value); \ + } + +#undef CV_TRACE_ARG +#define CV_TRACE_ARG CV__TRACE_ARG + +#endif // OPENCV_DISABLE_TRACE + +#ifdef OPENCV_TRACE_VERBOSE +#define CV_TRACE_FUNCTION_VERBOSE CV_TRACE_FUNCTION +#define CV_TRACE_REGION_VERBOSE CV_TRACE_REGION +#define CV_TRACE_REGION_NEXT_VERBOSE CV_TRACE_REGION_NEXT +#define CV_TRACE_ARG_VALUE_VERBOSE CV_TRACE_ARG_VALUE +#define CV_TRACE_ARG_VERBOSE CV_TRACE_ARG +#else +#define CV_TRACE_FUNCTION_VERBOSE(...) +#define CV_TRACE_REGION_VERBOSE(...) +#define CV_TRACE_REGION_NEXT_VERBOSE(...) +#define CV_TRACE_ARG_VALUE_VERBOSE(...) +#define CV_TRACE_ARG_VERBOSE(...) +#endif + +//! @endcond + +}}} // namespace + +//! @} + +#endif // OPENCV_TRACE_HPP diff --git a/include/opencv2/core/va_intel.hpp b/include/opencv2/core/va_intel.hpp new file mode 100644 index 0000000..f665470 --- /dev/null +++ b/include/opencv2/core/va_intel.hpp @@ -0,0 +1,78 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2015, Itseez, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. + +#ifndef OPENCV_CORE_VA_INTEL_HPP +#define OPENCV_CORE_VA_INTEL_HPP + +#ifndef __cplusplus +# error va_intel.hpp header must be compiled as C++ +#endif + +#include "opencv2/core.hpp" +#include "ocl.hpp" + +#if defined(HAVE_VA) +# include "va/va.h" +#else // HAVE_VA +# if !defined(_VA_H_) + typedef void* VADisplay; + typedef unsigned int VASurfaceID; +# endif // !_VA_H_ +#endif // HAVE_VA + +namespace cv { namespace va_intel { + +/** @addtogroup core_va_intel +This section describes Intel VA-API/OpenCL (CL-VA) interoperability. + +To enable CL-VA interoperability support, configure OpenCV using CMake with WITH_VA_INTEL=ON . Currently VA-API is +supported on Linux only. You should also install Intel Media Server Studio (MSS) to use this feature. You may +have to specify the path(s) to MSS components for cmake in environment variables: + +- VA_INTEL_IOCL_ROOT for Intel OpenCL (default is "/opt/intel/opencl"). + +To use CL-VA interoperability you should first create VADisplay (libva), and then call initializeContextFromVA() +function to create OpenCL context and set up interoperability. +*/ +//! @{ + +/////////////////// CL-VA Interoperability Functions /////////////////// + +namespace ocl { +using namespace cv::ocl; + +// TODO static functions in the Context class +/** @brief Creates OpenCL context from VA. +@param display - VADisplay for which CL interop should be established. +@param tryInterop - try to set up for interoperability, if true; set up for use slow copy if false. +@return Returns reference to OpenCL Context + */ +CV_EXPORTS Context& initializeContextFromVA(VADisplay display, bool tryInterop = true); + +} // namespace cv::va_intel::ocl + +/** @brief Converts InputArray to VASurfaceID object. +@param display - VADisplay object. +@param src - source InputArray. +@param surface - destination VASurfaceID object. +@param size - size of image represented by VASurfaceID object. + */ +CV_EXPORTS void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface, Size size); + +/** @brief Converts VASurfaceID object to OutputArray. +@param display - VADisplay object. +@param surface - source VASurfaceID object. +@param size - size of image represented by VASurfaceID object. +@param dst - destination OutputArray. + */ +CV_EXPORTS void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, OutputArray dst); + +//! @} + +}} // namespace cv::va_intel + +#endif /* OPENCV_CORE_VA_INTEL_HPP */ diff --git a/include/opencv2/core/version.hpp b/include/opencv2/core/version.hpp index e8662aa..91f95ee 100644 --- a/include/opencv2/core/version.hpp +++ b/include/opencv2/core/version.hpp @@ -1,64 +1,19 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright( C) 2000-2015, Intel Corporation, all rights reserved. -// Copyright (C) 2011-2013, NVIDIA Corporation, all rights reserved. -// Copyright (C) 2013, OpenCV Foundation, all rights reserved. -// Copyright (C) 2015, Itseez Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -//(including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort(including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. -/* - definition of the current version of OpenCV - Usefull to test in user programs -*/ - -#ifndef __OPENCV_VERSION_HPP__ -#define __OPENCV_VERSION_HPP__ +#ifndef OPENCV_VERSION_HPP +#define OPENCV_VERSION_HPP #define CV_VERSION_MAJOR 3 -#define CV_VERSION_MINOR 0 -#define CV_VERSION_REVISION 0 +#define CV_VERSION_MINOR 4 +#define CV_VERSION_REVISION 5 #define CV_VERSION_STATUS "" #define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR(__A) CVAUX_STR_EXP(__A) -#define CVAUX_STRW_EXP(__A) L#__A +#define CVAUX_STRW_EXP(__A) L ## #__A #define CVAUX_STRW(__A) CVAUX_STRW_EXP(__A) #define CV_VERSION CVAUX_STR(CV_VERSION_MAJOR) "." CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(CV_VERSION_REVISION) CV_VERSION_STATUS @@ -68,4 +23,4 @@ #define CV_MINOR_VERSION CV_VERSION_MINOR #define CV_SUBMINOR_VERSION CV_VERSION_REVISION -#endif +#endif // OPENCV_VERSION_HPP diff --git a/include/opencv2/core/vsx_utils.hpp b/include/opencv2/core/vsx_utils.hpp new file mode 100644 index 0000000..b4e3f30 --- /dev/null +++ b/include/opencv2/core/vsx_utils.hpp @@ -0,0 +1,1011 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_VSX_UTILS_HPP +#define OPENCV_HAL_VSX_UTILS_HPP + +#include "opencv2/core/cvdef.h" + +#ifndef SKIP_INCLUDES +# include +#endif + +//! @addtogroup core_utils_vsx +//! @{ +#if CV_VSX + +#define __VSX_S16__(c, v) (c){v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v} +#define __VSX_S8__(c, v) (c){v, v, v, v, v, v, v, v} +#define __VSX_S4__(c, v) (c){v, v, v, v} +#define __VSX_S2__(c, v) (c){v, v} + +typedef __vector unsigned char vec_uchar16; +#define vec_uchar16_set(...) (vec_uchar16){__VA_ARGS__} +#define vec_uchar16_sp(c) (__VSX_S16__(vec_uchar16, c)) +#define vec_uchar16_c(v) ((vec_uchar16)(v)) +#define vec_uchar16_z vec_uchar16_sp(0) + +typedef __vector signed char vec_char16; +#define vec_char16_set(...) (vec_char16){__VA_ARGS__} +#define vec_char16_sp(c) (__VSX_S16__(vec_char16, c)) +#define vec_char16_c(v) ((vec_char16)(v)) +#define vec_char16_z vec_char16_sp(0) + +typedef __vector unsigned short vec_ushort8; +#define vec_ushort8_set(...) (vec_ushort8){__VA_ARGS__} +#define vec_ushort8_sp(c) (__VSX_S8__(vec_ushort8, c)) +#define vec_ushort8_c(v) ((vec_ushort8)(v)) +#define vec_ushort8_z vec_ushort8_sp(0) + +typedef __vector signed short vec_short8; +#define vec_short8_set(...) (vec_short8){__VA_ARGS__} +#define vec_short8_sp(c) (__VSX_S8__(vec_short8, c)) +#define vec_short8_c(v) ((vec_short8)(v)) +#define vec_short8_z vec_short8_sp(0) + +typedef __vector unsigned int vec_uint4; +#define vec_uint4_set(...) (vec_uint4){__VA_ARGS__} +#define vec_uint4_sp(c) (__VSX_S4__(vec_uint4, c)) +#define vec_uint4_c(v) ((vec_uint4)(v)) +#define vec_uint4_z vec_uint4_sp(0) + +typedef __vector signed int vec_int4; +#define vec_int4_set(...) (vec_int4){__VA_ARGS__} +#define vec_int4_sp(c) (__VSX_S4__(vec_int4, c)) +#define vec_int4_c(v) ((vec_int4)(v)) +#define vec_int4_z vec_int4_sp(0) + +typedef __vector float vec_float4; +#define vec_float4_set(...) (vec_float4){__VA_ARGS__} +#define vec_float4_sp(c) (__VSX_S4__(vec_float4, c)) +#define vec_float4_c(v) ((vec_float4)(v)) +#define vec_float4_z vec_float4_sp(0) + +typedef __vector unsigned long long vec_udword2; +#define vec_udword2_set(...) (vec_udword2){__VA_ARGS__} +#define vec_udword2_sp(c) (__VSX_S2__(vec_udword2, c)) +#define vec_udword2_c(v) ((vec_udword2)(v)) +#define vec_udword2_z vec_udword2_sp(0) + +typedef __vector signed long long vec_dword2; +#define vec_dword2_set(...) (vec_dword2){__VA_ARGS__} +#define vec_dword2_sp(c) (__VSX_S2__(vec_dword2, c)) +#define vec_dword2_c(v) ((vec_dword2)(v)) +#define vec_dword2_z vec_dword2_sp(0) + +typedef __vector double vec_double2; +#define vec_double2_set(...) (vec_double2){__VA_ARGS__} +#define vec_double2_c(v) ((vec_double2)(v)) +#define vec_double2_sp(c) (__VSX_S2__(vec_double2, c)) +#define vec_double2_z vec_double2_sp(0) + +#define vec_bchar16 __vector __bool char +#define vec_bchar16_set(...) (vec_bchar16){__VA_ARGS__} +#define vec_bchar16_c(v) ((vec_bchar16)(v)) + +#define vec_bshort8 __vector __bool short +#define vec_bshort8_set(...) (vec_bshort8){__VA_ARGS__} +#define vec_bshort8_c(v) ((vec_bshort8)(v)) + +#define vec_bint4 __vector __bool int +#define vec_bint4_set(...) (vec_bint4){__VA_ARGS__} +#define vec_bint4_c(v) ((vec_bint4)(v)) + +#define vec_bdword2 __vector __bool long long +#define vec_bdword2_set(...) (vec_bdword2){__VA_ARGS__} +#define vec_bdword2_c(v) ((vec_bdword2)(v)) + +#define VSX_FINLINE(tp) extern inline tp __attribute__((always_inline)) + +#define VSX_REDIRECT_1RG(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) { return fn2(a); } + +#define VSX_REDIRECT_2RG(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a, const rg& b) { return fn2(a, b); } + +/* + * GCC VSX compatibility +**/ +#if defined(__GNUG__) && !defined(__clang__) + +// inline asm helper +#define VSX_IMPL_1RG(rt, rto, rg, rgo, opc, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ rt rs; __asm__ __volatile__(#opc" %x0,%x1" : "="#rto (rs) : #rgo (a)); return rs; } + +#define VSX_IMPL_1VRG(rt, rg, opc, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ rt rs; __asm__ __volatile__(#opc" %0,%1" : "=v" (rs) : "v" (a)); return rs; } + +#define VSX_IMPL_2VRG_F(rt, rg, fopc, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a, const rg& b) \ +{ rt rs; __asm__ __volatile__(fopc : "=v" (rs) : "v" (a), "v" (b)); return rs; } + +#define VSX_IMPL_2VRG(rt, rg, opc, fnm) VSX_IMPL_2VRG_F(rt, rg, #opc" %0,%1,%2", fnm) + +#if __GNUG__ < 7 +// up to GCC 6 vec_mul only supports precisions and llong +# ifdef vec_mul +# undef vec_mul +# endif +/* + * there's no a direct instruction for supporting 8-bit, 16-bit multiplication in ISA 2.07, + * XLC Implement it by using instruction "multiply even", "multiply odd" and "permute" +**/ +# define VSX_IMPL_MULH(Tvec, cperm) \ + VSX_FINLINE(Tvec) vec_mul(const Tvec& a, const Tvec& b) \ + { \ + static const vec_uchar16 ev_od = {cperm}; \ + return vec_perm((Tvec)vec_mule(a, b), (Tvec)vec_mulo(a, b), ev_od); \ + } + #define VSX_IMPL_MULH_P16 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30 + VSX_IMPL_MULH(vec_char16, VSX_IMPL_MULH_P16) + VSX_IMPL_MULH(vec_uchar16, VSX_IMPL_MULH_P16) + #define VSX_IMPL_MULH_P8 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29 + VSX_IMPL_MULH(vec_short8, VSX_IMPL_MULH_P8) + VSX_IMPL_MULH(vec_ushort8, VSX_IMPL_MULH_P8) + // vmuluwm can be used for unsigned or signed integers, that's what they said + VSX_IMPL_2VRG(vec_int4, vec_int4, vmuluwm, vec_mul) + VSX_IMPL_2VRG(vec_uint4, vec_uint4, vmuluwm, vec_mul) + // redirect to GCC builtin vec_mul, since it already supports precisions and llong + VSX_REDIRECT_2RG(vec_float4, vec_float4, vec_mul, __builtin_vec_mul) + VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mul, __builtin_vec_mul) + VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mul, __builtin_vec_mul) + VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mul, __builtin_vec_mul) +#endif // __GNUG__ < 7 + +#if __GNUG__ < 6 +/* + * Instruction "compare greater than or equal" in ISA 2.07 only supports single + * and double precision. + * In XLC and new versions of GCC implement integers by using instruction "greater than" and NOR. +**/ +# ifdef vec_cmpge +# undef vec_cmpge +# endif +# ifdef vec_cmple +# undef vec_cmple +# endif +# define vec_cmple(a, b) vec_cmpge(b, a) +# define VSX_IMPL_CMPGE(rt, rg, opc, fnm) \ + VSX_IMPL_2VRG_F(rt, rg, #opc" %0,%2,%1\n\t xxlnor %x0,%x0,%x0", fnm) + + VSX_IMPL_CMPGE(vec_bchar16, vec_char16, vcmpgtsb, vec_cmpge) + VSX_IMPL_CMPGE(vec_bchar16, vec_uchar16, vcmpgtub, vec_cmpge) + VSX_IMPL_CMPGE(vec_bshort8, vec_short8, vcmpgtsh, vec_cmpge) + VSX_IMPL_CMPGE(vec_bshort8, vec_ushort8, vcmpgtuh, vec_cmpge) + VSX_IMPL_CMPGE(vec_bint4, vec_int4, vcmpgtsw, vec_cmpge) + VSX_IMPL_CMPGE(vec_bint4, vec_uint4, vcmpgtuw, vec_cmpge) + VSX_IMPL_CMPGE(vec_bdword2, vec_dword2, vcmpgtsd, vec_cmpge) + VSX_IMPL_CMPGE(vec_bdword2, vec_udword2, vcmpgtud, vec_cmpge) + +// redirect to GCC builtin cmpge, since it already supports precisions + VSX_REDIRECT_2RG(vec_bint4, vec_float4, vec_cmpge, __builtin_vec_cmpge) + VSX_REDIRECT_2RG(vec_bdword2, vec_double2, vec_cmpge, __builtin_vec_cmpge) + +// up to gcc5 vec_nor doesn't support bool long long +# undef vec_nor + template + VSX_REDIRECT_2RG(T, T, vec_nor, __builtin_vec_nor) + + VSX_FINLINE(vec_bdword2) vec_nor(const vec_bdword2& a, const vec_bdword2& b) + { return vec_bdword2_c(__builtin_vec_nor(vec_dword2_c(a), vec_dword2_c(b))); } + +// vec_packs doesn't support double words in gcc4 and old versions of gcc5 +# undef vec_packs + VSX_REDIRECT_2RG(vec_char16, vec_short8, vec_packs, __builtin_vec_packs) + VSX_REDIRECT_2RG(vec_uchar16, vec_ushort8, vec_packs, __builtin_vec_packs) + VSX_REDIRECT_2RG(vec_short8, vec_int4, vec_packs, __builtin_vec_packs) + VSX_REDIRECT_2RG(vec_ushort8, vec_uint4, vec_packs, __builtin_vec_packs) + + VSX_IMPL_2VRG_F(vec_int4, vec_dword2, "vpksdss %0,%2,%1", vec_packs) + VSX_IMPL_2VRG_F(vec_uint4, vec_udword2, "vpkudus %0,%2,%1", vec_packs) +#endif // __GNUG__ < 6 + +#if __GNUG__ < 5 +// vec_xxpermdi in gcc4 missing little-endian supports just like clang +# define vec_permi(a, b, c) vec_xxpermdi(b, a, (3 ^ (((c) & 1) << 1 | (c) >> 1))) +#else +# define vec_permi vec_xxpermdi +#endif // __GNUG__ < 5 + +// shift left double by word immediate +#ifndef vec_sldw +# define vec_sldw __builtin_vsx_xxsldwi +#endif + +// vector population count +VSX_IMPL_1VRG(vec_uchar16, vec_uchar16, vpopcntb, vec_popcntu) +VSX_IMPL_1VRG(vec_uchar16, vec_char16, vpopcntb, vec_popcntu) +VSX_IMPL_1VRG(vec_ushort8, vec_ushort8, vpopcnth, vec_popcntu) +VSX_IMPL_1VRG(vec_ushort8, vec_short8, vpopcnth, vec_popcntu) +VSX_IMPL_1VRG(vec_uint4, vec_uint4, vpopcntw, vec_popcntu) +VSX_IMPL_1VRG(vec_uint4, vec_int4, vpopcntw, vec_popcntu) +VSX_IMPL_1VRG(vec_udword2, vec_udword2, vpopcntd, vec_popcntu) +VSX_IMPL_1VRG(vec_udword2, vec_dword2, vpopcntd, vec_popcntu) + +// converts between single and double-precision +VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, __builtin_vsx_xvcvdpsp) +VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, __builtin_vsx_xvcvspdp) + +// converts word and doubleword to double-precision +#ifdef vec_ctd +# undef vec_ctd +#endif +VSX_IMPL_1RG(vec_double2, wd, vec_int4, wa, xvcvsxwdp, vec_ctdo) +VSX_IMPL_1RG(vec_double2, wd, vec_uint4, wa, xvcvuxwdp, vec_ctdo) +VSX_IMPL_1RG(vec_double2, wd, vec_dword2, wi, xvcvsxddp, vec_ctd) +VSX_IMPL_1RG(vec_double2, wd, vec_udword2, wi, xvcvuxddp, vec_ctd) + +// converts word and doubleword to single-precision +#undef vec_ctf +VSX_IMPL_1RG(vec_float4, wf, vec_int4, wa, xvcvsxwsp, vec_ctf) +VSX_IMPL_1RG(vec_float4, wf, vec_uint4, wa, xvcvuxwsp, vec_ctf) +VSX_IMPL_1RG(vec_float4, wf, vec_dword2, wi, xvcvsxdsp, vec_ctfo) +VSX_IMPL_1RG(vec_float4, wf, vec_udword2, wi, xvcvuxdsp, vec_ctfo) + +// converts single and double precision to signed word +#undef vec_cts +VSX_IMPL_1RG(vec_int4, wa, vec_double2, wd, xvcvdpsxws, vec_ctso) +VSX_IMPL_1RG(vec_int4, wa, vec_float4, wf, xvcvspsxws, vec_cts) + +// converts single and double precision to unsigned word +#undef vec_ctu +VSX_IMPL_1RG(vec_uint4, wa, vec_double2, wd, xvcvdpuxws, vec_ctuo) +VSX_IMPL_1RG(vec_uint4, wa, vec_float4, wf, xvcvspuxws, vec_ctu) + +// converts single and double precision to signed doubleword +#ifdef vec_ctsl +# undef vec_ctsl +#endif +VSX_IMPL_1RG(vec_dword2, wi, vec_double2, wd, xvcvdpsxds, vec_ctsl) +VSX_IMPL_1RG(vec_dword2, wi, vec_float4, wf, xvcvspsxds, vec_ctslo) + +// converts single and double precision to unsigned doubleword +#ifdef vec_ctul +# undef vec_ctul +#endif +VSX_IMPL_1RG(vec_udword2, wi, vec_double2, wd, xvcvdpuxds, vec_ctul) +VSX_IMPL_1RG(vec_udword2, wi, vec_float4, wf, xvcvspuxds, vec_ctulo) + +// just in case if GCC doesn't define it +#ifndef vec_xl +# define vec_xl vec_vsx_ld +# define vec_xst vec_vsx_st +#endif + +#endif // GCC VSX compatibility + +/* + * CLANG VSX compatibility +**/ +#if defined(__clang__) && !defined(__IBMCPP__) + +/* + * CLANG doesn't support %x in the inline asm template which fixes register number + * when using any of the register constraints wa, wd, wf + * + * For more explanation checkout PowerPC and IBM RS6000 in https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html + * Also there's already an open bug https://bugs.llvm.org/show_bug.cgi?id=31837 + * + * So we're not able to use inline asm and only use built-in functions that CLANG supports + * and use __builtin_convertvector if clang missng any of vector conversions built-in functions +*/ + +// convert vector helper +#define VSX_IMPL_CONVERT(rt, rg, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) { return __builtin_convertvector(a, rt); } + +#if __clang_major__ < 5 +// implement vec_permi in a dirty way +# define VSX_IMPL_CLANG_4_PERMI(Tvec) \ + VSX_FINLINE(Tvec) vec_permi(const Tvec& a, const Tvec& b, unsigned const char c) \ + { \ + switch (c) \ + { \ + case 0: \ + return vec_mergeh(a, b); \ + case 1: \ + return vec_mergel(vec_mergeh(a, a), b); \ + case 2: \ + return vec_mergeh(vec_mergel(a, a), b); \ + default: \ + return vec_mergel(a, b); \ + } \ + } + VSX_IMPL_CLANG_4_PERMI(vec_udword2) + VSX_IMPL_CLANG_4_PERMI(vec_dword2) + VSX_IMPL_CLANG_4_PERMI(vec_double2) + +// vec_xxsldwi is missing in clang 4 +# define vec_xxsldwi(a, b, c) vec_sld(a, b, (c) * 4) +#else +// vec_xxpermdi is missing little-endian supports in clang 4 just like gcc4 +# define vec_permi(a, b, c) vec_xxpermdi(b, a, (3 ^ (((c) & 1) << 1 | (c) >> 1))) +#endif // __clang_major__ < 5 + +// shift left double by word immediate +#ifndef vec_sldw +# define vec_sldw vec_xxsldwi +#endif + +// Implement vec_rsqrt since clang only supports vec_rsqrte +#ifndef vec_rsqrt + VSX_FINLINE(vec_float4) vec_rsqrt(const vec_float4& a) + { return vec_div(vec_float4_sp(1), vec_sqrt(a)); } + + VSX_FINLINE(vec_double2) vec_rsqrt(const vec_double2& a) + { return vec_div(vec_double2_sp(1), vec_sqrt(a)); } +#endif + +// vec_promote missing support for doubleword +VSX_FINLINE(vec_dword2) vec_promote(long long a, int b) +{ + vec_dword2 ret = vec_dword2_z; + ret[b & 1] = a; + return ret; +} + +VSX_FINLINE(vec_udword2) vec_promote(unsigned long long a, int b) +{ + vec_udword2 ret = vec_udword2_z; + ret[b & 1] = a; + return ret; +} + +// vec_popcnt should return unsigned but clang has different thought just like gcc in vec_vpopcnt +#define VSX_IMPL_POPCNTU(Tvec, Tvec2, ucast) \ +VSX_FINLINE(Tvec) vec_popcntu(const Tvec2& a) \ +{ return ucast(vec_popcnt(a)); } +VSX_IMPL_POPCNTU(vec_uchar16, vec_char16, vec_uchar16_c); +VSX_IMPL_POPCNTU(vec_ushort8, vec_short8, vec_ushort8_c); +VSX_IMPL_POPCNTU(vec_uint4, vec_int4, vec_uint4_c); +// redirect unsigned types +VSX_REDIRECT_1RG(vec_uchar16, vec_uchar16, vec_popcntu, vec_popcnt) +VSX_REDIRECT_1RG(vec_ushort8, vec_ushort8, vec_popcntu, vec_popcnt) +VSX_REDIRECT_1RG(vec_uint4, vec_uint4, vec_popcntu, vec_popcnt) + +// converts between single and double precision +VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, __builtin_vsx_xvcvdpsp) +VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, __builtin_vsx_xvcvspdp) + +// converts word and doubleword to double-precision +#ifdef vec_ctd +# undef vec_ctd +#endif +VSX_REDIRECT_1RG(vec_double2, vec_int4, vec_ctdo, __builtin_vsx_xvcvsxwdp) +VSX_REDIRECT_1RG(vec_double2, vec_uint4, vec_ctdo, __builtin_vsx_xvcvuxwdp) + +VSX_IMPL_CONVERT(vec_double2, vec_dword2, vec_ctd) +VSX_IMPL_CONVERT(vec_double2, vec_udword2, vec_ctd) + +// converts word and doubleword to single-precision +#if __clang_major__ > 4 +# undef vec_ctf +#endif +VSX_IMPL_CONVERT(vec_float4, vec_int4, vec_ctf) +VSX_IMPL_CONVERT(vec_float4, vec_uint4, vec_ctf) +VSX_REDIRECT_1RG(vec_float4, vec_dword2, vec_ctfo, __builtin_vsx_xvcvsxdsp) +VSX_REDIRECT_1RG(vec_float4, vec_udword2, vec_ctfo, __builtin_vsx_xvcvuxdsp) + +// converts single and double precision to signed word +#if __clang_major__ > 4 +# undef vec_cts +#endif +VSX_REDIRECT_1RG(vec_int4, vec_double2, vec_ctso, __builtin_vsx_xvcvdpsxws) +VSX_IMPL_CONVERT(vec_int4, vec_float4, vec_cts) + +// converts single and double precision to unsigned word +#if __clang_major__ > 4 +# undef vec_ctu +#endif +VSX_REDIRECT_1RG(vec_uint4, vec_double2, vec_ctuo, __builtin_vsx_xvcvdpuxws) +VSX_IMPL_CONVERT(vec_uint4, vec_float4, vec_ctu) + +// converts single and double precision to signed doubleword +#ifdef vec_ctsl +# undef vec_ctsl +#endif +VSX_IMPL_CONVERT(vec_dword2, vec_double2, vec_ctsl) +// __builtin_convertvector unable to convert, xvcvspsxds is missing on it +VSX_FINLINE(vec_dword2) vec_ctslo(const vec_float4& a) +{ return vec_ctsl(vec_cvfo(a)); } + +// converts single and double precision to unsigned doubleword +#ifdef vec_ctul +# undef vec_ctul +#endif +VSX_IMPL_CONVERT(vec_udword2, vec_double2, vec_ctul) +// __builtin_convertvector unable to convert, xvcvspuxds is missing on it +VSX_FINLINE(vec_udword2) vec_ctulo(const vec_float4& a) +{ return vec_ctul(vec_cvfo(a)); } + +#endif // CLANG VSX compatibility + +/* + * Common GCC, CLANG compatibility +**/ +#if defined(__GNUG__) && !defined(__IBMCPP__) + +#ifdef vec_cvf +# undef vec_cvf +#endif + +#define VSX_IMPL_CONV_EVEN_4_2(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ return fn2(vec_sldw(a, a, 1)); } + +VSX_IMPL_CONV_EVEN_4_2(vec_double2, vec_float4, vec_cvf, vec_cvfo) +VSX_IMPL_CONV_EVEN_4_2(vec_double2, vec_int4, vec_ctd, vec_ctdo) +VSX_IMPL_CONV_EVEN_4_2(vec_double2, vec_uint4, vec_ctd, vec_ctdo) + +VSX_IMPL_CONV_EVEN_4_2(vec_dword2, vec_float4, vec_ctsl, vec_ctslo) +VSX_IMPL_CONV_EVEN_4_2(vec_udword2, vec_float4, vec_ctul, vec_ctulo) + +#define VSX_IMPL_CONV_EVEN_2_4(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ \ + rt v4 = fn2(a); \ + return vec_sldw(v4, v4, 3); \ +} + +VSX_IMPL_CONV_EVEN_2_4(vec_float4, vec_double2, vec_cvf, vec_cvfo) +VSX_IMPL_CONV_EVEN_2_4(vec_float4, vec_dword2, vec_ctf, vec_ctfo) +VSX_IMPL_CONV_EVEN_2_4(vec_float4, vec_udword2, vec_ctf, vec_ctfo) + +VSX_IMPL_CONV_EVEN_2_4(vec_int4, vec_double2, vec_cts, vec_ctso) +VSX_IMPL_CONV_EVEN_2_4(vec_uint4, vec_double2, vec_ctu, vec_ctuo) + +// Only for Eigen! +/* + * changing behavior of conversion intrinsics for gcc has effect on Eigen + * so we redfine old behavior again only on gcc, clang +*/ +#if !defined(__clang__) || __clang_major__ > 4 + // ignoring second arg since Eigen only truncates toward zero +# define VSX_IMPL_CONV_2VARIANT(rt, rg, fnm, fn2) \ + VSX_FINLINE(rt) fnm(const rg& a, int only_truncate) \ + { \ + assert(only_truncate == 0); \ + CV_UNUSED(only_truncate); \ + return fn2(a); \ + } + VSX_IMPL_CONV_2VARIANT(vec_int4, vec_float4, vec_cts, vec_cts) + VSX_IMPL_CONV_2VARIANT(vec_float4, vec_int4, vec_ctf, vec_ctf) + // define vec_cts for converting double precision to signed doubleword + // which isn't combitable with xlc but its okay since Eigen only use it for gcc + VSX_IMPL_CONV_2VARIANT(vec_dword2, vec_double2, vec_cts, vec_ctsl) +#endif // Eigen + +#endif // Common GCC, CLANG compatibility + +/* + * XLC VSX compatibility +**/ +#if defined(__IBMCPP__) + +// vector population count +#define vec_popcntu vec_popcnt + +// overload and redirect with setting second arg to zero +// since we only support conversions without the second arg +#define VSX_IMPL_OVERLOAD_Z2(rt, rg, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) { return fnm(a, 0); } + +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_int4, vec_ctd) +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_uint4, vec_ctd) +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_dword2, vec_ctd) +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_udword2, vec_ctd) + +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_int4, vec_ctf) +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_uint4, vec_ctf) +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_dword2, vec_ctf) +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_udword2, vec_ctf) + +VSX_IMPL_OVERLOAD_Z2(vec_int4, vec_double2, vec_cts) +VSX_IMPL_OVERLOAD_Z2(vec_int4, vec_float4, vec_cts) + +VSX_IMPL_OVERLOAD_Z2(vec_uint4, vec_double2, vec_ctu) +VSX_IMPL_OVERLOAD_Z2(vec_uint4, vec_float4, vec_ctu) + +VSX_IMPL_OVERLOAD_Z2(vec_dword2, vec_double2, vec_ctsl) +VSX_IMPL_OVERLOAD_Z2(vec_dword2, vec_float4, vec_ctsl) + +VSX_IMPL_OVERLOAD_Z2(vec_udword2, vec_double2, vec_ctul) +VSX_IMPL_OVERLOAD_Z2(vec_udword2, vec_float4, vec_ctul) + +// fixme: implement conversions of odd-numbered elements in a dirty way +// since xlc doesn't support VSX registers operand in inline asm. +#define VSX_IMPL_CONV_ODD_4_2(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) { return fn2(vec_sldw(a, a, 3)); } + +VSX_IMPL_CONV_ODD_4_2(vec_double2, vec_float4, vec_cvfo, vec_cvf) +VSX_IMPL_CONV_ODD_4_2(vec_double2, vec_int4, vec_ctdo, vec_ctd) +VSX_IMPL_CONV_ODD_4_2(vec_double2, vec_uint4, vec_ctdo, vec_ctd) + +VSX_IMPL_CONV_ODD_4_2(vec_dword2, vec_float4, vec_ctslo, vec_ctsl) +VSX_IMPL_CONV_ODD_4_2(vec_udword2, vec_float4, vec_ctulo, vec_ctul) + +#define VSX_IMPL_CONV_ODD_2_4(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ \ + rt v4 = fn2(a); \ + return vec_sldw(v4, v4, 1); \ +} + +VSX_IMPL_CONV_ODD_2_4(vec_float4, vec_double2, vec_cvfo, vec_cvf) +VSX_IMPL_CONV_ODD_2_4(vec_float4, vec_dword2, vec_ctfo, vec_ctf) +VSX_IMPL_CONV_ODD_2_4(vec_float4, vec_udword2, vec_ctfo, vec_ctf) + +VSX_IMPL_CONV_ODD_2_4(vec_int4, vec_double2, vec_ctso, vec_cts) +VSX_IMPL_CONV_ODD_2_4(vec_uint4, vec_double2, vec_ctuo, vec_ctu) + +#endif // XLC VSX compatibility + +// ignore GCC warning that caused by -Wunused-but-set-variable in rare cases +#if defined(__GNUG__) && !defined(__clang__) +# define VSX_UNUSED(Tvec) Tvec __attribute__((__unused__)) +#else // CLANG, XLC +# define VSX_UNUSED(Tvec) Tvec +#endif + +// gcc can find his way in casting log int and XLC, CLANG ambiguous +#if defined(__clang__) || defined(__IBMCPP__) + VSX_FINLINE(vec_udword2) vec_splats(uint64 v) + { return vec_splats((unsigned long long) v); } + + VSX_FINLINE(vec_dword2) vec_splats(int64 v) + { return vec_splats((long long) v); } + + VSX_FINLINE(vec_udword2) vec_promote(uint64 a, int b) + { return vec_promote((unsigned long long) a, b); } + + VSX_FINLINE(vec_dword2) vec_promote(int64 a, int b) + { return vec_promote((long long) a, b); } +#endif + +/* + * implement vsx_ld(offset, pointer), vsx_st(vector, offset, pointer) + * load and set using offset depend on the pointer type + * + * implement vsx_ldf(offset, pointer), vsx_stf(vector, offset, pointer) + * load and set using offset depend on fixed bytes size + * + * Note: In clang vec_xl and vec_xst fails to load unaligned addresses + * so we are using vec_vsx_ld, vec_vsx_st instead +*/ + +#if defined(__clang__) && !defined(__IBMCPP__) +# define vsx_ldf vec_vsx_ld +# define vsx_stf vec_vsx_st +#else // GCC , XLC +# define vsx_ldf vec_xl +# define vsx_stf vec_xst +#endif + +#define VSX_OFFSET(o, p) ((o) * sizeof(*(p))) +#define vsx_ld(o, p) vsx_ldf(VSX_OFFSET(o, p), p) +#define vsx_st(v, o, p) vsx_stf(v, VSX_OFFSET(o, p), p) + +/* + * implement vsx_ld2(offset, pointer), vsx_st2(vector, offset, pointer) to load and store double words + * In GCC vec_xl and vec_xst it maps to vec_vsx_ld, vec_vsx_st which doesn't support long long + * and in CLANG we are using vec_vsx_ld, vec_vsx_st because vec_xl, vec_xst fails to load unaligned addresses + * + * In XLC vec_xl and vec_xst fail to cast int64(long int) to long long +*/ +#if (defined(__GNUG__) || defined(__clang__)) && !defined(__IBMCPP__) + VSX_FINLINE(vec_udword2) vsx_ld2(long o, const uint64* p) + { return vec_udword2_c(vsx_ldf(VSX_OFFSET(o, p), (unsigned int*)p)); } + + VSX_FINLINE(vec_dword2) vsx_ld2(long o, const int64* p) + { return vec_dword2_c(vsx_ldf(VSX_OFFSET(o, p), (int*)p)); } + + VSX_FINLINE(void) vsx_st2(const vec_udword2& vec, long o, uint64* p) + { vsx_stf(vec_uint4_c(vec), VSX_OFFSET(o, p), (unsigned int*)p); } + + VSX_FINLINE(void) vsx_st2(const vec_dword2& vec, long o, int64* p) + { vsx_stf(vec_int4_c(vec), VSX_OFFSET(o, p), (int*)p); } +#else // XLC + VSX_FINLINE(vec_udword2) vsx_ld2(long o, const uint64* p) + { return vsx_ldf(VSX_OFFSET(o, p), (unsigned long long*)p); } + + VSX_FINLINE(vec_dword2) vsx_ld2(long o, const int64* p) + { return vsx_ldf(VSX_OFFSET(o, p), (long long*)p); } + + VSX_FINLINE(void) vsx_st2(const vec_udword2& vec, long o, uint64* p) + { vsx_stf(vec, VSX_OFFSET(o, p), (unsigned long long*)p); } + + VSX_FINLINE(void) vsx_st2(const vec_dword2& vec, long o, int64* p) + { vsx_stf(vec, VSX_OFFSET(o, p), (long long*)p); } +#endif + +// Store lower 8 byte +#define vec_st_l8(v, p) *((uint64*)(p)) = vec_extract(vec_udword2_c(v), 0) + +// Store higher 8 byte +#define vec_st_h8(v, p) *((uint64*)(p)) = vec_extract(vec_udword2_c(v), 1) + +// Load 64-bits of integer data to lower part +#define VSX_IMPL_LOAD_L8(Tvec, Tp) \ +VSX_FINLINE(Tvec) vec_ld_l8(const Tp *p) \ +{ return ((Tvec)vec_promote(*((uint64*)p), 0)); } + +VSX_IMPL_LOAD_L8(vec_uchar16, uchar) +VSX_IMPL_LOAD_L8(vec_char16, schar) +VSX_IMPL_LOAD_L8(vec_ushort8, ushort) +VSX_IMPL_LOAD_L8(vec_short8, short) +VSX_IMPL_LOAD_L8(vec_uint4, uint) +VSX_IMPL_LOAD_L8(vec_int4, int) +VSX_IMPL_LOAD_L8(vec_float4, float) +VSX_IMPL_LOAD_L8(vec_udword2, uint64) +VSX_IMPL_LOAD_L8(vec_dword2, int64) +VSX_IMPL_LOAD_L8(vec_double2, double) + +// logical not +#define vec_not(a) vec_nor(a, a) + +// power9 yaya +// not equal +#ifndef vec_cmpne +# define vec_cmpne(a, b) vec_not(vec_cmpeq(a, b)) +#endif + +// absolute difference +#ifndef vec_absd +# define vec_absd(a, b) vec_sub(vec_max(a, b), vec_min(a, b)) +#endif + +/* + * Implement vec_unpacklu and vec_unpackhu + * since vec_unpackl, vec_unpackh only support signed integers +**/ +#define VSX_IMPL_UNPACKU(rt, rg, zero) \ +VSX_FINLINE(rt) vec_unpacklu(const rg& a) \ +{ return (rt)(vec_mergel(a, zero)); } \ +VSX_FINLINE(rt) vec_unpackhu(const rg& a) \ +{ return (rt)(vec_mergeh(a, zero)); } + +VSX_IMPL_UNPACKU(vec_ushort8, vec_uchar16, vec_uchar16_z) +VSX_IMPL_UNPACKU(vec_uint4, vec_ushort8, vec_ushort8_z) +VSX_IMPL_UNPACKU(vec_udword2, vec_uint4, vec_uint4_z) + +/* + * Implement vec_mergesqe and vec_mergesqo + * Merges the sequence values of even and odd elements of two vectors +*/ +#define VSX_IMPL_PERM(rt, fnm, ...) \ +VSX_FINLINE(rt) fnm(const rt& a, const rt& b) \ +{ static const vec_uchar16 perm = {__VA_ARGS__}; return vec_perm(a, b, perm); } + +// 16 +#define perm16_mergesqe 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 +#define perm16_mergesqo 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 +VSX_IMPL_PERM(vec_uchar16, vec_mergesqe, perm16_mergesqe) +VSX_IMPL_PERM(vec_uchar16, vec_mergesqo, perm16_mergesqo) +VSX_IMPL_PERM(vec_char16, vec_mergesqe, perm16_mergesqe) +VSX_IMPL_PERM(vec_char16, vec_mergesqo, perm16_mergesqo) +// 8 +#define perm8_mergesqe 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 +#define perm8_mergesqo 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 +VSX_IMPL_PERM(vec_ushort8, vec_mergesqe, perm8_mergesqe) +VSX_IMPL_PERM(vec_ushort8, vec_mergesqo, perm8_mergesqo) +VSX_IMPL_PERM(vec_short8, vec_mergesqe, perm8_mergesqe) +VSX_IMPL_PERM(vec_short8, vec_mergesqo, perm8_mergesqo) +// 4 +#define perm4_mergesqe 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27 +#define perm4_mergesqo 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 +VSX_IMPL_PERM(vec_uint4, vec_mergesqe, perm4_mergesqe) +VSX_IMPL_PERM(vec_uint4, vec_mergesqo, perm4_mergesqo) +VSX_IMPL_PERM(vec_int4, vec_mergesqe, perm4_mergesqe) +VSX_IMPL_PERM(vec_int4, vec_mergesqo, perm4_mergesqo) +VSX_IMPL_PERM(vec_float4, vec_mergesqe, perm4_mergesqe) +VSX_IMPL_PERM(vec_float4, vec_mergesqo, perm4_mergesqo) +// 2 +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesqe, vec_mergeh) +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesqo, vec_mergel) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesqe, vec_mergeh) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesqo, vec_mergel) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesqe, vec_mergeh) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesqo, vec_mergel) + +/* + * Implement vec_mergesqh and vec_mergesql + * Merges the sequence most and least significant halves of two vectors +*/ +#define VSX_IMPL_MERGESQHL(Tvec) \ +VSX_FINLINE(Tvec) vec_mergesqh(const Tvec& a, const Tvec& b) \ +{ return (Tvec)vec_mergeh(vec_udword2_c(a), vec_udword2_c(b)); } \ +VSX_FINLINE(Tvec) vec_mergesql(const Tvec& a, const Tvec& b) \ +{ return (Tvec)vec_mergel(vec_udword2_c(a), vec_udword2_c(b)); } +VSX_IMPL_MERGESQHL(vec_uchar16) +VSX_IMPL_MERGESQHL(vec_char16) +VSX_IMPL_MERGESQHL(vec_ushort8) +VSX_IMPL_MERGESQHL(vec_short8) +VSX_IMPL_MERGESQHL(vec_uint4) +VSX_IMPL_MERGESQHL(vec_int4) +VSX_IMPL_MERGESQHL(vec_float4) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesqh, vec_mergeh) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesql, vec_mergel) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesqh, vec_mergeh) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesql, vec_mergel) +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesqh, vec_mergeh) +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesql, vec_mergel) + + +// 2 and 4 channels interleave for all types except 2 lanes +#define VSX_IMPL_ST_INTERLEAVE(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, Tp* ptr) \ +{ \ + vsx_stf(vec_mergeh(a, b), 0, ptr); \ + vsx_stf(vec_mergel(a, b), 16, ptr); \ +} \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, const Tvec& d, Tp* ptr) \ +{ \ + Tvec ac = vec_mergeh(a, c); \ + Tvec bd = vec_mergeh(b, d); \ + vsx_stf(vec_mergeh(ac, bd), 0, ptr); \ + vsx_stf(vec_mergel(ac, bd), 16, ptr); \ + ac = vec_mergel(a, c); \ + bd = vec_mergel(b, d); \ + vsx_stf(vec_mergeh(ac, bd), 32, ptr); \ + vsx_stf(vec_mergel(ac, bd), 48, ptr); \ +} +VSX_IMPL_ST_INTERLEAVE(uchar, vec_uchar16) +VSX_IMPL_ST_INTERLEAVE(schar, vec_char16) +VSX_IMPL_ST_INTERLEAVE(ushort, vec_ushort8) +VSX_IMPL_ST_INTERLEAVE(short, vec_short8) +VSX_IMPL_ST_INTERLEAVE(uint, vec_uint4) +VSX_IMPL_ST_INTERLEAVE(int, vec_int4) +VSX_IMPL_ST_INTERLEAVE(float, vec_float4) + +// 2 and 4 channels deinterleave for 16 lanes +#define VSX_IMPL_ST_DINTERLEAVE_8(Tp, Tvec) \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(16, ptr); \ + a = vec_mergesqe(v0, v1); \ + b = vec_mergesqo(v0, v1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(16, ptr); \ + Tvec v2 = vsx_ld(32, ptr); \ + Tvec v3 = vsx_ld(48, ptr); \ + Tvec m0 = vec_mergesqe(v0, v1); \ + Tvec m1 = vec_mergesqe(v2, v3); \ + a = vec_mergesqe(m0, m1); \ + c = vec_mergesqo(m0, m1); \ + m0 = vec_mergesqo(v0, v1); \ + m1 = vec_mergesqo(v2, v3); \ + b = vec_mergesqe(m0, m1); \ + d = vec_mergesqo(m0, m1); \ +} +VSX_IMPL_ST_DINTERLEAVE_8(uchar, vec_uchar16) +VSX_IMPL_ST_DINTERLEAVE_8(schar, vec_char16) + +// 2 and 4 channels deinterleave for 8 lanes +#define VSX_IMPL_ST_DINTERLEAVE_16(Tp, Tvec) \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(8, ptr); \ + a = vec_mergesqe(v0, v1); \ + b = vec_mergesqo(v0, v1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(8, ptr); \ + Tvec m0 = vec_mergeh(v0, v1); \ + Tvec m1 = vec_mergel(v0, v1); \ + Tvec ab0 = vec_mergeh(m0, m1); \ + Tvec cd0 = vec_mergel(m0, m1); \ + v0 = vsx_ld(16, ptr); \ + v1 = vsx_ld(24, ptr); \ + m0 = vec_mergeh(v0, v1); \ + m1 = vec_mergel(v0, v1); \ + Tvec ab1 = vec_mergeh(m0, m1); \ + Tvec cd1 = vec_mergel(m0, m1); \ + a = vec_mergesqh(ab0, ab1); \ + b = vec_mergesql(ab0, ab1); \ + c = vec_mergesqh(cd0, cd1); \ + d = vec_mergesql(cd0, cd1); \ +} +VSX_IMPL_ST_DINTERLEAVE_16(ushort, vec_ushort8) +VSX_IMPL_ST_DINTERLEAVE_16(short, vec_short8) + +// 2 and 4 channels deinterleave for 4 lanes +#define VSX_IMPL_ST_DINTERLEAVE_32(Tp, Tvec) \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + a = vsx_ld(0, ptr); \ + b = vsx_ld(4, ptr); \ + Tvec m0 = vec_mergeh(a, b); \ + Tvec m1 = vec_mergel(a, b); \ + a = vec_mergeh(m0, m1); \ + b = vec_mergel(m0, m1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(4, ptr); \ + Tvec v2 = vsx_ld(8, ptr); \ + Tvec v3 = vsx_ld(12, ptr); \ + Tvec m0 = vec_mergeh(v0, v2); \ + Tvec m1 = vec_mergeh(v1, v3); \ + a = vec_mergeh(m0, m1); \ + b = vec_mergel(m0, m1); \ + m0 = vec_mergel(v0, v2); \ + m1 = vec_mergel(v1, v3); \ + c = vec_mergeh(m0, m1); \ + d = vec_mergel(m0, m1); \ +} +VSX_IMPL_ST_DINTERLEAVE_32(uint, vec_uint4) +VSX_IMPL_ST_DINTERLEAVE_32(int, vec_int4) +VSX_IMPL_ST_DINTERLEAVE_32(float, vec_float4) + +// 2 and 4 channels interleave and deinterleave for 2 lanes +#define VSX_IMPL_ST_D_INTERLEAVE_64(Tp, Tvec, ld_func, st_func) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, Tp* ptr) \ +{ \ + st_func(vec_mergeh(a, b), 0, ptr); \ + st_func(vec_mergel(a, b), 2, ptr); \ +} \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, const Tvec& d, Tp* ptr) \ +{ \ + st_func(vec_mergeh(a, b), 0, ptr); \ + st_func(vec_mergeh(c, d), 2, ptr); \ + st_func(vec_mergel(a, b), 4, ptr); \ + st_func(vec_mergel(c, d), 6, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + Tvec m0 = ld_func(0, ptr); \ + Tvec m1 = ld_func(2, ptr); \ + a = vec_mergeh(m0, m1); \ + b = vec_mergel(m0, m1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = ld_func(0, ptr); \ + Tvec v1 = ld_func(2, ptr); \ + Tvec v2 = ld_func(4, ptr); \ + Tvec v3 = ld_func(6, ptr); \ + a = vec_mergeh(v0, v2); \ + b = vec_mergel(v0, v2); \ + c = vec_mergeh(v1, v3); \ + d = vec_mergel(v1, v3); \ +} +VSX_IMPL_ST_D_INTERLEAVE_64(int64, vec_dword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_D_INTERLEAVE_64(uint64, vec_udword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_D_INTERLEAVE_64(double, vec_double2, vsx_ld, vsx_st) + +/* 3 channels */ +#define VSX_IMPL_ST_INTERLEAVE_3CH_16(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + static const vec_uchar16 a12 = {0, 16, 0, 1, 17, 0, 2, 18, 0, 3, 19, 0, 4, 20, 0, 5}; \ + static const vec_uchar16 a123 = {0, 1, 16, 3, 4, 17, 6, 7, 18, 9, 10, 19, 12, 13, 20, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, a12), c, a123), 0, ptr); \ + static const vec_uchar16 b12 = {21, 0, 6, 22, 0, 7, 23, 0, 8, 24, 0, 9, 25, 0, 10, 26}; \ + static const vec_uchar16 b123 = {0, 21, 2, 3, 22, 5, 6, 23, 8, 9, 24, 11, 12, 25, 14, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, b12), c, b123), 16, ptr); \ + static const vec_uchar16 c12 = {0, 11, 27, 0, 12, 28, 0, 13, 29, 0, 14, 30, 0, 15, 31, 0}; \ + static const vec_uchar16 c123 = {26, 1, 2, 27, 4, 5, 28, 7, 8, 29, 10, 11, 30, 13, 14, 31}; \ + vsx_st(vec_perm(vec_perm(a, b, c12), c, c123), 32, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = vsx_ld(0, ptr); \ + Tvec v2 = vsx_ld(16, ptr); \ + Tvec v3 = vsx_ld(32, ptr); \ + static const vec_uchar16 a12_perm = {0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 a123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 17, 20, 23, 26, 29}; \ + a = vec_perm(vec_perm(v1, v2, a12_perm), v3, a123_perm); \ + static const vec_uchar16 b12_perm = {1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 b123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 18, 21, 24, 27, 30}; \ + b = vec_perm(vec_perm(v1, v2, b12_perm), v3, b123_perm); \ + static const vec_uchar16 c12_perm = {2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 0, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 c123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 19, 22, 25, 28, 31}; \ + c = vec_perm(vec_perm(v1, v2, c12_perm), v3, c123_perm); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_16(uchar, vec_uchar16) +VSX_IMPL_ST_INTERLEAVE_3CH_16(schar, vec_char16) + +#define VSX_IMPL_ST_INTERLEAVE_3CH_8(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + static const vec_uchar16 a12 = {0, 1, 16, 17, 0, 0, 2, 3, 18, 19, 0, 0, 4, 5, 20, 21}; \ + static const vec_uchar16 a123 = {0, 1, 2, 3, 16, 17, 6, 7, 8, 9, 18, 19, 12, 13, 14, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, a12), c, a123), 0, ptr); \ + static const vec_uchar16 b12 = {0, 0, 6, 7, 22, 23, 0, 0, 8, 9, 24, 25, 0, 0, 10, 11}; \ + static const vec_uchar16 b123 = {20, 21, 2, 3, 4, 5, 22, 23, 8, 9, 10, 11, 24, 25, 14, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, b12), c, b123), 8, ptr); \ + static const vec_uchar16 c12 = {26, 27, 0, 0, 12, 13, 28, 29, 0, 0, 14, 15, 30, 31, 0, 0}; \ + static const vec_uchar16 c123 = {0, 1, 26, 27, 4, 5, 6, 7, 28, 29, 10, 11, 12, 13, 30, 31}; \ + vsx_st(vec_perm(vec_perm(a, b, c12), c, c123), 16, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = vsx_ld(0, ptr); \ + Tvec v2 = vsx_ld(8, ptr); \ + Tvec v3 = vsx_ld(16, ptr); \ + static const vec_uchar16 a12_perm = {0, 1, 6, 7, 12, 13, 18, 19, 24, 25, 30, 31, 0, 0, 0, 0}; \ + static const vec_uchar16 a123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, 21, 26, 27}; \ + a = vec_perm(vec_perm(v1, v2, a12_perm), v3, a123_perm); \ + static const vec_uchar16 b12_perm = {2, 3, 8, 9, 14, 15, 20, 21, 26, 27, 0, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 b123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 22, 23, 28, 29}; \ + b = vec_perm(vec_perm(v1, v2, b12_perm), v3, b123_perm); \ + static const vec_uchar16 c12_perm = {4, 5, 10, 11, 16, 17, 22, 23, 28, 29, 0, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 c123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 19, 24, 25, 30, 31}; \ + c = vec_perm(vec_perm(v1, v2, c12_perm), v3, c123_perm); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_8(ushort, vec_ushort8) +VSX_IMPL_ST_INTERLEAVE_3CH_8(short, vec_short8) + +#define VSX_IMPL_ST_INTERLEAVE_3CH_4(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + Tvec hbc = vec_mergeh(b, c); \ + static const vec_uchar16 ahbc = {0, 1, 2, 3, 16, 17, 18, 19, 20, 21, 22, 23, 4, 5, 6, 7}; \ + vsx_st(vec_perm(a, hbc, ahbc), 0, ptr); \ + Tvec lab = vec_mergel(a, b); \ + vsx_st(vec_sld(lab, hbc, 8), 4, ptr); \ + static const vec_uchar16 clab = {8, 9, 10, 11, 24, 25, 26, 27, 28, 29, 30, 31, 12, 13, 14, 15};\ + vsx_st(vec_perm(c, lab, clab), 8, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = vsx_ld(0, ptr); \ + Tvec v2 = vsx_ld(4, ptr); \ + Tvec v3 = vsx_ld(8, ptr); \ + static const vec_uchar16 flp = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 28, 29, 30, 31}; \ + a = vec_perm(v1, vec_sld(v3, v2, 8), flp); \ + static const vec_uchar16 flp2 = {28, 29, 30, 31, 0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19}; \ + b = vec_perm(v2, vec_sld(v1, v3, 8), flp2); \ + c = vec_perm(vec_sld(v2, v1, 8), v3, flp); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_4(uint, vec_uint4) +VSX_IMPL_ST_INTERLEAVE_3CH_4(int, vec_int4) +VSX_IMPL_ST_INTERLEAVE_3CH_4(float, vec_float4) + +#define VSX_IMPL_ST_INTERLEAVE_3CH_2(Tp, Tvec, ld_func, st_func) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + st_func(vec_mergeh(a, b), 0, ptr); \ + st_func(vec_permi(c, a, 1), 2, ptr); \ + st_func(vec_mergel(b, c), 4, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, \ + Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = ld_func(0, ptr); \ + Tvec v2 = ld_func(2, ptr); \ + Tvec v3 = ld_func(4, ptr); \ + a = vec_permi(v1, v2, 1); \ + b = vec_permi(v1, v3, 2); \ + c = vec_permi(v2, v3, 1); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_2(int64, vec_dword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_INTERLEAVE_3CH_2(uint64, vec_udword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_INTERLEAVE_3CH_2(double, vec_double2, vsx_ld, vsx_st) + +#endif // CV_VSX + +//! @} + +#endif // OPENCV_HAL_VSX_UTILS_HPP diff --git a/include/opencv2/core/wimage.hpp b/include/opencv2/core/wimage.hpp index ef9d398..c7b6efa 100644 --- a/include/opencv2/core/wimage.hpp +++ b/include/opencv2/core/wimage.hpp @@ -39,8 +39,8 @@ ///////////////////////////////////////////////////////////////////////////////// //M*/ -#ifndef __OPENCV_CORE_WIMAGE_HPP__ -#define __OPENCV_CORE_WIMAGE_HPP__ +#ifndef OPENCV_CORE_WIMAGE_HPP +#define OPENCV_CORE_WIMAGE_HPP #include "opencv2/core/core_c.h" @@ -289,7 +289,7 @@ protected: }; /** Image class which owns the data, so it can be allocated and is always -freed. It cannot be copied but can be explicity cloned. +freed. It cannot be copied but can be explicitly cloned. */ template class WImageBuffer : public WImage diff --git a/include/opencv2/cvconfig.h b/include/opencv2/cvconfig.h index 5fd0d3b..56b6237 100644 --- a/include/opencv2/cvconfig.h +++ b/include/opencv2/cvconfig.h @@ -1,5 +1,14 @@ +#ifndef OPENCV_CVCONFIG_H_INCLUDED +#define OPENCV_CVCONFIG_H_INCLUDED + /* OpenCV compiled as static or dynamic libs */ -/* #undef BUILD_SHARED_LIBS */ +#define BUILD_SHARED_LIBS + +/* OpenCV intrinsics optimized code */ +#define CV_ENABLE_INTRINSICS + +/* OpenCV additional optimized code */ +/* #undef CV_DISABLE_OPTIMIZATION */ /* Compile for 'real' NVIDIA GPU architectures */ #define CUDA_ARCH_BIN "" @@ -26,10 +35,10 @@ /* #undef HAVE_CARBON */ /* AMD's Basic Linear Algebra Subprograms Library*/ -#define HAVE_CLAMDBLAS +/* #undef HAVE_CLAMDBLAS */ /* AMD's OpenCL Fast Fourier Transform Library*/ -#define HAVE_CLAMDFFT +/* #undef HAVE_CLAMDFFT */ /* Clp support */ /* #undef HAVE_CLP */ @@ -40,13 +49,13 @@ /* C= */ /* #undef HAVE_CSTRIPES */ -/* NVidia Cuda Basic Linear Algebra Subprograms (BLAS) API*/ +/* NVIDIA CUDA Basic Linear Algebra Subprograms (BLAS) API*/ /* #undef HAVE_CUBLAS */ -/* NVidia Cuda Runtime API*/ +/* NVIDIA CUDA Runtime API*/ /* #undef HAVE_CUDA */ -/* NVidia Cuda Fast Fourier Transform (FFT) API*/ +/* NVIDIA CUDA Fast Fourier Transform (FFT) API*/ /* #undef HAVE_CUFFT */ /* IEEE1394 capturing support */ @@ -57,6 +66,7 @@ /* DirectX */ #define HAVE_DIRECTX +#define HAVE_DIRECTX_NV12 #define HAVE_D3D11 #define HAVE_D3D10 #define HAVE_D3D9 @@ -70,12 +80,6 @@ /* FFMpeg video library */ #define HAVE_FFMPEG -/* ffmpeg's libswscale */ -#define HAVE_FFMPEG_SWSCALE - -/* ffmpeg in Gentoo */ -#define HAVE_GENTOO_FFMPEG - /* Geospatial Data Abstraction Library */ /* #undef HAVE_GDAL */ @@ -88,18 +92,20 @@ /* GTK+ 2.x toolkit */ /* #undef HAVE_GTK */ +/* Halide support */ +/* #undef HAVE_HALIDE */ + /* Define to 1 if you have the header file. */ -/* #undef HAVE_INTTYPES_H */ +#define HAVE_INTTYPES_H 1 /* Intel Perceptual Computing SDK library */ /* #undef HAVE_INTELPERC */ /* Intel Integrated Performance Primitives */ #define HAVE_IPP -#define HAVE_IPP_ICV_ONLY - -/* Intel IPP Async */ -/* #undef HAVE_IPP_A */ +#define HAVE_IPP_ICV +#define HAVE_IPP_IW +#define HAVE_IPP_IW_LL /* JPEG-2000 codec */ #define HAVE_JASPER @@ -110,15 +116,21 @@ /* libpng/png.h needs to be included */ /* #undef HAVE_LIBPNG_PNG_H */ +/* GDCM DICOM codec */ +/* #undef HAVE_GDCM */ + /* V4L/V4L2 capturing support via libv4l */ /* #undef HAVE_LIBV4L */ /* Microsoft Media Foundation Capture library */ -/* #undef HAVE_MSMF */ +#define HAVE_MSMF -/* NVidia Video Decoding API*/ +/* NVIDIA Video Decoding API*/ /* #undef HAVE_NVCUVID */ +/* NVIDIA Video Encoding API*/ +/* #undef HAVE_NVCUVENC */ + /* OpenCL Support */ #define HAVE_OPENCL /* #undef HAVE_OPENCL_STATIC */ @@ -139,6 +151,12 @@ /* PNG codec */ #define HAVE_PNG +/* Posix threads (pthreads) */ +/* #undef HAVE_PTHREAD */ + +/* parallel_for with pthreads */ +/* #undef HAVE_PTHREADS_PF */ + /* Qt support */ /* #undef HAVE_QT */ @@ -161,7 +179,7 @@ /* #undef HAVE_UNICAP */ /* Video for Windows support */ -#define HAVE_VFW +/* #undef HAVE_VFW */ /* V4L2 capturing support in videoio.h */ /* #undef HAVE_VIDEOIO */ @@ -181,3 +199,50 @@ /* gPhoto2 library */ /* #undef HAVE_GPHOTO2 */ + +/* VA library (libva) */ +/* #undef HAVE_VA */ + +/* Intel VA-API/OpenCL */ +/* #undef HAVE_VA_INTEL */ + +/* Intel Media SDK */ +/* #undef HAVE_MFX */ + +/* Lapack */ +/* #undef HAVE_LAPACK */ + +/* Library was compiled with functions instrumentation */ +/* #undef ENABLE_INSTRUMENTATION */ + +/* OpenVX */ +/* #undef HAVE_OPENVX */ + +#if defined(HAVE_XINE) || \ + defined(HAVE_GSTREAMER) || \ + defined(HAVE_QUICKTIME) || \ + defined(HAVE_QTKIT) || \ + defined(HAVE_AVFOUNDATION) || \ + /*defined(HAVE_OPENNI) || too specialized */ \ + defined(HAVE_FFMPEG) || \ + defined(HAVE_MSMF) +#define HAVE_VIDEO_INPUT +#endif + +#if /*defined(HAVE_XINE) || */\ + defined(HAVE_GSTREAMER) || \ + defined(HAVE_QUICKTIME) || \ + defined(HAVE_QTKIT) || \ + defined(HAVE_AVFOUNDATION) || \ + defined(HAVE_FFMPEG) || \ + defined(HAVE_MSMF) +#define HAVE_VIDEO_OUTPUT +#endif + +/* OpenCV trace utilities */ +#define OPENCV_TRACE + +/* Library QR-code decoding */ +#define HAVE_QUIRC + +#endif // OPENCV_CVCONFIG_H_INCLUDED diff --git a/include/opencv2/dnn.hpp b/include/opencv2/dnn.hpp new file mode 100644 index 0000000..97f2fe3 --- /dev/null +++ b/include/opencv2/dnn.hpp @@ -0,0 +1,78 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_DNN_HPP +#define OPENCV_DNN_HPP + +// This is an umbrella header to include into you project. +// We are free to change headers layout in dnn subfolder, so please include +// this header for future compatibility + + +/** @defgroup dnn Deep Neural Network module + @{ + This module contains: + - API for new layers creation, layers are building bricks of neural networks; + - set of built-in most-useful Layers; + - API to construct and modify comprehensive neural networks from layers; + - functionality for loading serialized networks models from different frameworks. + + Functionality of this module is designed only for forward pass computations (i.e. network testing). + A network training is in principle not supported. + @} +*/ +/** @example samples/dnn/classification.cpp +Check @ref tutorial_dnn_googlenet "the corresponding tutorial" for more details +*/ +/** @example samples/dnn/colorization.cpp +*/ +/** @example samples/dnn/object_detection.cpp +Check @ref tutorial_dnn_yolo "the corresponding tutorial" for more details +*/ +/** @example samples/dnn/openpose.cpp +*/ +/** @example samples/dnn/segmentation.cpp +*/ +/** @example samples/dnn/text_detection.cpp +*/ +#include + +#endif /* OPENCV_DNN_HPP */ diff --git a/include/opencv2/dnn/all_layers.hpp b/include/opencv2/dnn/all_layers.hpp new file mode 100644 index 0000000..c6fe6d0 --- /dev/null +++ b/include/opencv2/dnn/all_layers.hpp @@ -0,0 +1,634 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_DNN_DNN_ALL_LAYERS_HPP +#define OPENCV_DNN_DNN_ALL_LAYERS_HPP +#include + +namespace cv { +namespace dnn { +CV__DNN_EXPERIMENTAL_NS_BEGIN +//! @addtogroup dnn +//! @{ + +/** @defgroup dnnLayerList Partial List of Implemented Layers + @{ + This subsection of dnn module contains information about built-in layers and their descriptions. + + Classes listed here, in fact, provides C++ API for creating instances of built-in layers. + In addition to this way of layers instantiation, there is a more common factory API (see @ref dnnLayerFactory), it allows to create layers dynamically (by name) and register new ones. + You can use both API, but factory API is less convenient for native C++ programming and basically designed for use inside importers (see @ref readNetFromCaffe(), @ref readNetFromTorch(), @ref readNetFromTensorflow()). + + Built-in layers partially reproduce functionality of corresponding Caffe and Torch7 layers. + In particular, the following layers and Caffe importer were tested to reproduce Caffe functionality: + - Convolution + - Deconvolution + - Pooling + - InnerProduct + - TanH, ReLU, Sigmoid, BNLL, Power, AbsVal + - Softmax + - Reshape, Flatten, Slice, Split + - LRN + - MVN + - Dropout (since it does nothing on forward pass -)) +*/ + + class CV_EXPORTS BlankLayer : public Layer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + /** + * Constant layer produces the same data blob at an every forward pass. + */ + class CV_EXPORTS ConstLayer : public Layer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + //! LSTM recurrent layer + class CV_EXPORTS LSTMLayer : public Layer + { + public: + /** Creates instance of LSTM layer */ + static Ptr create(const LayerParams& params); + + /** @deprecated Use LayerParams::blobs instead. + @brief Set trained weights for LSTM layer. + + LSTM behavior on each step is defined by current input, previous output, previous cell state and learned weights. + + Let @f$x_t@f$ be current input, @f$h_t@f$ be current output, @f$c_t@f$ be current state. + Than current output and current cell state is computed as follows: + @f{eqnarray*}{ + h_t &= o_t \odot tanh(c_t), \\ + c_t &= f_t \odot c_{t-1} + i_t \odot g_t, \\ + @f} + where @f$\odot@f$ is per-element multiply operation and @f$i_t, f_t, o_t, g_t@f$ is internal gates that are computed using learned wights. + + Gates are computed as follows: + @f{eqnarray*}{ + i_t &= sigmoid&(W_{xi} x_t + W_{hi} h_{t-1} + b_i), \\ + f_t &= sigmoid&(W_{xf} x_t + W_{hf} h_{t-1} + b_f), \\ + o_t &= sigmoid&(W_{xo} x_t + W_{ho} h_{t-1} + b_o), \\ + g_t &= tanh &(W_{xg} x_t + W_{hg} h_{t-1} + b_g), \\ + @f} + where @f$W_{x?}@f$, @f$W_{h?}@f$ and @f$b_{?}@f$ are learned weights represented as matrices: + @f$W_{x?} \in R^{N_h \times N_x}@f$, @f$W_{h?} \in R^{N_h \times N_h}@f$, @f$b_? \in R^{N_h}@f$. + + For simplicity and performance purposes we use @f$ W_x = [W_{xi}; W_{xf}; W_{xo}, W_{xg}] @f$ + (i.e. @f$W_x@f$ is vertical concatenation of @f$ W_{x?} @f$), @f$ W_x \in R^{4N_h \times N_x} @f$. + The same for @f$ W_h = [W_{hi}; W_{hf}; W_{ho}, W_{hg}], W_h \in R^{4N_h \times N_h} @f$ + and for @f$ b = [b_i; b_f, b_o, b_g]@f$, @f$b \in R^{4N_h} @f$. + + @param Wh is matrix defining how previous output is transformed to internal gates (i.e. according to above mentioned notation is @f$ W_h @f$) + @param Wx is matrix defining how current input is transformed to internal gates (i.e. according to above mentioned notation is @f$ W_x @f$) + @param b is bias vector (i.e. according to above mentioned notation is @f$ b @f$) + */ + CV_DEPRECATED virtual void setWeights(const Mat &Wh, const Mat &Wx, const Mat &b) = 0; + + /** @brief Specifies shape of output blob which will be [[`T`], `N`] + @p outTailShape. + * @details If this parameter is empty or unset then @p outTailShape = [`Wh`.size(0)] will be used, + * where `Wh` is parameter from setWeights(). + */ + virtual void setOutShape(const MatShape &outTailShape = MatShape()) = 0; + + /** @deprecated Use flag `produce_cell_output` in LayerParams. + * @brief Specifies either interpret first dimension of input blob as timestamp dimenion either as sample. + * + * If flag is set to true then shape of input blob will be interpreted as [`T`, `N`, `[data dims]`] where `T` specifies number of timestamps, `N` is number of independent streams. + * In this case each forward() call will iterate through `T` timestamps and update layer's state `T` times. + * + * If flag is set to false then shape of input blob will be interpreted as [`N`, `[data dims]`]. + * In this case each forward() call will make one iteration and produce one timestamp with shape [`N`, `[out dims]`]. + */ + CV_DEPRECATED virtual void setUseTimstampsDim(bool use = true) = 0; + + /** @deprecated Use flag `use_timestamp_dim` in LayerParams. + * @brief If this flag is set to true then layer will produce @f$ c_t @f$ as second output. + * @details Shape of the second output is the same as first output. + */ + CV_DEPRECATED virtual void setProduceCellOutput(bool produce = false) = 0; + + /* In common case it use single input with @f$x_t@f$ values to compute output(s) @f$h_t@f$ (and @f$c_t@f$). + * @param input should contain packed values @f$x_t@f$ + * @param output contains computed outputs: @f$h_t@f$ (and @f$c_t@f$ if setProduceCellOutput() flag was set to true). + * + * If setUseTimstampsDim() is set to true then @p input[0] should has at least two dimensions with the following shape: [`T`, `N`, `[data dims]`], + * where `T` specifies number of timestamps, `N` is number of independent streams (i.e. @f$ x_{t_0 + t}^{stream} @f$ is stored inside @p input[0][t, stream, ...]). + * + * If setUseTimstampsDim() is set to false then @p input[0] should contain single timestamp, its shape should has form [`N`, `[data dims]`] with at least one dimension. + * (i.e. @f$ x_{t}^{stream} @f$ is stored inside @p input[0][stream, ...]). + */ + + int inputNameToIndex(String inputName) CV_OVERRIDE; + int outputNameToIndex(const String& outputName) CV_OVERRIDE; + }; + + /** @brief Classical recurrent layer + + Accepts two inputs @f$x_t@f$ and @f$h_{t-1}@f$ and compute two outputs @f$o_t@f$ and @f$h_t@f$. + + - input: should contain packed input @f$x_t@f$. + - output: should contain output @f$o_t@f$ (and @f$h_t@f$ if setProduceHiddenOutput() is set to true). + + input[0] should have shape [`T`, `N`, `data_dims`] where `T` and `N` is number of timestamps and number of independent samples of @f$x_t@f$ respectively. + + output[0] will have shape [`T`, `N`, @f$N_o@f$], where @f$N_o@f$ is number of rows in @f$ W_{xo} @f$ matrix. + + If setProduceHiddenOutput() is set to true then @p output[1] will contain a Mat with shape [`T`, `N`, @f$N_h@f$], where @f$N_h@f$ is number of rows in @f$ W_{hh} @f$ matrix. + */ + class CV_EXPORTS RNNLayer : public Layer + { + public: + /** Creates instance of RNNLayer */ + static Ptr create(const LayerParams& params); + + /** Setups learned weights. + + Recurrent-layer behavior on each step is defined by current input @f$ x_t @f$, previous state @f$ h_t @f$ and learned weights as follows: + @f{eqnarray*}{ + h_t &= tanh&(W_{hh} h_{t-1} + W_{xh} x_t + b_h), \\ + o_t &= tanh&(W_{ho} h_t + b_o), + @f} + + @param Wxh is @f$ W_{xh} @f$ matrix + @param bh is @f$ b_{h} @f$ vector + @param Whh is @f$ W_{hh} @f$ matrix + @param Who is @f$ W_{xo} @f$ matrix + @param bo is @f$ b_{o} @f$ vector + */ + virtual void setWeights(const Mat &Wxh, const Mat &bh, const Mat &Whh, const Mat &Who, const Mat &bo) = 0; + + /** @brief If this flag is set to true then layer will produce @f$ h_t @f$ as second output. + * @details Shape of the second output is the same as first output. + */ + virtual void setProduceHiddenOutput(bool produce = false) = 0; + + }; + + class CV_EXPORTS BaseConvolutionLayer : public Layer + { + public: + Size kernel, stride, pad, dilation, adjustPad; + String padMode; + int numOutput; + }; + + class CV_EXPORTS ConvolutionLayer : public BaseConvolutionLayer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS DeconvolutionLayer : public BaseConvolutionLayer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS LRNLayer : public Layer + { + public: + int type; + + int size; + float alpha, beta, bias; + bool normBySize; + + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS PoolingLayer : public Layer + { + public: + int type; + Size kernel, stride; + int pad_l, pad_t, pad_r, pad_b; + CV_DEPRECATED_EXTERNAL Size pad; + bool globalPooling; + bool computeMaxIdx; + String padMode; + bool ceilMode; + // If true for average pooling with padding, divide an every output region + // by a whole kernel area. Otherwise exclude zero padded values and divide + // by number of real values. + bool avePoolPaddedArea; + // ROIPooling parameters. + Size pooledSize; + float spatialScale; + // PSROIPooling parameters. + int psRoiOutChannels; + + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS SoftmaxLayer : public Layer + { + public: + bool logSoftMax; + + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS InnerProductLayer : public Layer + { + public: + int axis; + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS MVNLayer : public Layer + { + public: + float eps; + bool normVariance, acrossChannels; + + static Ptr create(const LayerParams& params); + }; + + /* Reshaping */ + + class CV_EXPORTS ReshapeLayer : public Layer + { + public: + MatShape newShapeDesc; + Range newShapeRange; + + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS FlattenLayer : public Layer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS ConcatLayer : public Layer + { + public: + int axis; + /** + * @brief Add zero padding in case of concatenation of blobs with different + * spatial sizes. + * + * Details: https://github.com/torch/nn/blob/master/doc/containers.md#depthconcat + */ + bool padding; + + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS SplitLayer : public Layer + { + public: + int outputsCount; //!< Number of copies that will be produced (is ignored when negative). + + static Ptr create(const LayerParams ¶ms); + }; + + /** + * Slice layer has several modes: + * 1. Caffe mode + * @param[in] axis Axis of split operation + * @param[in] slice_point Array of split points + * + * Number of output blobs equals to number of split points plus one. The + * first blob is a slice on input from 0 to @p slice_point[0] - 1 by @p axis, + * the second output blob is a slice of input from @p slice_point[0] to + * @p slice_point[1] - 1 by @p axis and the last output blob is a slice of + * input from @p slice_point[-1] up to the end of @p axis size. + * + * 2. TensorFlow mode + * @param begin Vector of start indices + * @param size Vector of sizes + * + * More convenient numpy-like slice. One and only output blob + * is a slice `input[begin[0]:begin[0]+size[0], begin[1]:begin[1]+size[1], ...]` + * + * 3. Torch mode + * @param axis Axis of split operation + * + * Split input blob on the equal parts by @p axis. + */ + class CV_EXPORTS SliceLayer : public Layer + { + public: + /** + * @brief Vector of slice ranges. + * + * The first dimension equals number of output blobs. + * Inner vector has slice ranges for the first number of input dimensions. + */ + std::vector > sliceRanges; + int axis; + + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS PermuteLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + /** + * Permute channels of 4-dimensional input blob. + * @param group Number of groups to split input channels and pick in turns + * into output blob. + * + * \f[ groupSize = \frac{number\ of\ channels}{group} \f] + * \f[ output(n, c, h, w) = input(n, groupSize \times (c \% group) + \lfloor \frac{c}{group} \rfloor, h, w) \f] + * Read more at https://arxiv.org/pdf/1707.01083.pdf + */ + class CV_EXPORTS ShuffleChannelLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + + int group; + }; + + /** + * @brief Adds extra values for specific axes. + * @param paddings Vector of paddings in format + * @code + * [ pad_before, pad_after, // [0]th dimension + * pad_before, pad_after, // [1]st dimension + * ... + * pad_before, pad_after ] // [n]th dimension + * @endcode + * that represents number of padded values at every dimension + * starting from the first one. The rest of dimensions won't + * be padded. + * @param value Value to be padded. Defaults to zero. + * @param type Padding type: 'constant', 'reflect' + * @param input_dims Torch's parameter. If @p input_dims is not equal to the + * actual input dimensionality then the `[0]th` dimension + * is considered as a batch dimension and @p paddings are shifted + * to a one dimension. Defaults to `-1` that means padding + * corresponding to @p paddings. + */ + class CV_EXPORTS PaddingLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + /* Activations */ + class CV_EXPORTS ActivationLayer : public Layer + { + public: + virtual void forwardSlice(const float* src, float* dst, int len, + size_t outPlaneSize, int cn0, int cn1) const = 0; + }; + + class CV_EXPORTS ReLULayer : public ActivationLayer + { + public: + float negativeSlope; + + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS ReLU6Layer : public ActivationLayer + { + public: + float minValue, maxValue; + + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS ChannelsPReLULayer : public ActivationLayer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS ELULayer : public ActivationLayer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS TanHLayer : public ActivationLayer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS SigmoidLayer : public ActivationLayer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS BNLLLayer : public ActivationLayer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS AbsLayer : public ActivationLayer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS PowerLayer : public ActivationLayer + { + public: + float power, scale, shift; + + static Ptr create(const LayerParams ¶ms); + }; + + /* Layers used in semantic segmentation */ + + class CV_EXPORTS CropLayer : public Layer + { + public: + int startAxis; + std::vector offset; + + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS EltwiseLayer : public Layer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS BatchNormLayer : public ActivationLayer + { + public: + bool hasWeights, hasBias; + float epsilon; + + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS MaxUnpoolLayer : public Layer + { + public: + Size poolKernel; + Size poolPad; + Size poolStride; + + static Ptr create(const LayerParams ¶ms); + }; + + class CV_EXPORTS ScaleLayer : public Layer + { + public: + bool hasBias; + int axis; + + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS ShiftLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS PriorBoxLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS ReorgLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS RegionLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS DetectionOutputLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + /** + * @brief \f$ L_p \f$ - normalization layer. + * @param p Normalization factor. The most common `p = 1` for \f$ L_1 \f$ - + * normalization or `p = 2` for \f$ L_2 \f$ - normalization or a custom one. + * @param eps Parameter \f$ \epsilon \f$ to prevent a division by zero. + * @param across_spatial If true, normalize an input across all non-batch dimensions. + * Otherwise normalize an every channel separately. + * + * Across spatial: + * @f[ + * norm = \sqrt[p]{\epsilon + \sum_{x, y, c} |src(x, y, c)|^p } \\ + * dst(x, y, c) = \frac{ src(x, y, c) }{norm} + * @f] + * + * Channel wise normalization: + * @f[ + * norm(c) = \sqrt[p]{\epsilon + \sum_{x, y} |src(x, y, c)|^p } \\ + * dst(x, y, c) = \frac{ src(x, y, c) }{norm(c)} + * @f] + * + * Where `x, y` - spatial coordinates, `c` - channel. + * + * An every sample in the batch is normalized separately. Optionally, + * output is scaled by the trained parameters. + */ + class CV_EXPORTS NormalizeBBoxLayer : public Layer + { + public: + float pnorm, epsilon; + CV_DEPRECATED_EXTERNAL bool acrossSpatial; + + static Ptr create(const LayerParams& params); + }; + + /** + * @brief Resize input 4-dimensional blob by nearest neighbor or bilinear strategy. + * + * Layer is used to support TensorFlow's resize_nearest_neighbor and resize_bilinear ops. + */ + class CV_EXPORTS ResizeLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + /** + * @brief Bilinear resize layer from https://github.com/cdmh/deeplab-public + * + * It differs from @ref ResizeLayer in output shape and resize scales computations. + */ + class CV_EXPORTS InterpLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS ProposalLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + + class CV_EXPORTS CropAndResizeLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + +//! @} +//! @} +CV__DNN_EXPERIMENTAL_NS_END +} +} +#endif diff --git a/include/opencv2/dnn/dict.hpp b/include/opencv2/dnn/dict.hpp new file mode 100644 index 0000000..60c2aa5 --- /dev/null +++ b/include/opencv2/dnn/dict.hpp @@ -0,0 +1,160 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include +#include +#include + +#include + +#ifndef OPENCV_DNN_DNN_DICT_HPP +#define OPENCV_DNN_DNN_DICT_HPP + +namespace cv { +namespace dnn { +CV__DNN_EXPERIMENTAL_NS_BEGIN +//! @addtogroup dnn +//! @{ + +/** @brief This struct stores the scalar value (or array) of one of the following type: double, cv::String or int64. + * @todo Maybe int64 is useless because double type exactly stores at least 2^52 integers. + */ +struct CV_EXPORTS_W DictValue +{ + DictValue(const DictValue &r); + DictValue(bool i) : type(Param::INT), pi(new AutoBuffer) { (*pi)[0] = i ? 1 : 0; } //!< Constructs integer scalar + DictValue(int64 i = 0) : type(Param::INT), pi(new AutoBuffer) { (*pi)[0] = i; } //!< Constructs integer scalar + CV_WRAP DictValue(int i) : type(Param::INT), pi(new AutoBuffer) { (*pi)[0] = i; } //!< Constructs integer scalar + DictValue(unsigned p) : type(Param::INT), pi(new AutoBuffer) { (*pi)[0] = p; } //!< Constructs integer scalar + CV_WRAP DictValue(double p) : type(Param::REAL), pd(new AutoBuffer) { (*pd)[0] = p; } //!< Constructs floating point scalar + CV_WRAP DictValue(const String &s) : type(Param::STRING), ps(new AutoBuffer) { (*ps)[0] = s; } //!< Constructs string scalar + DictValue(const char *s) : type(Param::STRING), ps(new AutoBuffer) { (*ps)[0] = s; } //!< @overload + + template + static DictValue arrayInt(TypeIter begin, int size); //!< Constructs integer array + template + static DictValue arrayReal(TypeIter begin, int size); //!< Constructs floating point array + template + static DictValue arrayString(TypeIter begin, int size); //!< Constructs array of strings + + template + T get(int idx = -1) const; //!< Tries to convert array element with specified index to requested type and returns its. + + int size() const; + + CV_WRAP bool isInt() const; + CV_WRAP bool isString() const; + CV_WRAP bool isReal() const; + + CV_WRAP int getIntValue(int idx = -1) const; + CV_WRAP double getRealValue(int idx = -1) const; + CV_WRAP String getStringValue(int idx = -1) const; + + DictValue &operator=(const DictValue &r); + + friend std::ostream &operator<<(std::ostream &stream, const DictValue &dictv); + + ~DictValue(); + +private: + + int type; + + union + { + AutoBuffer *pi; + AutoBuffer *pd; + AutoBuffer *ps; + void *pv; + }; + + DictValue(int _type, void *_p) : type(_type), pv(_p) {} + void release(); +}; + +/** @brief This class implements name-value dictionary, values are instances of DictValue. */ +class CV_EXPORTS Dict +{ + typedef std::map _Dict; + _Dict dict; + +public: + + //! Checks a presence of the @p key in the dictionary. + bool has(const String &key) const; + + //! If the @p key in the dictionary then returns pointer to its value, else returns NULL. + DictValue *ptr(const String &key); + + /** @overload */ + const DictValue *ptr(const String &key) const; + + //! If the @p key in the dictionary then returns its value, else an error will be generated. + const DictValue &get(const String &key) const; + + /** @overload */ + template + T get(const String &key) const; + + //! If the @p key in the dictionary then returns its value, else returns @p defaultValue. + template + T get(const String &key, const T &defaultValue) const; + + //! Sets new @p value for the @p key, or adds new key-value pair into the dictionary. + template + const T &set(const String &key, const T &value); + + //! Erase @p key from the dictionary. + void erase(const String &key); + + friend std::ostream &operator<<(std::ostream &stream, const Dict &dict); + + std::map::const_iterator begin() const; + + std::map::const_iterator end() const; +}; + +//! @} +CV__DNN_EXPERIMENTAL_NS_END +} +} + +#endif diff --git a/include/opencv2/dnn/dnn.hpp b/include/opencv2/dnn/dnn.hpp new file mode 100644 index 0000000..c0e84b8 --- /dev/null +++ b/include/opencv2/dnn/dnn.hpp @@ -0,0 +1,977 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_DNN_DNN_HPP +#define OPENCV_DNN_DNN_HPP + +#include +#include + +#if !defined CV_DOXYGEN && !defined CV_DNN_DONT_ADD_EXPERIMENTAL_NS +#define CV__DNN_EXPERIMENTAL_NS_BEGIN namespace experimental_dnn_34_v11 { +#define CV__DNN_EXPERIMENTAL_NS_END } +namespace cv { namespace dnn { namespace experimental_dnn_34_v11 { } using namespace experimental_dnn_34_v11; }} +#else +#define CV__DNN_EXPERIMENTAL_NS_BEGIN +#define CV__DNN_EXPERIMENTAL_NS_END +#endif + +#include + +namespace cv { +namespace dnn { +CV__DNN_EXPERIMENTAL_NS_BEGIN +//! @addtogroup dnn +//! @{ + + typedef std::vector MatShape; + + /** + * @brief Enum of computation backends supported by layers. + * @see Net::setPreferableBackend + */ + enum Backend + { + //! DNN_BACKEND_DEFAULT equals to DNN_BACKEND_INFERENCE_ENGINE if + //! OpenCV is built with Intel's Inference Engine library or + //! DNN_BACKEND_OPENCV otherwise. + DNN_BACKEND_DEFAULT, + DNN_BACKEND_HALIDE, + DNN_BACKEND_INFERENCE_ENGINE, + DNN_BACKEND_OPENCV + }; + + /** + * @brief Enum of target devices for computations. + * @see Net::setPreferableTarget + */ + enum Target + { + DNN_TARGET_CPU, + DNN_TARGET_OPENCL, + DNN_TARGET_OPENCL_FP16, + DNN_TARGET_MYRIAD, + //! FPGA device with CPU fallbacks using Inference Engine's Heterogeneous plugin. + DNN_TARGET_FPGA + }; + + CV_EXPORTS std::vector< std::pair > getAvailableBackends(); + CV_EXPORTS std::vector getAvailableTargets(Backend be); + + /** @brief This class provides all data needed to initialize layer. + * + * It includes dictionary with scalar params (which can be read by using Dict interface), + * blob params #blobs and optional meta information: #name and #type of layer instance. + */ + class CV_EXPORTS LayerParams : public Dict + { + public: + //TODO: Add ability to name blob params + std::vector blobs; //!< List of learned parameters stored as blobs. + + String name; //!< Name of the layer instance (optional, can be used internal purposes). + String type; //!< Type name which was used for creating layer by layer factory (optional). + }; + + /** + * @brief Derivatives of this class encapsulates functions of certain backends. + */ + class BackendNode + { + public: + BackendNode(int backendId); + + virtual ~BackendNode(); //!< Virtual destructor to make polymorphism. + + int backendId; //!< Backend identifier. + }; + + /** + * @brief Derivatives of this class wraps cv::Mat for different backends and targets. + */ + class BackendWrapper + { + public: + BackendWrapper(int backendId, int targetId); + + /** + * @brief Wrap cv::Mat for specific backend and target. + * @param[in] targetId Target identifier. + * @param[in] m cv::Mat for wrapping. + * + * Make CPU->GPU data transfer if it's require for the target. + */ + BackendWrapper(int targetId, const cv::Mat& m); + + /** + * @brief Make wrapper for reused cv::Mat. + * @param[in] base Wrapper of cv::Mat that will be reused. + * @param[in] shape Specific shape. + * + * Initialize wrapper from another one. It'll wrap the same host CPU + * memory and mustn't allocate memory on device(i.e. GPU). It might + * has different shape. Use in case of CPU memory reusing for reuse + * associated memory on device too. + */ + BackendWrapper(const Ptr& base, const MatShape& shape); + + virtual ~BackendWrapper(); //!< Virtual destructor to make polymorphism. + + /** + * @brief Transfer data to CPU host memory. + */ + virtual void copyToHost() = 0; + + /** + * @brief Indicate that an actual data is on CPU. + */ + virtual void setHostDirty() = 0; + + int backendId; //!< Backend identifier. + int targetId; //!< Target identifier. + }; + + class CV_EXPORTS ActivationLayer; + + /** @brief This interface class allows to build new Layers - are building blocks of networks. + * + * Each class, derived from Layer, must implement allocate() methods to declare own outputs and forward() to compute outputs. + * Also before using the new layer into networks you must register your layer by using one of @ref dnnLayerFactory "LayerFactory" macros. + */ + class CV_EXPORTS_W Layer : public Algorithm + { + public: + + //! List of learned parameters must be stored here to allow read them by using Net::getParam(). + CV_PROP_RW std::vector blobs; + + /** @brief Computes and sets internal parameters according to inputs, outputs and blobs. + * @deprecated Use Layer::finalize(InputArrayOfArrays, OutputArrayOfArrays) instead + * @param[in] input vector of already allocated input blobs + * @param[out] output vector of already allocated output blobs + * + * If this method is called after network has allocated all memory for input and output blobs + * and before inferencing. + */ + CV_DEPRECATED_EXTERNAL + virtual void finalize(const std::vector &input, std::vector &output); + + /** @brief Computes and sets internal parameters according to inputs, outputs and blobs. + * @param[in] inputs vector of already allocated input blobs + * @param[out] outputs vector of already allocated output blobs + * + * If this method is called after network has allocated all memory for input and output blobs + * and before inferencing. + */ + CV_WRAP virtual void finalize(InputArrayOfArrays inputs, OutputArrayOfArrays outputs); + + /** @brief Given the @p input blobs, computes the output @p blobs. + * @deprecated Use Layer::forward(InputArrayOfArrays, OutputArrayOfArrays, OutputArrayOfArrays) instead + * @param[in] input the input blobs. + * @param[out] output allocated output blobs, which will store results of the computation. + * @param[out] internals allocated internal blobs + */ + CV_DEPRECATED_EXTERNAL + virtual void forward(std::vector &input, std::vector &output, std::vector &internals); + + /** @brief Given the @p input blobs, computes the output @p blobs. + * @param[in] inputs the input blobs. + * @param[out] outputs allocated output blobs, which will store results of the computation. + * @param[out] internals allocated internal blobs + */ + virtual void forward(InputArrayOfArrays inputs, OutputArrayOfArrays outputs, OutputArrayOfArrays internals); + + /** @brief Given the @p input blobs, computes the output @p blobs. + * @param[in] inputs the input blobs. + * @param[out] outputs allocated output blobs, which will store results of the computation. + * @param[out] internals allocated internal blobs + */ + void forward_fallback(InputArrayOfArrays inputs, OutputArrayOfArrays outputs, OutputArrayOfArrays internals); + + /** @brief + * @overload + * @deprecated Use Layer::finalize(InputArrayOfArrays, OutputArrayOfArrays) instead + */ + CV_DEPRECATED_EXTERNAL + void finalize(const std::vector &inputs, CV_OUT std::vector &outputs); + + /** @brief + * @overload + * @deprecated Use Layer::finalize(InputArrayOfArrays, OutputArrayOfArrays) instead + */ + CV_DEPRECATED std::vector finalize(const std::vector &inputs); + + /** @brief Allocates layer and computes output. + * @deprecated This method will be removed in the future release. + */ + CV_DEPRECATED CV_WRAP void run(const std::vector &inputs, CV_OUT std::vector &outputs, + CV_IN_OUT std::vector &internals); + + /** @brief Returns index of input blob into the input array. + * @param inputName label of input blob + * + * Each layer input and output can be labeled to easily identify them using "%[.output_name]" notation. + * This method maps label of input blob to its index into input vector. + */ + virtual int inputNameToIndex(String inputName); + /** @brief Returns index of output blob in output array. + * @see inputNameToIndex() + */ + CV_WRAP virtual int outputNameToIndex(const String& outputName); + + /** + * @brief Ask layer if it support specific backend for doing computations. + * @param[in] backendId computation backend identifier. + * @see Backend + */ + virtual bool supportBackend(int backendId); + + /** + * @brief Returns Halide backend node. + * @param[in] inputs Input Halide buffers. + * @see BackendNode, BackendWrapper + * + * Input buffers should be exactly the same that will be used in forward invocations. + * Despite we can use Halide::ImageParam based on input shape only, + * it helps prevent some memory management issues (if something wrong, + * Halide tests will be failed). + */ + virtual Ptr initHalide(const std::vector > &inputs); + + virtual Ptr initInfEngine(const std::vector > &inputs); + + /** + * @brief Automatic Halide scheduling based on layer hyper-parameters. + * @param[in] node Backend node with Halide functions. + * @param[in] inputs Blobs that will be used in forward invocations. + * @param[in] outputs Blobs that will be used in forward invocations. + * @param[in] targetId Target identifier + * @see BackendNode, Target + * + * Layer don't use own Halide::Func members because we can have applied + * layers fusing. In this way the fused function should be scheduled. + */ + virtual void applyHalideScheduler(Ptr& node, + const std::vector &inputs, + const std::vector &outputs, + int targetId) const; + + /** + * @brief Implement layers fusing. + * @param[in] node Backend node of bottom layer. + * @see BackendNode + * + * Actual for graph-based backends. If layer attached successfully, + * returns non-empty cv::Ptr to node of the same backend. + * Fuse only over the last function. + */ + virtual Ptr tryAttach(const Ptr& node); + + /** + * @brief Tries to attach to the layer the subsequent activation layer, i.e. do the layer fusion in a partial case. + * @param[in] layer The subsequent activation layer. + * + * Returns true if the activation layer has been attached successfully. + */ + virtual bool setActivation(const Ptr& layer); + + /** + * @brief Try to fuse current layer with a next one + * @param[in] top Next layer to be fused. + * @returns True if fusion was performed. + */ + virtual bool tryFuse(Ptr& top); + + /** + * @brief Returns parameters of layers with channel-wise multiplication and addition. + * @param[out] scale Channel-wise multipliers. Total number of values should + * be equal to number of channels. + * @param[out] shift Channel-wise offsets. Total number of values should + * be equal to number of channels. + * + * Some layers can fuse their transformations with further layers. + * In example, convolution + batch normalization. This way base layer + * use weights from layer after it. Fused layer is skipped. + * By default, @p scale and @p shift are empty that means layer has no + * element-wise multiplications or additions. + */ + virtual void getScaleShift(Mat& scale, Mat& shift) const; + + /** + * @brief "Deattaches" all the layers, attached to particular layer. + */ + virtual void unsetAttached(); + + virtual bool getMemoryShapes(const std::vector &inputs, + const int requiredOutputs, + std::vector &outputs, + std::vector &internals) const; + virtual int64 getFLOPS(const std::vector &inputs, + const std::vector &outputs) const {CV_UNUSED(inputs); CV_UNUSED(outputs); return 0;} + + CV_PROP String name; //!< Name of the layer instance, can be used for logging or other internal purposes. + CV_PROP String type; //!< Type name which was used for creating layer by layer factory. + CV_PROP int preferableTarget; //!< prefer target for layer forwarding + + Layer(); + explicit Layer(const LayerParams ¶ms); //!< Initializes only #name, #type and #blobs fields. + void setParamsFrom(const LayerParams ¶ms); //!< Initializes only #name, #type and #blobs fields. + virtual ~Layer(); + }; + + /** @brief This class allows to create and manipulate comprehensive artificial neural networks. + * + * Neural network is presented as directed acyclic graph (DAG), where vertices are Layer instances, + * and edges specify relationships between layers inputs and outputs. + * + * Each network layer has unique integer id and unique string name inside its network. + * LayerId can store either layer name or layer id. + * + * This class supports reference counting of its instances, i. e. copies point to the same instance. + */ + class CV_EXPORTS_W_SIMPLE Net + { + public: + + CV_WRAP Net(); //!< Default constructor. + CV_WRAP ~Net(); //!< Destructor frees the net only if there aren't references to the net anymore. + + /** @brief Create a network from Intel's Model Optimizer intermediate representation. + * @param[in] xml XML configuration file with network's topology. + * @param[in] bin Binary file with trained weights. + * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine + * backend. + */ + CV_WRAP static Net readFromModelOptimizer(const String& xml, const String& bin); + + /** Returns true if there are no layers in the network. */ + CV_WRAP bool empty() const; + + /** @brief Adds new layer to the net. + * @param name unique name of the adding layer. + * @param type typename of the adding layer (type must be registered in LayerRegister). + * @param params parameters which will be used to initialize the creating layer. + * @returns unique identifier of created layer, or -1 if a failure will happen. + */ + int addLayer(const String &name, const String &type, LayerParams ¶ms); + /** @brief Adds new layer and connects its first input to the first output of previously added layer. + * @see addLayer() + */ + int addLayerToPrev(const String &name, const String &type, LayerParams ¶ms); + + /** @brief Converts string name of the layer to the integer identifier. + * @returns id of the layer, or -1 if the layer wasn't found. + */ + CV_WRAP int getLayerId(const String &layer); + + CV_WRAP std::vector getLayerNames() const; + + /** @brief Container for strings and integers. */ + typedef DictValue LayerId; + + /** @brief Returns pointer to layer with specified id or name which the network use. */ + CV_WRAP Ptr getLayer(LayerId layerId); + + /** @brief Returns pointers to input layers of specific layer. */ + std::vector > getLayerInputs(LayerId layerId); // FIXIT: CV_WRAP + + /** @brief Connects output of the first layer to input of the second layer. + * @param outPin descriptor of the first layer output. + * @param inpPin descriptor of the second layer input. + * + * Descriptors have the following template <layer_name>[.input_number]: + * - the first part of the template layer_name is sting name of the added layer. + * If this part is empty then the network input pseudo layer will be used; + * - the second optional part of the template input_number + * is either number of the layer input, either label one. + * If this part is omitted then the first layer input will be used. + * + * @see setNetInputs(), Layer::inputNameToIndex(), Layer::outputNameToIndex() + */ + CV_WRAP void connect(String outPin, String inpPin); + + /** @brief Connects #@p outNum output of the first layer to #@p inNum input of the second layer. + * @param outLayerId identifier of the first layer + * @param outNum number of the first layer output + * @param inpLayerId identifier of the second layer + * @param inpNum number of the second layer input + */ + void connect(int outLayerId, int outNum, int inpLayerId, int inpNum); + + /** @brief Sets outputs names of the network input pseudo layer. + * + * Each net always has special own the network input pseudo layer with id=0. + * This layer stores the user blobs only and don't make any computations. + * In fact, this layer provides the only way to pass user data into the network. + * As any other layer, this layer can label its outputs and this function provides an easy way to do this. + */ + CV_WRAP void setInputsNames(const std::vector &inputBlobNames); + + /** @brief Runs forward pass to compute output of layer with name @p outputName. + * @param outputName name for layer which output is needed to get + * @return blob for first output of specified layer. + * @details By default runs forward pass for the whole network. + */ + CV_WRAP Mat forward(const String& outputName = String()); + + /** @brief Runs forward pass to compute output of layer with name @p outputName. + * @param outputBlobs contains all output blobs for specified layer. + * @param outputName name for layer which output is needed to get + * @details If @p outputName is empty, runs forward pass for the whole network. + */ + CV_WRAP void forward(OutputArrayOfArrays outputBlobs, const String& outputName = String()); + + /** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames. + * @param outputBlobs contains blobs for first outputs of specified layers. + * @param outBlobNames names for layers which outputs are needed to get + */ + CV_WRAP void forward(OutputArrayOfArrays outputBlobs, + const std::vector& outBlobNames); + + /** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames. + * @param outputBlobs contains all output blobs for each layer specified in @p outBlobNames. + * @param outBlobNames names for layers which outputs are needed to get + */ + CV_WRAP_AS(forwardAndRetrieve) void forward(CV_OUT std::vector >& outputBlobs, + const std::vector& outBlobNames); + + /** + * @brief Compile Halide layers. + * @param[in] scheduler Path to YAML file with scheduling directives. + * @see setPreferableBackend + * + * Schedule layers that support Halide backend. Then compile them for + * specific target. For layers that not represented in scheduling file + * or if no manual scheduling used at all, automatic scheduling will be applied. + */ + CV_WRAP void setHalideScheduler(const String& scheduler); + + /** + * @brief Ask network to use specific computation backend where it supported. + * @param[in] backendId backend identifier. + * @see Backend + * + * If OpenCV is compiled with Intel's Inference Engine library, DNN_BACKEND_DEFAULT + * means DNN_BACKEND_INFERENCE_ENGINE. Otherwise it equals to DNN_BACKEND_OPENCV. + */ + CV_WRAP void setPreferableBackend(int backendId); + + /** + * @brief Ask network to make computations on specific target device. + * @param[in] targetId target identifier. + * @see Target + * + * List of supported combinations backend / target: + * | | DNN_BACKEND_OPENCV | DNN_BACKEND_INFERENCE_ENGINE | DNN_BACKEND_HALIDE | + * |------------------------|--------------------|------------------------------|--------------------| + * | DNN_TARGET_CPU | + | + | + | + * | DNN_TARGET_OPENCL | + | + | + | + * | DNN_TARGET_OPENCL_FP16 | + | + | | + * | DNN_TARGET_MYRIAD | | + | | + * | DNN_TARGET_FPGA | | + | | + */ + CV_WRAP void setPreferableTarget(int targetId); + + /** @brief Sets the new input value for the network + * @param blob A new blob. Should have CV_32F or CV_8U depth. + * @param name A name of input layer. + * @param scalefactor An optional normalization scale. + * @param mean An optional mean subtraction values. + * @see connect(String, String) to know format of the descriptor. + * + * If scale or mean values are specified, a final input blob is computed + * as: + * \f[input(n,c,h,w) = scalefactor \times (blob(n,c,h,w) - mean_c)\f] + */ + CV_WRAP void setInput(InputArray blob, const String& name = "", + double scalefactor = 1.0, const Scalar& mean = Scalar()); + + /** @brief Sets the new value for the learned param of the layer. + * @param layer name or id of the layer. + * @param numParam index of the layer parameter in the Layer::blobs array. + * @param blob the new value. + * @see Layer::blobs + * @note If shape of the new blob differs from the previous shape, + * then the following forward pass may fail. + */ + CV_WRAP void setParam(LayerId layer, int numParam, const Mat &blob); + + /** @brief Returns parameter blob of the layer. + * @param layer name or id of the layer. + * @param numParam index of the layer parameter in the Layer::blobs array. + * @see Layer::blobs + */ + CV_WRAP Mat getParam(LayerId layer, int numParam = 0); + + /** @brief Returns indexes of layers with unconnected outputs. + */ + CV_WRAP std::vector getUnconnectedOutLayers() const; + + /** @brief Returns names of layers with unconnected outputs. + */ + CV_WRAP std::vector getUnconnectedOutLayersNames() const; + + /** @brief Returns input and output shapes for all layers in loaded model; + * preliminary inferencing isn't necessary. + * @param netInputShapes shapes for all input blobs in net input layer. + * @param layersIds output parameter for layer IDs. + * @param inLayersShapes output parameter for input layers shapes; + * order is the same as in layersIds + * @param outLayersShapes output parameter for output layers shapes; + * order is the same as in layersIds + */ + CV_WRAP void getLayersShapes(const std::vector& netInputShapes, + CV_OUT std::vector& layersIds, + CV_OUT std::vector >& inLayersShapes, + CV_OUT std::vector >& outLayersShapes) const; + + /** @overload */ + CV_WRAP void getLayersShapes(const MatShape& netInputShape, + CV_OUT std::vector& layersIds, + CV_OUT std::vector >& inLayersShapes, + CV_OUT std::vector >& outLayersShapes) const; + + /** @brief Returns input and output shapes for layer with specified + * id in loaded model; preliminary inferencing isn't necessary. + * @param netInputShape shape input blob in net input layer. + * @param layerId id for layer. + * @param inLayerShapes output parameter for input layers shapes; + * order is the same as in layersIds + * @param outLayerShapes output parameter for output layers shapes; + * order is the same as in layersIds + */ + void getLayerShapes(const MatShape& netInputShape, + const int layerId, + CV_OUT std::vector& inLayerShapes, + CV_OUT std::vector& outLayerShapes) const; // FIXIT: CV_WRAP + + /** @overload */ + void getLayerShapes(const std::vector& netInputShapes, + const int layerId, + CV_OUT std::vector& inLayerShapes, + CV_OUT std::vector& outLayerShapes) const; // FIXIT: CV_WRAP + + /** @brief Computes FLOP for whole loaded model with specified input shapes. + * @param netInputShapes vector of shapes for all net inputs. + * @returns computed FLOP. + */ + CV_WRAP int64 getFLOPS(const std::vector& netInputShapes) const; + /** @overload */ + CV_WRAP int64 getFLOPS(const MatShape& netInputShape) const; + /** @overload */ + CV_WRAP int64 getFLOPS(const int layerId, + const std::vector& netInputShapes) const; + /** @overload */ + CV_WRAP int64 getFLOPS(const int layerId, + const MatShape& netInputShape) const; + + /** @brief Returns list of types for layer used in model. + * @param layersTypes output parameter for returning types. + */ + CV_WRAP void getLayerTypes(CV_OUT std::vector& layersTypes) const; + + /** @brief Returns count of layers of specified type. + * @param layerType type. + * @returns count of layers + */ + CV_WRAP int getLayersCount(const String& layerType) const; + + /** @brief Computes bytes number which are required to store + * all weights and intermediate blobs for model. + * @param netInputShapes vector of shapes for all net inputs. + * @param weights output parameter to store resulting bytes for weights. + * @param blobs output parameter to store resulting bytes for intermediate blobs. + */ + void getMemoryConsumption(const std::vector& netInputShapes, + CV_OUT size_t& weights, CV_OUT size_t& blobs) const; // FIXIT: CV_WRAP + /** @overload */ + CV_WRAP void getMemoryConsumption(const MatShape& netInputShape, + CV_OUT size_t& weights, CV_OUT size_t& blobs) const; + /** @overload */ + CV_WRAP void getMemoryConsumption(const int layerId, + const std::vector& netInputShapes, + CV_OUT size_t& weights, CV_OUT size_t& blobs) const; + /** @overload */ + CV_WRAP void getMemoryConsumption(const int layerId, + const MatShape& netInputShape, + CV_OUT size_t& weights, CV_OUT size_t& blobs) const; + + /** @brief Computes bytes number which are required to store + * all weights and intermediate blobs for each layer. + * @param netInputShapes vector of shapes for all net inputs. + * @param layerIds output vector to save layer IDs. + * @param weights output parameter to store resulting bytes for weights. + * @param blobs output parameter to store resulting bytes for intermediate blobs. + */ + void getMemoryConsumption(const std::vector& netInputShapes, + CV_OUT std::vector& layerIds, + CV_OUT std::vector& weights, + CV_OUT std::vector& blobs) const; // FIXIT: CV_WRAP + /** @overload */ + void getMemoryConsumption(const MatShape& netInputShape, + CV_OUT std::vector& layerIds, + CV_OUT std::vector& weights, + CV_OUT std::vector& blobs) const; // FIXIT: CV_WRAP + + /** @brief Enables or disables layer fusion in the network. + * @param fusion true to enable the fusion, false to disable. The fusion is enabled by default. + */ + CV_WRAP void enableFusion(bool fusion); + + /** @brief Returns overall time for inference and timings (in ticks) for layers. + * Indexes in returned vector correspond to layers ids. Some layers can be fused with others, + * in this case zero ticks count will be return for that skipped layers. + * @param timings vector for tick timings for all layers. + * @return overall ticks for model inference. + */ + CV_WRAP int64 getPerfProfile(CV_OUT std::vector& timings); + + private: + struct Impl; + Ptr impl; + }; + + /** @brief Reads a network model stored in Darknet model files. + * @param cfgFile path to the .cfg file with text description of the network architecture. + * @param darknetModel path to the .weights file with learned network. + * @returns Network object that ready to do forward, throw an exception in failure cases. + * @returns Net object. + */ + CV_EXPORTS_W Net readNetFromDarknet(const String &cfgFile, const String &darknetModel = String()); + + /** @brief Reads a network model stored in Darknet model files. + * @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture. + * @param bufferModel A buffer contains a content of .weights file with learned network. + * @returns Net object. + */ + CV_EXPORTS_W Net readNetFromDarknet(const std::vector& bufferCfg, + const std::vector& bufferModel = std::vector()); + + /** @brief Reads a network model stored in Darknet model files. + * @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture. + * @param lenCfg Number of bytes to read from bufferCfg + * @param bufferModel A buffer contains a content of .weights file with learned network. + * @param lenModel Number of bytes to read from bufferModel + * @returns Net object. + */ + CV_EXPORTS Net readNetFromDarknet(const char *bufferCfg, size_t lenCfg, + const char *bufferModel = NULL, size_t lenModel = 0); + + /** @brief Reads a network model stored in Caffe framework's format. + * @param prototxt path to the .prototxt file with text description of the network architecture. + * @param caffeModel path to the .caffemodel file with learned network. + * @returns Net object. + */ + CV_EXPORTS_W Net readNetFromCaffe(const String &prototxt, const String &caffeModel = String()); + + /** @brief Reads a network model stored in Caffe model in memory. + * @param bufferProto buffer containing the content of the .prototxt file + * @param bufferModel buffer containing the content of the .caffemodel file + * @returns Net object. + */ + CV_EXPORTS_W Net readNetFromCaffe(const std::vector& bufferProto, + const std::vector& bufferModel = std::vector()); + + /** @brief Reads a network model stored in Caffe model in memory. + * @details This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + * @param bufferProto buffer containing the content of the .prototxt file + * @param lenProto length of bufferProto + * @param bufferModel buffer containing the content of the .caffemodel file + * @param lenModel length of bufferModel + * @returns Net object. + */ + CV_EXPORTS Net readNetFromCaffe(const char *bufferProto, size_t lenProto, + const char *bufferModel = NULL, size_t lenModel = 0); + + /** @brief Reads a network model stored in TensorFlow framework's format. + * @param model path to the .pb file with binary protobuf description of the network architecture + * @param config path to the .pbtxt file that contains text graph definition in protobuf format. + * Resulting Net object is built by text graph using weights from a binary one that + * let us make it more flexible. + * @returns Net object. + */ + CV_EXPORTS_W Net readNetFromTensorflow(const String &model, const String &config = String()); + + /** @brief Reads a network model stored in TensorFlow framework's format. + * @param bufferModel buffer containing the content of the pb file + * @param bufferConfig buffer containing the content of the pbtxt file + * @returns Net object. + */ + CV_EXPORTS_W Net readNetFromTensorflow(const std::vector& bufferModel, + const std::vector& bufferConfig = std::vector()); + + /** @brief Reads a network model stored in TensorFlow framework's format. + * @details This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + * @param bufferModel buffer containing the content of the pb file + * @param lenModel length of bufferModel + * @param bufferConfig buffer containing the content of the pbtxt file + * @param lenConfig length of bufferConfig + */ + CV_EXPORTS Net readNetFromTensorflow(const char *bufferModel, size_t lenModel, + const char *bufferConfig = NULL, size_t lenConfig = 0); + + /** + * @brief Reads a network model stored in Torch7 framework's format. + * @param model path to the file, dumped from Torch by using torch.save() function. + * @param isBinary specifies whether the network was serialized in ascii mode or binary. + * @param evaluate specifies testing phase of network. If true, it's similar to evaluate() method in Torch. + * @returns Net object. + * + * @note Ascii mode of Torch serializer is more preferable, because binary mode extensively use `long` type of C language, + * which has various bit-length on different systems. + * + * The loading file must contain serialized nn.Module object + * with importing network. Try to eliminate a custom objects from serialazing data to avoid importing errors. + * + * List of supported layers (i.e. object instances derived from Torch nn.Module class): + * - nn.Sequential + * - nn.Parallel + * - nn.Concat + * - nn.Linear + * - nn.SpatialConvolution + * - nn.SpatialMaxPooling, nn.SpatialAveragePooling + * - nn.ReLU, nn.TanH, nn.Sigmoid + * - nn.Reshape + * - nn.SoftMax, nn.LogSoftMax + * + * Also some equivalents of these classes from cunn, cudnn, and fbcunn may be successfully imported. + */ + CV_EXPORTS_W Net readNetFromTorch(const String &model, bool isBinary = true, bool evaluate = true); + + /** + * @brief Read deep learning network represented in one of the supported formats. + * @param[in] model Binary file contains trained weights. The following file + * extensions are expected for models from different frameworks: + * * `*.caffemodel` (Caffe, http://caffe.berkeleyvision.org/) + * * `*.pb` (TensorFlow, https://www.tensorflow.org/) + * * `*.t7` | `*.net` (Torch, http://torch.ch/) + * * `*.weights` (Darknet, https://pjreddie.com/darknet/) + * * `*.bin` (DLDT, https://software.intel.com/openvino-toolkit) + * @param[in] config Text file contains network configuration. It could be a + * file with the following extensions: + * * `*.prototxt` (Caffe, http://caffe.berkeleyvision.org/) + * * `*.pbtxt` (TensorFlow, https://www.tensorflow.org/) + * * `*.cfg` (Darknet, https://pjreddie.com/darknet/) + * * `*.xml` (DLDT, https://software.intel.com/openvino-toolkit) + * @param[in] framework Explicit framework name tag to determine a format. + * @returns Net object. + * + * This function automatically detects an origin framework of trained model + * and calls an appropriate function such @ref readNetFromCaffe, @ref readNetFromTensorflow, + * @ref readNetFromTorch or @ref readNetFromDarknet. An order of @p model and @p config + * arguments does not matter. + */ + CV_EXPORTS_W Net readNet(const String& model, const String& config = "", const String& framework = ""); + + /** + * @brief Read deep learning network represented in one of the supported formats. + * @details This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + * @param[in] framework Name of origin framework. + * @param[in] bufferModel A buffer with a content of binary file with weights + * @param[in] bufferConfig A buffer with a content of text file contains network configuration. + * @returns Net object. + */ + CV_EXPORTS_W Net readNet(const String& framework, const std::vector& bufferModel, + const std::vector& bufferConfig = std::vector()); + + /** @brief Loads blob which was serialized as torch.Tensor object of Torch7 framework. + * @warning This function has the same limitations as readNetFromTorch(). + */ + CV_EXPORTS_W Mat readTorchBlob(const String &filename, bool isBinary = true); + + /** @brief Load a network from Intel's Model Optimizer intermediate representation. + * @param[in] xml XML configuration file with network's topology. + * @param[in] bin Binary file with trained weights. + * @returns Net object. + * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine + * backend. + */ + CV_EXPORTS_W Net readNetFromModelOptimizer(const String &xml, const String &bin); + + /** @brief Reads a network model ONNX. + * @param onnxFile path to the .onnx file with text description of the network architecture. + * @returns Network object that ready to do forward, throw an exception in failure cases. + */ + CV_EXPORTS_W Net readNetFromONNX(const String &onnxFile); + + /** @brief Creates blob from .pb file. + * @param path to the .pb file with input tensor. + * @returns Mat. + */ + CV_EXPORTS_W Mat readTensorFromONNX(const String& path); + + /** @brief Creates 4-dimensional blob from image. Optionally resizes and crops @p image from center, + * subtract @p mean values, scales values by @p scalefactor, swap Blue and Red channels. + * @param image input image (with 1-, 3- or 4-channels). + * @param size spatial size for output image + * @param mean scalar with mean values which are subtracted from channels. Values are intended + * to be in (mean-R, mean-G, mean-B) order if @p image has BGR ordering and @p swapRB is true. + * @param scalefactor multiplier for @p image values. + * @param swapRB flag which indicates that swap first and last channels + * in 3-channel image is necessary. + * @param crop flag which indicates whether image will be cropped after resize or not + * @param ddepth Depth of output blob. Choose CV_32F or CV_8U. + * @details if @p crop is true, input image is resized so one side after resize is equal to corresponding + * dimension in @p size and another one is equal or larger. Then, crop from the center is performed. + * If @p crop is false, direct resize without cropping and preserving aspect ratio is performed. + * @returns 4-dimensional Mat with NCHW dimensions order. + */ + CV_EXPORTS_W Mat blobFromImage(InputArray image, double scalefactor=1.0, const Size& size = Size(), + const Scalar& mean = Scalar(), bool swapRB=false, bool crop=false, + int ddepth=CV_32F); + + /** @brief Creates 4-dimensional blob from image. + * @details This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + */ + CV_EXPORTS void blobFromImage(InputArray image, OutputArray blob, double scalefactor=1.0, + const Size& size = Size(), const Scalar& mean = Scalar(), + bool swapRB=false, bool crop=false, int ddepth=CV_32F); + + + /** @brief Creates 4-dimensional blob from series of images. Optionally resizes and + * crops @p images from center, subtract @p mean values, scales values by @p scalefactor, + * swap Blue and Red channels. + * @param images input images (all with 1-, 3- or 4-channels). + * @param size spatial size for output image + * @param mean scalar with mean values which are subtracted from channels. Values are intended + * to be in (mean-R, mean-G, mean-B) order if @p image has BGR ordering and @p swapRB is true. + * @param scalefactor multiplier for @p images values. + * @param swapRB flag which indicates that swap first and last channels + * in 3-channel image is necessary. + * @param crop flag which indicates whether image will be cropped after resize or not + * @param ddepth Depth of output blob. Choose CV_32F or CV_8U. + * @details if @p crop is true, input image is resized so one side after resize is equal to corresponding + * dimension in @p size and another one is equal or larger. Then, crop from the center is performed. + * If @p crop is false, direct resize without cropping and preserving aspect ratio is performed. + * @returns 4-dimensional Mat with NCHW dimensions order. + */ + CV_EXPORTS_W Mat blobFromImages(InputArrayOfArrays images, double scalefactor=1.0, + Size size = Size(), const Scalar& mean = Scalar(), bool swapRB=false, bool crop=false, + int ddepth=CV_32F); + + /** @brief Creates 4-dimensional blob from series of images. + * @details This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + */ + CV_EXPORTS void blobFromImages(InputArrayOfArrays images, OutputArray blob, + double scalefactor=1.0, Size size = Size(), + const Scalar& mean = Scalar(), bool swapRB=false, bool crop=false, + int ddepth=CV_32F); + + /** @brief Parse a 4D blob and output the images it contains as 2D arrays through a simpler data structure + * (std::vector). + * @param[in] blob_ 4 dimensional array (images, channels, height, width) in floating point precision (CV_32F) from + * which you would like to extract the images. + * @param[out] images_ array of 2D Mat containing the images extracted from the blob in floating point precision + * (CV_32F). They are non normalized neither mean added. The number of returned images equals the first dimension + * of the blob (batch size). Every image has a number of channels equals to the second dimension of the blob (depth). + */ + CV_EXPORTS_W void imagesFromBlob(const cv::Mat& blob_, OutputArrayOfArrays images_); + + /** @brief Convert all weights of Caffe network to half precision floating point. + * @param src Path to origin model from Caffe framework contains single + * precision floating point weights (usually has `.caffemodel` extension). + * @param dst Path to destination model with updated weights. + * @param layersTypes Set of layers types which parameters will be converted. + * By default, converts only Convolutional and Fully-Connected layers' + * weights. + * + * @note Shrinked model has no origin float32 weights so it can't be used + * in origin Caffe framework anymore. However the structure of data + * is taken from NVidia's Caffe fork: https://github.com/NVIDIA/caffe. + * So the resulting model may be used there. + */ + CV_EXPORTS_W void shrinkCaffeModel(const String& src, const String& dst, + const std::vector& layersTypes = std::vector()); + + /** @brief Create a text representation for a binary network stored in protocol buffer format. + * @param[in] model A path to binary network. + * @param[in] output A path to output text file to be created. + * + * @note To reduce output file size, trained weights are not included. + */ + CV_EXPORTS_W void writeTextGraph(const String& model, const String& output); + + /** @brief Performs non maximum suppression given boxes and corresponding scores. + + * @param bboxes a set of bounding boxes to apply NMS. + * @param scores a set of corresponding confidences. + * @param score_threshold a threshold used to filter boxes by score. + * @param nms_threshold a threshold used in non maximum suppression. + * @param indices the kept indices of bboxes after NMS. + * @param eta a coefficient in adaptive threshold formula: \f$nms\_threshold_{i+1}=eta\cdot nms\_threshold_i\f$. + * @param top_k if `>0`, keep at most @p top_k picked indices. + */ + CV_EXPORTS_W void NMSBoxes(const std::vector& bboxes, const std::vector& scores, + const float score_threshold, const float nms_threshold, + CV_OUT std::vector& indices, + const float eta = 1.f, const int top_k = 0); + + CV_EXPORTS_W void NMSBoxes(const std::vector& bboxes, const std::vector& scores, + const float score_threshold, const float nms_threshold, + CV_OUT std::vector& indices, + const float eta = 1.f, const int top_k = 0); + + CV_EXPORTS_AS(NMSBoxesRotated) void NMSBoxes(const std::vector& bboxes, const std::vector& scores, + const float score_threshold, const float nms_threshold, + CV_OUT std::vector& indices, + const float eta = 1.f, const int top_k = 0); + + /** @brief Release a Myriad device is binded by OpenCV. + * + * Single Myriad device cannot be shared across multiple processes which uses + * Inference Engine's Myriad plugin. + */ + CV_EXPORTS_W void resetMyriadDevice(); + +//! @} +CV__DNN_EXPERIMENTAL_NS_END +} +} + +#include +#include + +#endif /* OPENCV_DNN_DNN_HPP */ diff --git a/include/opencv2/dnn/dnn.inl.hpp b/include/opencv2/dnn/dnn.inl.hpp new file mode 100644 index 0000000..17d4c20 --- /dev/null +++ b/include/opencv2/dnn/dnn.inl.hpp @@ -0,0 +1,395 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_DNN_DNN_INL_HPP +#define OPENCV_DNN_DNN_INL_HPP + +#include + +namespace cv { +namespace dnn { +CV__DNN_EXPERIMENTAL_NS_BEGIN + +template +DictValue DictValue::arrayInt(TypeIter begin, int size) +{ + DictValue res(Param::INT, new AutoBuffer(size)); + for (int j = 0; j < size; begin++, j++) + (*res.pi)[j] = *begin; + return res; +} + +template +DictValue DictValue::arrayReal(TypeIter begin, int size) +{ + DictValue res(Param::REAL, new AutoBuffer(size)); + for (int j = 0; j < size; begin++, j++) + (*res.pd)[j] = *begin; + return res; +} + +template +DictValue DictValue::arrayString(TypeIter begin, int size) +{ + DictValue res(Param::STRING, new AutoBuffer(size)); + for (int j = 0; j < size; begin++, j++) + (*res.ps)[j] = *begin; + return res; +} + +template<> +inline DictValue DictValue::get(int idx) const +{ + CV_Assert(idx == -1); + return *this; +} + +template<> +inline int64 DictValue::get(int idx) const +{ + CV_Assert((idx == -1 && size() == 1) || (idx >= 0 && idx < size())); + idx = (idx == -1) ? 0 : idx; + + if (type == Param::INT) + { + return (*pi)[idx]; + } + else if (type == Param::REAL) + { + double doubleValue = (*pd)[idx]; + + double fracpart, intpart; + fracpart = std::modf(doubleValue, &intpart); + CV_Assert(fracpart == 0.0); + + return (int64)doubleValue; + } + else if (type == Param::STRING) + { + return std::atoi((*ps)[idx].c_str()); + } + else + { + CV_Assert(isInt() || isReal() || isString()); + return 0; + } +} + +template<> +inline int DictValue::get(int idx) const +{ + return (int)get(idx); +} + +inline int DictValue::getIntValue(int idx) const +{ + return (int)get(idx); +} + +template<> +inline unsigned DictValue::get(int idx) const +{ + return (unsigned)get(idx); +} + +template<> +inline bool DictValue::get(int idx) const +{ + return (get(idx) != 0); +} + +template<> +inline double DictValue::get(int idx) const +{ + CV_Assert((idx == -1 && size() == 1) || (idx >= 0 && idx < size())); + idx = (idx == -1) ? 0 : idx; + + if (type == Param::REAL) + { + return (*pd)[idx]; + } + else if (type == Param::INT) + { + return (double)(*pi)[idx]; + } + else if (type == Param::STRING) + { + return std::atof((*ps)[idx].c_str()); + } + else + { + CV_Assert(isReal() || isInt() || isString()); + return 0; + } +} + +inline double DictValue::getRealValue(int idx) const +{ + return get(idx); +} + +template<> +inline float DictValue::get(int idx) const +{ + return (float)get(idx); +} + +template<> +inline String DictValue::get(int idx) const +{ + CV_Assert(isString()); + CV_Assert((idx == -1 && ps->size() == 1) || (idx >= 0 && idx < (int)ps->size())); + return (*ps)[(idx == -1) ? 0 : idx]; +} + + +inline String DictValue::getStringValue(int idx) const +{ + return get(idx); +} + +inline void DictValue::release() +{ + switch (type) + { + case Param::INT: + delete pi; + break; + case Param::STRING: + delete ps; + break; + case Param::REAL: + delete pd; + break; + } +} + +inline DictValue::~DictValue() +{ + release(); +} + +inline DictValue & DictValue::operator=(const DictValue &r) +{ + if (&r == this) + return *this; + + if (r.type == Param::INT) + { + AutoBuffer *tmp = new AutoBuffer(*r.pi); + release(); + pi = tmp; + } + else if (r.type == Param::STRING) + { + AutoBuffer *tmp = new AutoBuffer(*r.ps); + release(); + ps = tmp; + } + else if (r.type == Param::REAL) + { + AutoBuffer *tmp = new AutoBuffer(*r.pd); + release(); + pd = tmp; + } + + type = r.type; + + return *this; +} + +inline DictValue::DictValue(const DictValue &r) +{ + type = r.type; + + if (r.type == Param::INT) + pi = new AutoBuffer(*r.pi); + else if (r.type == Param::STRING) + ps = new AutoBuffer(*r.ps); + else if (r.type == Param::REAL) + pd = new AutoBuffer(*r.pd); +} + +inline bool DictValue::isString() const +{ + return (type == Param::STRING); +} + +inline bool DictValue::isInt() const +{ + return (type == Param::INT); +} + +inline bool DictValue::isReal() const +{ + return (type == Param::REAL || type == Param::INT); +} + +inline int DictValue::size() const +{ + switch (type) + { + case Param::INT: + return (int)pi->size(); + case Param::STRING: + return (int)ps->size(); + case Param::REAL: + return (int)pd->size(); + } +#ifdef __OPENCV_BUILD + CV_Error(Error::StsInternal, ""); +#else + CV_ErrorNoReturn(Error::StsInternal, ""); +#endif +} + +inline std::ostream &operator<<(std::ostream &stream, const DictValue &dictv) +{ + int i; + + if (dictv.isInt()) + { + for (i = 0; i < dictv.size() - 1; i++) + stream << dictv.get(i) << ", "; + stream << dictv.get(i); + } + else if (dictv.isReal()) + { + for (i = 0; i < dictv.size() - 1; i++) + stream << dictv.get(i) << ", "; + stream << dictv.get(i); + } + else if (dictv.isString()) + { + for (i = 0; i < dictv.size() - 1; i++) + stream << "\"" << dictv.get(i) << "\", "; + stream << dictv.get(i); + } + + return stream; +} + +///////////////////////////////////////////////////////////////// + +inline bool Dict::has(const String &key) const +{ + return dict.count(key) != 0; +} + +inline DictValue *Dict::ptr(const String &key) +{ + _Dict::iterator i = dict.find(key); + return (i == dict.end()) ? NULL : &i->second; +} + +inline const DictValue *Dict::ptr(const String &key) const +{ + _Dict::const_iterator i = dict.find(key); + return (i == dict.end()) ? NULL : &i->second; +} + +inline const DictValue &Dict::get(const String &key) const +{ + _Dict::const_iterator i = dict.find(key); + if (i == dict.end()) + CV_Error(Error::StsObjectNotFound, "Required argument \"" + key + "\" not found into dictionary"); + return i->second; +} + +template +inline T Dict::get(const String &key) const +{ + return this->get(key).get(); +} + +template +inline T Dict::get(const String &key, const T &defaultValue) const +{ + _Dict::const_iterator i = dict.find(key); + + if (i != dict.end()) + return i->second.get(); + else + return defaultValue; +} + +template +inline const T &Dict::set(const String &key, const T &value) +{ + _Dict::iterator i = dict.find(key); + + if (i != dict.end()) + i->second = DictValue(value); + else + dict.insert(std::make_pair(key, DictValue(value))); + + return value; +} + +inline void Dict::erase(const String &key) +{ + dict.erase(key); +} + +inline std::ostream &operator<<(std::ostream &stream, const Dict &dict) +{ + Dict::_Dict::const_iterator it; + for (it = dict.dict.begin(); it != dict.dict.end(); it++) + stream << it->first << " : " << it->second << "\n"; + + return stream; +} + +inline std::map::const_iterator Dict::begin() const +{ + return dict.begin(); +} + +inline std::map::const_iterator Dict::end() const +{ + return dict.end(); +} + +CV__DNN_EXPERIMENTAL_NS_END +} +} + +#endif diff --git a/include/opencv2/dnn/layer.details.hpp b/include/opencv2/dnn/layer.details.hpp new file mode 100644 index 0000000..619514e --- /dev/null +++ b/include/opencv2/dnn/layer.details.hpp @@ -0,0 +1,78 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +#ifndef OPENCV_DNN_LAYER_DETAILS_HPP +#define OPENCV_DNN_LAYER_DETAILS_HPP + +#include + +namespace cv { +namespace dnn { +CV__DNN_EXPERIMENTAL_NS_BEGIN + +/** @brief Registers layer constructor in runtime. +* @param type string, containing type name of the layer. +* @param constructorFunc pointer to the function of type LayerRegister::Constructor, which creates the layer. +* @details This macros must be placed inside the function code. +*/ +#define CV_DNN_REGISTER_LAYER_FUNC(type, constructorFunc) \ + cv::dnn::LayerFactory::registerLayer(#type, constructorFunc); + +/** @brief Registers layer class in runtime. + * @param type string, containing type name of the layer. + * @param class C++ class, derived from Layer. + * @details This macros must be placed inside the function code. + */ +#define CV_DNN_REGISTER_LAYER_CLASS(type, class) \ + cv::dnn::LayerFactory::registerLayer(#type, cv::dnn::details::_layerDynamicRegisterer); + +/** @brief Registers layer constructor on module load time. +* @param type string, containing type name of the layer. +* @param constructorFunc pointer to the function of type LayerRegister::Constructor, which creates the layer. +* @details This macros must be placed outside the function code. +*/ +#define CV_DNN_REGISTER_LAYER_FUNC_STATIC(type, constructorFunc) \ +static cv::dnn::details::_LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, constructorFunc); + +/** @brief Registers layer class on module load time. + * @param type string, containing type name of the layer. + * @param class C++ class, derived from Layer. + * @details This macros must be placed outside the function code. + */ +#define CV_DNN_REGISTER_LAYER_CLASS_STATIC(type, class) \ +Ptr __LayerStaticRegisterer_func_##type(LayerParams ¶ms) \ + { return Ptr(new class(params)); } \ +static cv::dnn::details::_LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, __LayerStaticRegisterer_func_##type); + +namespace details { + +template +Ptr _layerDynamicRegisterer(LayerParams ¶ms) +{ + return Ptr(LayerClass::create(params)); +} + +//allows automatically register created layer on module load time +class _LayerStaticRegisterer +{ + String type; +public: + + _LayerStaticRegisterer(const String &layerType, LayerFactory::Constructor layerConstructor) + { + this->type = layerType; + LayerFactory::registerLayer(layerType, layerConstructor); + } + + ~_LayerStaticRegisterer() + { + LayerFactory::unregisterLayer(type); + } +}; + +} // namespace +CV__DNN_EXPERIMENTAL_NS_END +}} // namespace + +#endif diff --git a/include/opencv2/dnn/layer.hpp b/include/opencv2/dnn/layer.hpp new file mode 100644 index 0000000..c4712b8 --- /dev/null +++ b/include/opencv2/dnn/layer.hpp @@ -0,0 +1,85 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_DNN_LAYER_HPP +#define OPENCV_DNN_LAYER_HPP +#include + +namespace cv { +namespace dnn { +CV__DNN_EXPERIMENTAL_NS_BEGIN +//! @addtogroup dnn +//! @{ +//! +//! @defgroup dnnLayerFactory Utilities for New Layers Registration +//! @{ + +/** @brief %Layer factory allows to create instances of registered layers. */ +class CV_EXPORTS LayerFactory +{ +public: + + //! Each Layer class must provide this function to the factory + typedef Ptr(*Constructor)(LayerParams ¶ms); + + //! Registers the layer class with typename @p type and specified @p constructor. Thread-safe. + static void registerLayer(const String &type, Constructor constructor); + + //! Unregisters registered layer with specified type name. Thread-safe. + static void unregisterLayer(const String &type); + + /** @brief Creates instance of registered layer. + * @param type type name of creating layer. + * @param params parameters which will be used for layer initialization. + * @note Thread-safe. + */ + static Ptr createLayerInstance(const String &type, LayerParams& params); + +private: + LayerFactory(); +}; + +//! @} +//! @} +CV__DNN_EXPERIMENTAL_NS_END +} +} +#endif diff --git a/include/opencv2/dnn/shape_utils.hpp b/include/opencv2/dnn/shape_utils.hpp new file mode 100644 index 0000000..b0ed3af --- /dev/null +++ b/include/opencv2/dnn/shape_utils.hpp @@ -0,0 +1,219 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_DNN_DNN_SHAPE_UTILS_HPP +#define OPENCV_DNN_DNN_SHAPE_UTILS_HPP + +#include +#include // CV_MAX_DIM +#include +#include +#include + +namespace cv { +namespace dnn { +CV__DNN_EXPERIMENTAL_NS_BEGIN + +//Slicing + +struct _Range : public cv::Range +{ + _Range(const Range &r) : cv::Range(r) {} + _Range(int start_, int size_ = 1) : cv::Range(start_, start_ + size_) {} +}; + +static inline Mat slice(const Mat &m, const _Range &r0) +{ + Range ranges[CV_MAX_DIM]; + for (int i = 1; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + return m(&ranges[0]); +} + +static inline Mat slice(const Mat &m, const _Range &r0, const _Range &r1) +{ + CV_Assert(m.dims >= 2); + Range ranges[CV_MAX_DIM]; + for (int i = 2; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + ranges[1] = r1; + return m(&ranges[0]); +} + +static inline Mat slice(const Mat &m, const _Range &r0, const _Range &r1, const _Range &r2) +{ + CV_Assert(m.dims >= 3); + Range ranges[CV_MAX_DIM]; + for (int i = 3; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + ranges[1] = r1; + ranges[2] = r2; + return m(&ranges[0]); +} + +static inline Mat slice(const Mat &m, const _Range &r0, const _Range &r1, const _Range &r2, const _Range &r3) +{ + CV_Assert(m.dims >= 4); + Range ranges[CV_MAX_DIM]; + for (int i = 4; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + ranges[1] = r1; + ranges[2] = r2; + ranges[3] = r3; + return m(&ranges[0]); +} + +static inline Mat getPlane(const Mat &m, int n, int cn) +{ + CV_Assert(m.dims > 2); + int sz[CV_MAX_DIM]; + for(int i = 2; i < m.dims; i++) + { + sz[i-2] = m.size.p[i]; + } + return Mat(m.dims - 2, sz, m.type(), (void*)m.ptr(n, cn)); +} + +static inline MatShape shape(const int* dims, const int n) +{ + MatShape shape; + shape.assign(dims, dims + n); + return shape; +} + +static inline MatShape shape(const Mat& mat) +{ + return shape(mat.size.p, mat.dims); +} + +static inline MatShape shape(const MatSize& sz) +{ + return shape(sz.p, sz.dims()); +} + +static inline MatShape shape(const UMat& mat) +{ + return shape(mat.size.p, mat.dims); +} + +namespace {inline bool is_neg(int i) { return i < 0; }} + +static inline MatShape shape(int a0, int a1=-1, int a2=-1, int a3=-1) +{ + int dims[] = {a0, a1, a2, a3}; + MatShape s = shape(dims, 4); + s.erase(std::remove_if(s.begin(), s.end(), is_neg), s.end()); + return s; +} + +static inline int total(const MatShape& shape, int start = -1, int end = -1) +{ + if (start == -1) start = 0; + if (end == -1) end = (int)shape.size(); + + if (shape.empty()) + return 0; + + int elems = 1; + CV_Assert(start <= (int)shape.size() && end <= (int)shape.size() && + start <= end); + for(int i = start; i < end; i++) + { + elems *= shape[i]; + } + return elems; +} + +static inline MatShape concat(const MatShape& a, const MatShape& b) +{ + MatShape c = a; + c.insert(c.end(), b.begin(), b.end()); + + return c; +} + +static inline std::string toString(const MatShape& shape, const String& name = "") +{ + std::ostringstream ss; + if (!name.empty()) + ss << name << ' '; + ss << '['; + for(size_t i = 0, n = shape.size(); i < n; ++i) + ss << ' ' << shape[i]; + ss << " ]"; + return ss.str(); +} +static inline void print(const MatShape& shape, const String& name = "") +{ + std::cout << toString(shape, name) << std::endl; +} +static inline std::ostream& operator<<(std::ostream &out, const MatShape& shape) +{ + out << toString(shape); + return out; +} + +inline int clamp(int ax, int dims) +{ + return ax < 0 ? ax + dims : ax; +} + +inline int clamp(int ax, const MatShape& shape) +{ + return clamp(ax, (int)shape.size()); +} + +inline Range clamp(const Range& r, int axisSize) +{ + Range clamped(std::max(r.start, 0), + r.end > 0 ? std::min(r.end, axisSize) : axisSize + r.end + 1); + CV_Assert_N(clamped.start < clamped.end, clamped.end <= axisSize); + return clamped; +} + +CV__DNN_EXPERIMENTAL_NS_END +} +} +#endif diff --git a/include/opencv2/features2d.hpp b/include/opencv2/features2d.hpp index cf95e7d..ee81ebe 100644 --- a/include/opencv2/features2d.hpp +++ b/include/opencv2/features2d.hpp @@ -40,11 +40,15 @@ // //M*/ -#ifndef __OPENCV_FEATURES_2D_HPP__ -#define __OPENCV_FEATURES_2D_HPP__ +#ifndef OPENCV_FEATURES_2D_HPP +#define OPENCV_FEATURES_2D_HPP +#include "opencv2/opencv_modules.hpp" #include "opencv2/core.hpp" + +#ifdef HAVE_OPENCV_FLANN #include "opencv2/flann/miniflann.hpp" +#endif /** @defgroup features2d 2D Features Framework @@ -74,7 +78,7 @@ This section describes approaches based on local 2D features and used to categor - A complete Bag-Of-Words sample can be found at opencv_source_code/samples/cpp/bagofwords_classification.cpp - (Python) An example using the features2D framework to perform object categorization can be - found at opencv_source_code/samples/python2/find_obj.py + found at opencv_source_code/samples/python/find_obj.py @} */ @@ -117,6 +121,10 @@ public: * Remove duplicated keypoints. */ static void removeDuplicated( std::vector& keypoints ); + /* + * Remove duplicated keypoints and sort the remaining keypoints + */ + static void removeDuplicatedSorted( std::vector& keypoints ); /* * Retain the specified number of the best keypoints (according to the response) @@ -129,7 +137,11 @@ public: /** @brief Abstract base class for 2D image feature detectors and descriptor extractors */ +#ifdef __EMSCRIPTEN__ +class CV_EXPORTS_W Feature2D : public Algorithm +#else class CV_EXPORTS_W Feature2D : public virtual Algorithm +#endif { public: virtual ~Feature2D(); @@ -153,8 +165,8 @@ public: @param masks Masks for each input image specifying where to look for keypoints (optional). masks[i] is a mask for images[i]. */ - virtual void detect( InputArrayOfArrays images, - std::vector >& keypoints, + CV_WRAP virtual void detect( InputArrayOfArrays images, + CV_OUT std::vector >& keypoints, InputArrayOfArrays masks=noArray() ); /** @brief Computes the descriptors for a set of keypoints detected in an image (first variant) or image set @@ -182,8 +194,8 @@ public: descriptors computed for a keypoints[i]. Row j is the keypoints (or keypoints[i]) is the descriptor for keypoint j-th keypoint. */ - virtual void compute( InputArrayOfArrays images, - std::vector >& keypoints, + CV_WRAP virtual void compute( InputArrayOfArrays images, + CV_OUT CV_IN_OUT std::vector >& keypoints, OutputArrayOfArrays descriptors ); /** Detects keypoints and computes the descriptors */ @@ -196,8 +208,21 @@ public: CV_WRAP virtual int descriptorType() const; CV_WRAP virtual int defaultNorm() const; + CV_WRAP void write( const String& fileName ) const; + + CV_WRAP void read( const String& fileName ); + + virtual void write( FileStorage&) const CV_OVERRIDE; + + // see corresponding cv::Algorithm method + CV_WRAP virtual void read( const FileNode&) CV_OVERRIDE; + //! Return true if detector object is empty - CV_WRAP virtual bool empty() const; + CV_WRAP virtual bool empty() const CV_OVERRIDE; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; + + // see corresponding cv::Algorithm method + CV_WRAP inline void write(const Ptr& fs, const String& name = String()) const { Algorithm::write(fs, name); } }; /** Feature detectors in OpenCV have wrappers with a common interface that enables you to easily switch @@ -242,6 +267,24 @@ public: @param indexChange index remapping of the bits. */ CV_WRAP static Ptr create(const std::vector &radiusList, const std::vector &numberList, float dMax=5.85f, float dMin=8.2f, const std::vector& indexChange=std::vector()); + + /** @brief The BRISK constructor for a custom pattern, detection threshold and octaves + + @param thresh AGAST detection threshold score. + @param octaves detection octaves. Use 0 to do single scale. + @param radiusList defines the radii (in pixels) where the samples around a keypoint are taken (for + keypoint scale 1). + @param numberList defines the number of sampling points on the sampling circle. Must be the same + size as radiusList.. + @param dMax threshold for the short pairings used for descriptor formation (in pixels for keypoint + scale 1). + @param dMin threshold for the long pairings used for orientation determination (in pixels for + keypoint scale 1). + @param indexChange index remapping of the bits. */ + CV_WRAP static Ptr create(int thresh, int octaves, const std::vector &radiusList, + const std::vector &numberList, float dMax=5.85f, float dMin=8.2f, + const std::vector& indexChange=std::vector()); + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; /** @brief Class implementing the ORB (*oriented BRIEF*) keypoint detector and descriptor extractor @@ -265,10 +308,11 @@ public: will mean that to cover certain scale range you will need more pyramid levels and so the speed will suffer. @param nlevels The number of pyramid levels. The smallest level will have linear size equal to - input_image_linear_size/pow(scaleFactor, nlevels). + input_image_linear_size/pow(scaleFactor, nlevels - firstLevel). @param edgeThreshold This is size of the border where the features are not detected. It should roughly match the patchSize parameter. - @param firstLevel It should be 0 in the current implementation. + @param firstLevel The level of pyramid to put source image to. Previous layers are filled + with upscaled source image. @param WTA_K The number of points that produce each element of the oriented BRIEF descriptor. The default value 2 means the BRIEF where we take a random point pair and compare their brightnesses, so we get 0/1 response. Other possible values are 3 and 4. For example, 3 means that we take 3 @@ -315,30 +359,54 @@ public: CV_WRAP virtual void setFastThreshold(int fastThreshold) = 0; CV_WRAP virtual int getFastThreshold() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; -/** @brief Maximally stable extremal region extractor. : +/** @brief Maximally stable extremal region extractor -The class encapsulates all the parameters of the MSER extraction algorithm (see -). Also see - for useful comments and parameters description. +The class encapsulates all the parameters of the %MSER extraction algorithm (see [wiki +article](http://en.wikipedia.org/wiki/Maximally_stable_extremal_regions)). -@note - - (Python) A complete example showing the use of the MSER detector can be found at - opencv_source_code/samples/python2/mser.py - */ +- there are two different implementation of %MSER: one for grey image, one for color image + +- the grey image algorithm is taken from: @cite nister2008linear ; the paper claims to be faster +than union-find method; it actually get 1.5~2m/s on my centrino L7200 1.2GHz laptop. + +- the color image algorithm is taken from: @cite forssen2007maximally ; it should be much slower +than grey image method ( 3~4 times ); the chi_table.h file is taken directly from paper's source +code which is distributed under GPL. + +- (Python) A complete example showing the use of the %MSER detector can be found at samples/python/mser.py +*/ class CV_EXPORTS_W MSER : public Feature2D { public: - //! the full constructor + /** @brief Full consturctor for %MSER detector + + @param _delta it compares \f$(size_{i}-size_{i-delta})/size_{i-delta}\f$ + @param _min_area prune the area which smaller than minArea + @param _max_area prune the area which bigger than maxArea + @param _max_variation prune the area have similar size to its children + @param _min_diversity for color image, trace back to cut off mser with diversity less than min_diversity + @param _max_evolution for color image, the evolution steps + @param _area_threshold for color image, the area threshold to cause re-initialize + @param _min_margin for color image, ignore too small margin + @param _edge_blur_size for color image, the aperture size for edge blur + */ CV_WRAP static Ptr create( int _delta=5, int _min_area=60, int _max_area=14400, double _max_variation=0.25, double _min_diversity=.2, int _max_evolution=200, double _area_threshold=1.01, double _min_margin=0.003, int _edge_blur_size=5 ); + /** @brief Detect %MSER regions + + @param image input image (8UC1, 8UC3 or 8UC4, must be greater or equal than 3x3) + @param msers resulting list of point sets + @param bboxes resulting bounding boxes + */ CV_WRAP virtual void detectRegions( InputArray image, CV_OUT std::vector >& msers, - std::vector& bboxes ) = 0; + CV_OUT std::vector& bboxes ) = 0; CV_WRAP virtual void setDelta(int delta) = 0; CV_WRAP virtual int getDelta() const = 0; @@ -351,6 +419,7 @@ public: CV_WRAP virtual void setPass2Only(bool f) = 0; CV_WRAP virtual bool getPass2Only() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; /** @overload */ @@ -406,6 +475,7 @@ public: CV_WRAP virtual void setType(int type) = 0; CV_WRAP virtual int getType() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; /** @overload */ @@ -424,6 +494,9 @@ circle around this pixel. AgastFeatureDetector::AGAST_5_8, AgastFeatureDetector::AGAST_7_12d, AgastFeatureDetector::AGAST_7_12s, AgastFeatureDetector::OAST_9_16 +For non-Intel platforms, there is a tree optimised variant of AGAST with same numerical results. +The 32-bit binary tree tables were generated automatically from original code using perl script. +The perl script and examples of tree generation are placed in features2d/doc folder. Detects corners using the AGAST algorithm by @cite mair2010_agast . */ @@ -457,6 +530,7 @@ public: CV_WRAP virtual void setType(int type) = 0; CV_WRAP virtual int getType() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; /** @brief Wrapping class for feature detection using the goodFeaturesToTrack function. : @@ -466,6 +540,8 @@ class CV_EXPORTS_W GFTTDetector : public Feature2D public: CV_WRAP static Ptr create( int maxCorners=1000, double qualityLevel=0.01, double minDistance=1, int blockSize=3, bool useHarrisDetector=false, double k=0.04 ); + CV_WRAP static Ptr create( int maxCorners, double qualityLevel, double minDistance, + int blockSize, int gradiantSize, bool useHarrisDetector=false, double k=0.04 ); CV_WRAP virtual void setMaxFeatures(int maxFeatures) = 0; CV_WRAP virtual int getMaxFeatures() const = 0; @@ -483,6 +559,7 @@ public: CV_WRAP virtual void setK(double k) = 0; CV_WRAP virtual double getK() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; /** @brief Class for extracting blobs from an image. : @@ -549,6 +626,7 @@ public: CV_WRAP static Ptr create(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params()); + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; //! @} features2d_main @@ -605,15 +683,25 @@ public: CV_WRAP virtual void setDiffusivity(int diff) = 0; CV_WRAP virtual int getDiffusivity() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; -/** @brief Class implementing the AKAZE keypoint detector and descriptor extractor, described in @cite ANB13 . : +/** @brief Class implementing the AKAZE keypoint detector and descriptor extractor, described in @cite ANB13. -@note AKAZE descriptors can only be used with KAZE or AKAZE keypoints. Try to avoid using *extract* -and *detect* instead of *operator()* due to performance reasons. .. [ANB13] Fast Explicit Diffusion -for Accelerated Features in Nonlinear Scale Spaces. Pablo F. Alcantarilla, Jesús Nuevo and Adrien -Bartoli. In British Machine Vision Conference (BMVC), Bristol, UK, September 2013. - */ +@details AKAZE descriptors can only be used with KAZE or AKAZE keypoints. This class is thread-safe. + +@note When you need descriptors use Feature2D::detectAndCompute, which +provides better performance. When using Feature2D::detect followed by +Feature2D::compute scale space pyramid is computed twice. + +@note AKAZE implements T-API. When image is passed as UMat some parts of the algorithm +will use OpenCL. + +@note [ANB13] Fast Explicit Diffusion for Accelerated Features in Nonlinear +Scale Spaces. Pablo F. Alcantarilla, Jesús Nuevo and Adrien Bartoli. In +British Machine Vision Conference (BMVC), Bristol, UK, September 2013. + +*/ class CV_EXPORTS_W AKAZE : public Feature2D { public: @@ -663,6 +751,7 @@ public: CV_WRAP virtual void setDiffusivity(int diff) = 0; CV_WRAP virtual int getDiffusivity() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; }; //! @} features2d_main @@ -702,7 +791,7 @@ struct CV_EXPORTS SL2 * Euclidean distance functor */ template -struct CV_EXPORTS L2 +struct L2 { enum { normType = NORM_L2 }; typedef T ValueType; @@ -718,7 +807,7 @@ struct CV_EXPORTS L2 * Manhattan distance (city block distance) functor */ template -struct CV_EXPORTS L1 +struct L1 { enum { normType = NORM_L1 }; typedef T ValueType; @@ -745,6 +834,15 @@ an image set. class CV_EXPORTS_W DescriptorMatcher : public Algorithm { public: + enum + { + FLANNBASED = 1, + BRUTEFORCE = 2, + BRUTEFORCE_L1 = 3, + BRUTEFORCE_HAMMING = 4, + BRUTEFORCE_HAMMINGLUT = 5, + BRUTEFORCE_SL2 = 6 + }; virtual ~DescriptorMatcher(); /** @brief Adds descriptors to train a CPU(trainDescCollectionis) or GPU(utrainDescCollectionis) descriptor @@ -763,11 +861,11 @@ public: /** @brief Clears the train descriptor collections. */ - CV_WRAP virtual void clear(); + CV_WRAP virtual void clear() CV_OVERRIDE; /** @brief Returns true if there are no train descriptors in the both collections. */ - CV_WRAP virtual bool empty() const; + CV_WRAP virtual bool empty() const CV_OVERRIDE; /** @brief Returns true if the descriptor matcher supports masking permissible matches. */ @@ -842,8 +940,8 @@ public: query descriptor and the training descriptor is equal or smaller than maxDistance. Found matches are returned in the distance increasing order. */ - void radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors, - std::vector >& matches, float maxDistance, + CV_WRAP void radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors, + CV_OUT std::vector >& matches, float maxDistance, InputArray mask=noArray(), bool compactResult=false ) const; /** @overload @@ -880,13 +978,26 @@ public: false, the matches vector has the same size as queryDescriptors rows. If compactResult is true, the matches vector does not contain matches for fully masked-out query descriptors. */ - void radiusMatch( InputArray queryDescriptors, std::vector >& matches, float maxDistance, + CV_WRAP void radiusMatch( InputArray queryDescriptors, CV_OUT std::vector >& matches, float maxDistance, InputArrayOfArrays masks=noArray(), bool compactResult=false ); + + CV_WRAP void write( const String& fileName ) const + { + FileStorage fs(fileName, FileStorage::WRITE); + write(fs); + } + + CV_WRAP void read( const String& fileName ) + { + FileStorage fs(fileName, FileStorage::READ); + read(fs.root()); + } // Reads matcher object from a file node - virtual void read( const FileNode& ); + // see corresponding cv::Algorithm method + CV_WRAP virtual void read( const FileNode& ) CV_OVERRIDE; // Writes matcher object to a file storage - virtual void write( FileStorage& ) const; + virtual void write( FileStorage& ) const CV_OVERRIDE; /** @brief Clones the matcher. @@ -894,7 +1005,7 @@ public: that is, copies both parameters and train data. If emptyTrainData is true, the method creates an object copy with the current parameters but with empty train data. */ - virtual Ptr clone( bool emptyTrainData=false ) const = 0; + CV_WRAP virtual Ptr clone( bool emptyTrainData=false ) const = 0; /** @brief Creates a descriptor matcher of a given type with the default parameters (using default constructor). @@ -908,6 +1019,13 @@ public: - `FlannBased` */ CV_WRAP static Ptr create( const String& descriptorMatcherType ); + + CV_WRAP static Ptr create( int matcherType ); + + + // see corresponding cv::Algorithm method + CV_WRAP inline void write(const Ptr& fs, const String& name = String()) const { Algorithm::write(fs, name); } + protected: /** * Class to work with descriptors from several images as with one merged matrix. @@ -964,8 +1082,17 @@ sets. class CV_EXPORTS_W BFMatcher : public DescriptorMatcher { public: - /** @brief Brute-force matcher constructor. + /** @brief Brute-force matcher constructor (obsolete). Please use BFMatcher.create() + * + * + */ + CV_WRAP BFMatcher( int normType=NORM_L2, bool crossCheck=false ); + virtual ~BFMatcher() {} + + virtual bool isMaskSupported() const CV_OVERRIDE { return true; } + + /** @brief Brute-force matcher create method. @param normType One of NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2. L1 and L2 norms are preferable choices for SIFT and SURF descriptors, NORM_HAMMING should be used with ORB, BRISK and BRIEF, NORM_HAMMING2 should be used with ORB when WTA_K==3 or 4 (see ORB::ORB constructor @@ -977,26 +1104,24 @@ public: pairs. Such technique usually produces best results with minimal number of outliers when there are enough matches. This is alternative to the ratio test, used by D. Lowe in SIFT paper. */ - CV_WRAP BFMatcher( int normType=NORM_L2, bool crossCheck=false ); - virtual ~BFMatcher() {} + CV_WRAP static Ptr create( int normType=NORM_L2, bool crossCheck=false ) ; - virtual bool isMaskSupported() const { return true; } - - virtual Ptr clone( bool emptyTrainData=false ) const; + virtual Ptr clone( bool emptyTrainData=false ) const CV_OVERRIDE; protected: virtual void knnMatchImpl( InputArray queryDescriptors, std::vector >& matches, int k, - InputArrayOfArrays masks=noArray(), bool compactResult=false ); + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector >& matches, float maxDistance, - InputArrayOfArrays masks=noArray(), bool compactResult=false ); + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; int normType; bool crossCheck; }; +#if defined(HAVE_OPENCV_FLANN) || defined(CV_DOXYGEN) /** @brief Flann-based descriptor matcher. -This matcher trains flann::Index_ on a train descriptor collection and calls its nearest search +This matcher trains cv::flann::Index on a train descriptor collection and calls its nearest search methods to find the best matches. So, this matcher may be faster when matching a large train collection than the brute force matcher. FlannBasedMatcher does not support masking permissible matches of descriptor sets because flann::Index does not support this. : @@ -1007,27 +1132,29 @@ public: CV_WRAP FlannBasedMatcher( const Ptr& indexParams=makePtr(), const Ptr& searchParams=makePtr() ); - virtual void add( InputArrayOfArrays descriptors ); - virtual void clear(); + virtual void add( InputArrayOfArrays descriptors ) CV_OVERRIDE; + virtual void clear() CV_OVERRIDE; // Reads matcher object from a file node - virtual void read( const FileNode& ); + virtual void read( const FileNode& ) CV_OVERRIDE; // Writes matcher object to a file storage - virtual void write( FileStorage& ) const; + virtual void write( FileStorage& ) const CV_OVERRIDE; - virtual void train(); - virtual bool isMaskSupported() const; + virtual void train() CV_OVERRIDE; + virtual bool isMaskSupported() const CV_OVERRIDE; - virtual Ptr clone( bool emptyTrainData=false ) const; + CV_WRAP static Ptr create(); + + virtual Ptr clone( bool emptyTrainData=false ) const CV_OVERRIDE; protected: static void convertToDMatches( const DescriptorCollection& descriptors, const Mat& indices, const Mat& distances, std::vector >& matches ); virtual void knnMatchImpl( InputArray queryDescriptors, std::vector >& matches, int k, - InputArrayOfArrays masks=noArray(), bool compactResult=false ); + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector >& matches, float maxDistance, - InputArrayOfArrays masks=noArray(), bool compactResult=false ); + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; Ptr indexParams; Ptr searchParams; @@ -1037,6 +1164,8 @@ protected: int addedDescCount; }; +#endif + //! @} features2d_match /****************************************************************************************\ @@ -1202,8 +1331,8 @@ public: virtual ~BOWKMeansTrainer(); // Returns trained vocabulary (i.e. cluster centers). - CV_WRAP virtual Mat cluster() const; - CV_WRAP virtual Mat cluster( const Mat& descriptors ) const; + CV_WRAP virtual Mat cluster() const CV_OVERRIDE; + CV_WRAP virtual Mat cluster( const Mat& descriptors ) const CV_OVERRIDE; protected: diff --git a/include/opencv2/features2d/hal/interface.h b/include/opencv2/features2d/hal/interface.h new file mode 100644 index 0000000..bcc6577 --- /dev/null +++ b/include/opencv2/features2d/hal/interface.h @@ -0,0 +1,33 @@ +#ifndef OPENCV_FEATURE2D_HAL_INTERFACE_H +#define OPENCV_FEATURE2D_HAL_INTERFACE_H + +#include "opencv2/core/cvdef.h" +//! @addtogroup featrure2d_hal_interface +//! @{ + +//! @name Fast feature detector types +//! @sa cv::FastFeatureDetector +//! @{ +#define CV_HAL_TYPE_5_8 0 +#define CV_HAL_TYPE_7_12 1 +#define CV_HAL_TYPE_9_16 2 +//! @} + +//! @name Key point +//! @sa cv::KeyPoint +//! @{ +struct CV_EXPORTS cvhalKeyPoint +{ + float x; + float y; + float size; + float angle; + float response; + int octave; + int class_id; +}; +//! @} + +//! @} + +#endif diff --git a/include/opencv2/flann.hpp b/include/opencv2/flann.hpp index 4f92d57..fec3d06 100644 --- a/include/opencv2/flann.hpp +++ b/include/opencv2/flann.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef _OPENCV_FLANN_HPP_ -#define _OPENCV_FLANN_HPP_ +#ifndef OPENCV_FLANN_HPP +#define OPENCV_FLANN_HPP #include "opencv2/core.hpp" #include "opencv2/flann/miniflann.hpp" @@ -59,7 +59,7 @@ can be found in @cite Muja2009 . namespace cvflann { CV_EXPORTS flann_distance_t flann_distance_type(); - FLANN_DEPRECATED CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order); + CV_DEPRECATED CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order); } @@ -103,6 +103,58 @@ using ::cvflann::KL_Divergence; /** @brief The FLANN nearest neighbor index class. This class is templated with the type of elements for which the index is built. + +`Distance` functor specifies the metric to be used to calculate the distance between two points. +There are several `Distance` functors that are readily available: + +@link cvflann::L2_Simple cv::flann::L2_Simple @endlink- Squared Euclidean distance functor. +This is the simpler, unrolled version. This is preferable for very low dimensionality data (eg 3D points) + +@link cvflann::L2 cv::flann::L2 @endlink- Squared Euclidean distance functor, optimized version. + +@link cvflann::L1 cv::flann::L1 @endlink - Manhattan distance functor, optimized version. + +@link cvflann::MinkowskiDistance cv::flann::MinkowskiDistance @endlink - The Minkowsky distance functor. +This is highly optimised with loop unrolling. +The computation of squared root at the end is omitted for efficiency. + +@link cvflann::MaxDistance cv::flann::MaxDistance @endlink - The max distance functor. It computes the +maximum distance between two vectors. This distance is not a valid kdtree distance, it's not +dimensionwise additive. + +@link cvflann::HammingLUT cv::flann::HammingLUT @endlink - %Hamming distance functor. It counts the bit +differences between two strings using a lookup table implementation. + +@link cvflann::Hamming cv::flann::Hamming @endlink - %Hamming distance functor. Population count is +performed using library calls, if available. Lookup table implementation is used as a fallback. + +@link cvflann::Hamming2 cv::flann::Hamming2 @endlink- %Hamming distance functor. Population count is +implemented in 12 arithmetic operations (one of which is multiplication). + +@link cvflann::HistIntersectionDistance cv::flann::HistIntersectionDistance @endlink - The histogram +intersection distance functor. + +@link cvflann::HellingerDistance cv::flann::HellingerDistance @endlink - The Hellinger distance functor. + +@link cvflann::ChiSquareDistance cv::flann::ChiSquareDistance @endlink - The chi-square distance functor. + +@link cvflann::KL_Divergence cv::flann::KL_Divergence @endlink - The Kullback-Leibler divergence functor. + +Although the provided implementations cover a vast range of cases, it is also possible to use +a custom implementation. The distance functor is a class whose `operator()` computes the distance +between two features. If the distance is also a kd-tree compatible distance, it should also provide an +`accum_dist()` method that computes the distance between individual feature dimensions. + +In addition to `operator()` and `accum_dist()`, a distance functor should also define the +`ElementType` and the `ResultType` as the types of the elements it operates on and the type of the +result it computes. If a distance functor can be used as a kd-tree distance (meaning that the full +distance between a pair of features can be accumulated from the partial distances between the +individual dimensions) a typedef `is_kdtree_distance` should be present inside the distance functor. +If the distance is not a kd-tree distance, but it's a distance in a vector space (the individual +dimensions of the elements it operates on can be accessed independently) a typedef +`is_vector_space_distance` should be defined inside the functor. If neither typedef is defined, the +distance is assumed to be a metric distance and will only be used with indexes operating on +generic metric distances. */ template class GenericIndex @@ -217,6 +269,17 @@ public: std::vector& dists, int knn, const ::cvflann::SearchParams& params); void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params); + /** @brief Performs a radius nearest neighbor search for a given query point using the index. + + @param query The query point. + @param indices Vector that will contain the indices of the nearest neighbors found. + @param dists Vector that will contain the distances to the nearest neighbors found. It has the same + number of elements as indices. + @param radius The search radius. + @param params SearchParams + + This function returns the number of nearest neighbors found. + */ int radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& params); int radiusSearch(const Mat& query, Mat& indices, Mat& dists, @@ -230,7 +293,7 @@ public: ::cvflann::IndexParams getParameters() { return nnIndex->getParameters(); } - FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); } + CV_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); } private: ::cvflann::Index* nnIndex; @@ -338,164 +401,134 @@ int GenericIndex::radiusSearch(const Mat& query, Mat& indices, Mat& di * @deprecated Use GenericIndex class instead */ template -class -#ifndef _MSC_VER - FLANN_DEPRECATED -#endif - Index_ { +class Index_ +{ public: - typedef typename L2::ElementType ElementType; - typedef typename L2::ResultType DistanceType; + typedef typename L2::ElementType ElementType; + typedef typename L2::ResultType DistanceType; - Index_(const Mat& features, const ::cvflann::IndexParams& params); - - ~Index_(); - - void knnSearch(const std::vector& query, std::vector& indices, std::vector& dists, int knn, const ::cvflann::SearchParams& params); - void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params); - - int radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& params); - int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& params); - - void save(String filename) - { - if (nnIndex_L1) nnIndex_L1->save(filename); - if (nnIndex_L2) nnIndex_L2->save(filename); - } - - int veclen() const + CV_DEPRECATED Index_(const Mat& dataset, const ::cvflann::IndexParams& params) { - if (nnIndex_L1) return nnIndex_L1->veclen(); - if (nnIndex_L2) return nnIndex_L2->veclen(); - } + printf("[WARNING] The cv::flann::Index_ class is deperecated, use cv::flann::GenericIndex instead\n"); - int size() const + CV_Assert(dataset.type() == CvType::type()); + CV_Assert(dataset.isContinuous()); + ::cvflann::Matrix m_dataset((ElementType*)dataset.ptr(0), dataset.rows, dataset.cols); + + if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) { + nnIndex_L1 = NULL; + nnIndex_L2 = new ::cvflann::Index< L2 >(m_dataset, params); + } + else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) { + nnIndex_L1 = new ::cvflann::Index< L1 >(m_dataset, params); + nnIndex_L2 = NULL; + } + else { + printf("[ERROR] cv::flann::Index_ only provides backwards compatibility for the L1 and L2 distances. " + "For other distance types you must use cv::flann::GenericIndex\n"); + CV_Assert(0); + } + if (nnIndex_L1) nnIndex_L1->buildIndex(); + if (nnIndex_L2) nnIndex_L2->buildIndex(); + } + CV_DEPRECATED ~Index_() { - if (nnIndex_L1) return nnIndex_L1->size(); - if (nnIndex_L2) return nnIndex_L2->size(); - } + if (nnIndex_L1) delete nnIndex_L1; + if (nnIndex_L2) delete nnIndex_L2; + } - ::cvflann::IndexParams getParameters() - { - if (nnIndex_L1) return nnIndex_L1->getParameters(); - if (nnIndex_L2) return nnIndex_L2->getParameters(); + CV_DEPRECATED void knnSearch(const std::vector& query, std::vector& indices, std::vector& dists, int knn, const ::cvflann::SearchParams& searchParams) + { + ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); + ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); + ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); - } + if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams); + if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams); + } + CV_DEPRECATED void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams) + { + CV_Assert(queries.type() == CvType::type()); + CV_Assert(queries.isContinuous()); + ::cvflann::Matrix m_queries((ElementType*)queries.ptr(0), queries.rows, queries.cols); - FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() - { - if (nnIndex_L1) return nnIndex_L1->getIndexParameters(); - if (nnIndex_L2) return nnIndex_L2->getIndexParameters(); - } + CV_Assert(indices.type() == CV_32S); + CV_Assert(indices.isContinuous()); + ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); + + CV_Assert(dists.type() == CvType::type()); + CV_Assert(dists.isContinuous()); + ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); + + if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); + if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); + } + + CV_DEPRECATED int radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) + { + ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); + ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); + ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); + + if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + } + + CV_DEPRECATED int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) + { + CV_Assert(query.type() == CvType::type()); + CV_Assert(query.isContinuous()); + ::cvflann::Matrix m_query((ElementType*)query.ptr(0), query.rows, query.cols); + + CV_Assert(indices.type() == CV_32S); + CV_Assert(indices.isContinuous()); + ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); + + CV_Assert(dists.type() == CvType::type()); + CV_Assert(dists.isContinuous()); + ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); + + if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + } + + CV_DEPRECATED void save(String filename) + { + if (nnIndex_L1) nnIndex_L1->save(filename); + if (nnIndex_L2) nnIndex_L2->save(filename); + } + + CV_DEPRECATED int veclen() const + { + if (nnIndex_L1) return nnIndex_L1->veclen(); + if (nnIndex_L2) return nnIndex_L2->veclen(); + } + + CV_DEPRECATED int size() const + { + if (nnIndex_L1) return nnIndex_L1->size(); + if (nnIndex_L2) return nnIndex_L2->size(); + } + + CV_DEPRECATED ::cvflann::IndexParams getParameters() + { + if (nnIndex_L1) return nnIndex_L1->getParameters(); + if (nnIndex_L2) return nnIndex_L2->getParameters(); + + } + + CV_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() + { + if (nnIndex_L1) return nnIndex_L1->getIndexParameters(); + if (nnIndex_L2) return nnIndex_L2->getIndexParameters(); + } private: - // providing backwards compatibility for L2 and L1 distances (most common) - ::cvflann::Index< L2 >* nnIndex_L2; - ::cvflann::Index< L1 >* nnIndex_L1; + // providing backwards compatibility for L2 and L1 distances (most common) + ::cvflann::Index< L2 >* nnIndex_L2; + ::cvflann::Index< L1 >* nnIndex_L1; }; -#ifdef _MSC_VER -template -class FLANN_DEPRECATED Index_; -#endif - -//! @cond IGNORED - -template -Index_::Index_(const Mat& dataset, const ::cvflann::IndexParams& params) -{ - printf("[WARNING] The cv::flann::Index_ class is deperecated, use cv::flann::GenericIndex instead\n"); - - CV_Assert(dataset.type() == CvType::type()); - CV_Assert(dataset.isContinuous()); - ::cvflann::Matrix m_dataset((ElementType*)dataset.ptr(0), dataset.rows, dataset.cols); - - if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) { - nnIndex_L1 = NULL; - nnIndex_L2 = new ::cvflann::Index< L2 >(m_dataset, params); - } - else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) { - nnIndex_L1 = new ::cvflann::Index< L1 >(m_dataset, params); - nnIndex_L2 = NULL; - } - else { - printf("[ERROR] cv::flann::Index_ only provides backwards compatibility for the L1 and L2 distances. " - "For other distance types you must use cv::flann::GenericIndex\n"); - CV_Assert(0); - } - if (nnIndex_L1) nnIndex_L1->buildIndex(); - if (nnIndex_L2) nnIndex_L2->buildIndex(); -} - -template -Index_::~Index_() -{ - if (nnIndex_L1) delete nnIndex_L1; - if (nnIndex_L2) delete nnIndex_L2; -} - -template -void Index_::knnSearch(const std::vector& query, std::vector& indices, std::vector& dists, int knn, const ::cvflann::SearchParams& searchParams) -{ - ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); - ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); - ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); - - if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams); - if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams); -} - - -template -void Index_::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams) -{ - CV_Assert(queries.type() == CvType::type()); - CV_Assert(queries.isContinuous()); - ::cvflann::Matrix m_queries((ElementType*)queries.ptr(0), queries.rows, queries.cols); - - CV_Assert(indices.type() == CV_32S); - CV_Assert(indices.isContinuous()); - ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); - - CV_Assert(dists.type() == CvType::type()); - CV_Assert(dists.isContinuous()); - ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); - - if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); - if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); -} - -template -int Index_::radiusSearch(const std::vector& query, std::vector& indices, std::vector& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) -{ - ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); - ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); - ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); - - if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); - if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); -} - -template -int Index_::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) -{ - CV_Assert(query.type() == CvType::type()); - CV_Assert(query.isContinuous()); - ::cvflann::Matrix m_query((ElementType*)query.ptr(0), query.rows, query.cols); - - CV_Assert(indices.type() == CV_32S); - CV_Assert(indices.isContinuous()); - ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); - - CV_Assert(dists.type() == CvType::type()); - CV_Assert(dists.isContinuous()); - ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); - - if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); - if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); -} - -//! @endcond /** @brief Clusters features using hierarchical k-means algorithm. @@ -535,7 +568,7 @@ int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::K /** @deprecated */ template -FLANN_DEPRECATED int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params) +CV_DEPRECATED int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::KMeansIndexParams& params) { printf("[WARNING] cv::flann::hierarchicalClustering is deprecated, use " "cv::flann::hierarchicalClustering instead\n"); diff --git a/include/opencv2/flann/allocator.h b/include/opencv2/flann/allocator.h index 26091d0..f347f88 100644 --- a/include/opencv2/flann/allocator.h +++ b/include/opencv2/flann/allocator.h @@ -97,6 +97,7 @@ public: blocksize = blockSize; remaining = 0; base = NULL; + loc = NULL; usedMemory = 0; wastedMemory = 0; @@ -181,6 +182,9 @@ public: return mem; } +private: + PooledAllocator(const PooledAllocator &); // copy disabled + PooledAllocator& operator=(const PooledAllocator &); // assign disabled }; } diff --git a/include/opencv2/flann/any.h b/include/opencv2/flann/any.h index 8c2edaa..5b57aa3 100644 --- a/include/opencv2/flann/any.h +++ b/include/opencv2/flann/any.h @@ -54,49 +54,50 @@ struct base_any_policy template struct typed_base_any_policy : base_any_policy { - virtual ::size_t get_size() { return sizeof(T); } - virtual const std::type_info& type() { return typeid(T); } + virtual ::size_t get_size() CV_OVERRIDE { return sizeof(T); } + virtual const std::type_info& type() CV_OVERRIDE { return typeid(T); } }; template -struct small_any_policy : typed_base_any_policy +struct small_any_policy CV_FINAL : typed_base_any_policy { - virtual void static_delete(void**) { } - virtual void copy_from_value(void const* src, void** dest) + virtual void static_delete(void**) CV_OVERRIDE { } + virtual void copy_from_value(void const* src, void** dest) CV_OVERRIDE { new (dest) T(* reinterpret_cast(src)); } - virtual void clone(void* const* src, void** dest) { *dest = *src; } - virtual void move(void* const* src, void** dest) { *dest = *src; } - virtual void* get_value(void** src) { return reinterpret_cast(src); } - virtual const void* get_value(void* const * src) { return reinterpret_cast(src); } - virtual void print(std::ostream& out, void* const* src) { out << *reinterpret_cast(src); } + virtual void clone(void* const* src, void** dest) CV_OVERRIDE { *dest = *src; } + virtual void move(void* const* src, void** dest) CV_OVERRIDE { *dest = *src; } + virtual void* get_value(void** src) CV_OVERRIDE { return reinterpret_cast(src); } + virtual const void* get_value(void* const * src) CV_OVERRIDE { return reinterpret_cast(src); } + virtual void print(std::ostream& out, void* const* src) CV_OVERRIDE { out << *reinterpret_cast(src); } }; template -struct big_any_policy : typed_base_any_policy +struct big_any_policy CV_FINAL : typed_base_any_policy { - virtual void static_delete(void** x) + virtual void static_delete(void** x) CV_OVERRIDE { - if (* x) delete (* reinterpret_cast(x)); *x = NULL; + if (* x) delete (* reinterpret_cast(x)); + *x = NULL; } - virtual void copy_from_value(void const* src, void** dest) + virtual void copy_from_value(void const* src, void** dest) CV_OVERRIDE { *dest = new T(*reinterpret_cast(src)); } - virtual void clone(void* const* src, void** dest) + virtual void clone(void* const* src, void** dest) CV_OVERRIDE { *dest = new T(**reinterpret_cast(src)); } - virtual void move(void* const* src, void** dest) + virtual void move(void* const* src, void** dest) CV_OVERRIDE { (*reinterpret_cast(dest))->~T(); **reinterpret_cast(dest) = **reinterpret_cast(src); } - virtual void* get_value(void** src) { return *src; } - virtual const void* get_value(void* const * src) { return *src; } - virtual void print(std::ostream& out, void* const* src) { out << *reinterpret_cast(*src); } + virtual void* get_value(void** src) CV_OVERRIDE { return *src; } + virtual const void* get_value(void* const * src) CV_OVERRIDE { return *src; } + virtual void print(std::ostream& out, void* const* src) CV_OVERRIDE { out << *reinterpret_cast(*src); } }; template<> inline void big_any_policy::print(std::ostream& out, void* const* src) @@ -245,6 +246,12 @@ public: return assign(x); } + /// Assignment operator. Template-based version above doesn't work as expected. We need regular assignment operator here. + any& operator=(const any& x) + { + return assign(x); + } + /// Assignment operator, specialed for literal strings. /// They have types like const char [6] which don't work as expected. any& operator=(const char* x) diff --git a/include/opencv2/flann/autotuned_index.h b/include/opencv2/flann/autotuned_index.h index 0670d19..2fbc6c9 100644 --- a/include/opencv2/flann/autotuned_index.h +++ b/include/opencv2/flann/autotuned_index.h @@ -30,6 +30,8 @@ #ifndef OPENCV_FLANN_AUTOTUNED_INDEX_H_ #define OPENCV_FLANN_AUTOTUNED_INDEX_H_ +#include + #include "general.h" #include "nn_index.h" #include "ground_truth.h" @@ -81,6 +83,7 @@ public: memory_weight_ = get_param(params, "memory_weight", 0.0f); sample_fraction_ = get_param(params,"sample_fraction", 0.1f); bestIndex_ = NULL; + speedup_ = 0; } AutotunedIndex(const AutotunedIndex&); @@ -97,7 +100,7 @@ public: /** * Method responsible with building the index. */ - virtual void buildIndex() + virtual void buildIndex() CV_OVERRIDE { std::ostringstream stream; bestParams_ = estimateBuildParams(); @@ -121,7 +124,7 @@ public: /** * Saves the index to a stream */ - virtual void saveIndex(FILE* stream) + virtual void saveIndex(FILE* stream) CV_OVERRIDE { save_value(stream, (int)bestIndex_->getType()); bestIndex_->saveIndex(stream); @@ -131,7 +134,7 @@ public: /** * Loads the index from a stream */ - virtual void loadIndex(FILE* stream) + virtual void loadIndex(FILE* stream) CV_OVERRIDE { int index_type; @@ -148,7 +151,7 @@ public: /** * Method that searches for nearest-neighbors */ - virtual void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + virtual void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE { int checks = get_param(searchParams,"checks",FLANN_CHECKS_AUTOTUNED); if (checks == FLANN_CHECKS_AUTOTUNED) { @@ -160,7 +163,7 @@ public: } - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return bestIndex_->getParameters(); } @@ -179,7 +182,7 @@ public: /** * Number of features in this index. */ - virtual size_t size() const + virtual size_t size() const CV_OVERRIDE { return bestIndex_->size(); } @@ -187,7 +190,7 @@ public: /** * The length of each vector in this index. */ - virtual size_t veclen() const + virtual size_t veclen() const CV_OVERRIDE { return bestIndex_->veclen(); } @@ -195,7 +198,7 @@ public: /** * The amount of memory (in bytes) this index uses. */ - virtual int usedMemory() const + virtual int usedMemory() const CV_OVERRIDE { return bestIndex_->usedMemory(); } @@ -203,7 +206,7 @@ public: /** * Algorithm name */ - virtual flann_algorithm_t getType() const + virtual flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_AUTOTUNED; } @@ -377,6 +380,7 @@ private: // evaluate kdtree for all parameter combinations for (size_t i = 0; i < FLANN_ARRAY_LEN(testTrees); ++i) { CostData cost; + cost.params["algorithm"] = FLANN_INDEX_KDTREE; cost.params["trees"] = testTrees[i]; evaluate_kdtree(cost); diff --git a/include/opencv2/flann/composite_index.h b/include/opencv2/flann/composite_index.h index 527ca1a..5e12a17 100644 --- a/include/opencv2/flann/composite_index.h +++ b/include/opencv2/flann/composite_index.h @@ -101,7 +101,7 @@ public: /** * @return The index type */ - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_COMPOSITE; } @@ -109,7 +109,7 @@ public: /** * @return Size of the index */ - size_t size() const + size_t size() const CV_OVERRIDE { return kdtree_index_->size(); } @@ -117,7 +117,7 @@ public: /** * \returns The dimensionality of the features in this index. */ - size_t veclen() const + size_t veclen() const CV_OVERRIDE { return kdtree_index_->veclen(); } @@ -125,7 +125,7 @@ public: /** * \returns The amount of memory (in bytes) used by the index. */ - int usedMemory() const + int usedMemory() const CV_OVERRIDE { return kmeans_index_->usedMemory() + kdtree_index_->usedMemory(); } @@ -133,7 +133,7 @@ public: /** * \brief Builds the index */ - void buildIndex() + void buildIndex() CV_OVERRIDE { Logger::info("Building kmeans tree...\n"); kmeans_index_->buildIndex(); @@ -145,7 +145,7 @@ public: * \brief Saves the index to a stream * \param stream The stream to save the index to */ - void saveIndex(FILE* stream) + void saveIndex(FILE* stream) CV_OVERRIDE { kmeans_index_->saveIndex(stream); kdtree_index_->saveIndex(stream); @@ -155,7 +155,7 @@ public: * \brief Loads the index from a stream * \param stream The stream from which the index is loaded */ - void loadIndex(FILE* stream) + void loadIndex(FILE* stream) CV_OVERRIDE { kmeans_index_->loadIndex(stream); kdtree_index_->loadIndex(stream); @@ -164,7 +164,7 @@ public: /** * \returns The index parameters */ - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return index_params_; } @@ -172,7 +172,7 @@ public: /** * \brief Method that searches for nearest-neighbours */ - void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE { kmeans_index_->findNeighbors(result, vec, searchParams); kdtree_index_->findNeighbors(result, vec, searchParams); diff --git a/include/opencv2/flann/defines.h b/include/opencv2/flann/defines.h index f0264f7..6fd53c2 100644 --- a/include/opencv2/flann/defines.h +++ b/include/opencv2/flann/defines.h @@ -35,7 +35,7 @@ #ifdef FLANN_EXPORT #undef FLANN_EXPORT #endif -#ifdef WIN32 +#ifdef _WIN32 /* win32 dll export/import directives */ #ifdef FLANN_EXPORTS #define FLANN_EXPORT __declspec(dllexport) @@ -50,19 +50,6 @@ #endif -#ifdef FLANN_DEPRECATED -#undef FLANN_DEPRECATED -#endif -#ifdef __GNUC__ -#define FLANN_DEPRECATED __attribute__ ((deprecated)) -#elif defined(_MSC_VER) -#define FLANN_DEPRECATED __declspec(deprecated) -#else -#pragma message("WARNING: You need to implement FLANN_DEPRECATED for this compiler") -#define FLANN_DEPRECATED -#endif - - #undef FLANN_PLATFORM_32_BIT #undef FLANN_PLATFORM_64_BIT #if defined __amd64__ || defined __x86_64__ || defined _WIN64 || defined _M_X64 diff --git a/include/opencv2/flann/dist.h b/include/opencv2/flann/dist.h index 9dbe527..a65e712 100644 --- a/include/opencv2/flann/dist.h +++ b/include/opencv2/flann/dist.h @@ -43,7 +43,7 @@ typedef unsigned __int64 uint64_t; #include "defines.h" -#if (defined WIN32 || defined _WIN32) && defined(_M_ARM) +#if defined _WIN32 && defined(_M_ARM) # include #endif @@ -462,10 +462,9 @@ struct Hamming } } #else // NO NEON and NOT GNUC - typedef unsigned long long pop_t; HammingLUT lut; result = lut(reinterpret_cast (a), - reinterpret_cast (b), size * sizeof(pop_t)); + reinterpret_cast (b), size); #endif return result; } @@ -698,7 +697,7 @@ struct KL_Divergence typedef typename Accumulator::Type ResultType; /** - * Compute the Kullback–Leibler divergence + * Compute the Kullback-Leibler divergence */ template ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const @@ -843,7 +842,7 @@ typename Distance::ResultType ensureSquareDistance( typename Distance::ResultTyp /* * ...and a template to ensure the user that he will process the normal distance, - * and not squared distance, without loosing processing time calling sqrt(ensureSquareDistance) + * and not squared distance, without losing processing time calling sqrt(ensureSquareDistance) * that will result in doing actually sqrt(dist*dist) for L1 distance for instance. */ template diff --git a/include/opencv2/flann/dummy.h b/include/opencv2/flann/dummy.h index 26bd3fa..d6837e5 100644 --- a/include/opencv2/flann/dummy.h +++ b/include/opencv2/flann/dummy.h @@ -5,10 +5,7 @@ namespace cvflann { -#if (defined WIN32 || defined _WIN32 || defined WINCE) && defined CVAPI_EXPORTS -__declspec(dllexport) -#endif -void dummyfunc(); +CV_DEPRECATED inline void dummyfunc() {} } diff --git a/include/opencv2/flann/dynamic_bitset.h b/include/opencv2/flann/dynamic_bitset.h index d795b5d..923b658 100644 --- a/include/opencv2/flann/dynamic_bitset.h +++ b/include/opencv2/flann/dynamic_bitset.h @@ -59,7 +59,7 @@ class DynamicBitset public: /** default constructor */ - DynamicBitset() + DynamicBitset() : size_(0) { } diff --git a/include/opencv2/flann/flann_base.hpp b/include/opencv2/flann/flann_base.hpp index 98c33cf..0ffb857 100644 --- a/include/opencv2/flann/flann_base.hpp +++ b/include/opencv2/flann/flann_base.hpp @@ -80,9 +80,11 @@ NNIndex* load_saved_index(const Matrix } IndexHeader header = load_header(fin); if (header.data_type != Datatype::type()) { + fclose(fin); throw FLANNException("Datatype of saved index is different than of the one to be created."); } if ((size_t(header.rows) != dataset.rows)||(size_t(header.cols) != dataset.cols)) { + fclose(fin); throw FLANNException("The index saved belongs to a different dataset"); } @@ -126,7 +128,7 @@ public: /** * Builds the index. */ - void buildIndex() + void buildIndex() CV_OVERRIDE { if (!loaded_) { nnIndex_->buildIndex(); @@ -148,7 +150,7 @@ public: * \brief Saves the index to a stream * \param stream The stream to save the index to */ - virtual void saveIndex(FILE* stream) + virtual void saveIndex(FILE* stream) CV_OVERRIDE { nnIndex_->saveIndex(stream); } @@ -157,7 +159,7 @@ public: * \brief Loads the index from a stream * \param stream The stream from which the index is loaded */ - virtual void loadIndex(FILE* stream) + virtual void loadIndex(FILE* stream) CV_OVERRIDE { nnIndex_->loadIndex(stream); } @@ -165,7 +167,7 @@ public: /** * \returns number of features in this index. */ - size_t veclen() const + size_t veclen() const CV_OVERRIDE { return nnIndex_->veclen(); } @@ -173,7 +175,7 @@ public: /** * \returns The dimensionality of the features in this index. */ - size_t size() const + size_t size() const CV_OVERRIDE { return nnIndex_->size(); } @@ -181,7 +183,7 @@ public: /** * \returns The index type (kdtree, kmeans,...) */ - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return nnIndex_->getType(); } @@ -189,7 +191,7 @@ public: /** * \returns The amount of memory (in bytes) used by the index. */ - virtual int usedMemory() const + virtual int usedMemory() const CV_OVERRIDE { return nnIndex_->usedMemory(); } @@ -198,7 +200,7 @@ public: /** * \returns The index parameters */ - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return nnIndex_->getParameters(); } @@ -211,7 +213,7 @@ public: * \param[in] knn Number of nearest neighbors to return * \param[in] params Search parameters */ - void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) + void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) CV_OVERRIDE { nnIndex_->knnSearch(queries, indices, dists, knn, params); } @@ -225,7 +227,7 @@ public: * \param[in] params Search parameters * \returns Number of neighbors found */ - int radiusSearch(const Matrix& query, Matrix& indices, Matrix& dists, float radius, const SearchParams& params) + int radiusSearch(const Matrix& query, Matrix& indices, Matrix& dists, float radius, const SearchParams& params) CV_OVERRIDE { return nnIndex_->radiusSearch(query, indices, dists, radius, params); } @@ -233,7 +235,7 @@ public: /** * \brief Method that searches for nearest-neighbours */ - void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE { nnIndex_->findNeighbors(result, vec, searchParams); } @@ -241,7 +243,7 @@ public: /** * \brief Returns actual index */ - FLANN_DEPRECATED NNIndex* getIndex() + CV_DEPRECATED NNIndex* getIndex() { return nnIndex_; } @@ -250,7 +252,7 @@ public: * \brief Returns index parameters. * \deprecated use getParameters() instead. */ - FLANN_DEPRECATED const IndexParams* getIndexParameters() + CV_DEPRECATED const IndexParams* getIndexParameters() { return &index_params_; } @@ -262,6 +264,9 @@ private: bool loaded_; /** Parameters passed to the index */ IndexParams index_params_; + + Index(const Index &); // copy disabled + Index& operator=(const Index &); // assign disabled }; /** diff --git a/include/opencv2/flann/hierarchical_clustering_index.h b/include/opencv2/flann/hierarchical_clustering_index.h index 9d890d4..2a947da 100644 --- a/include/opencv2/flann/hierarchical_clustering_index.h +++ b/include/opencv2/flann/hierarchical_clustering_index.h @@ -435,7 +435,7 @@ public: /** * Returns size of index. */ - size_t size() const + size_t size() const CV_OVERRIDE { return size_; } @@ -443,7 +443,7 @@ public: /** * Returns the length of an index feature. */ - size_t veclen() const + size_t veclen() const CV_OVERRIDE { return veclen_; } @@ -453,7 +453,7 @@ public: * Computes the inde memory usage * Returns: memory used by the index */ - int usedMemory() const + int usedMemory() const CV_OVERRIDE { return pool.usedMemory+pool.wastedMemory+memoryCounter; } @@ -461,7 +461,7 @@ public: /** * Builds the index */ - void buildIndex() + void buildIndex() CV_OVERRIDE { if (branching_<2) { throw FLANNException("Branching factor must be at least 2"); @@ -480,13 +480,13 @@ public: } - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_HIERARCHICAL; } - void saveIndex(FILE* stream) + void saveIndex(FILE* stream) CV_OVERRIDE { save_value(stream, branching_); save_value(stream, trees_); @@ -501,7 +501,7 @@ public: } - void loadIndex(FILE* stream) + void loadIndex(FILE* stream) CV_OVERRIDE { free_elements(); @@ -544,7 +544,7 @@ public: * vec = the vector for which to search the nearest neighbors * searchParams = parameters that influence the search algorithm (checks) */ - void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE { int maxChecks = get_param(searchParams,"checks",32); @@ -569,7 +569,7 @@ public: } - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return params; } diff --git a/include/opencv2/flann/kdtree_index.h b/include/opencv2/flann/kdtree_index.h index dc0971c..c233515 100644 --- a/include/opencv2/flann/kdtree_index.h +++ b/include/opencv2/flann/kdtree_index.h @@ -120,24 +120,29 @@ public: /** * Builds the index */ - void buildIndex() + void buildIndex() CV_OVERRIDE { /* Construct the randomized trees. */ for (int i = 0; i < trees_; i++) { /* Randomize the order of vectors to allow for unbiased sampling. */ +#ifndef OPENCV_FLANN_USE_STD_RAND + cv::randShuffle(vind_); +#else std::random_shuffle(vind_.begin(), vind_.end()); +#endif + tree_roots_[i] = divideTree(&vind_[0], int(size_) ); } } - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_KDTREE; } - void saveIndex(FILE* stream) + void saveIndex(FILE* stream) CV_OVERRIDE { save_value(stream, trees_); for (int i=0; i& result, const ElementType* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE { int maxChecks = get_param(searchParams,"checks", 32); float epsError = 1+get_param(searchParams,"eps",0.0f); @@ -209,7 +214,7 @@ public: } } - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return index_params_; } diff --git a/include/opencv2/flann/kdtree_single_index.h b/include/opencv2/flann/kdtree_single_index.h index 30488ad..22a28d0 100644 --- a/include/opencv2/flann/kdtree_single_index.h +++ b/include/opencv2/flann/kdtree_single_index.h @@ -87,6 +87,7 @@ public: { size_ = dataset_.rows; dim_ = dataset_.cols; + root_node_ = 0; int dim_param = get_param(params,"dim",-1); if (dim_param>0) dim_ = dim_param; leaf_max_size_ = get_param(params,"leaf_max_size",10); @@ -113,7 +114,7 @@ public: /** * Builds the index */ - void buildIndex() + void buildIndex() CV_OVERRIDE { computeBoundingBox(root_bbox_); root_node_ = divideTree(0, (int)size_, root_bbox_ ); // construct the tree @@ -132,13 +133,13 @@ public: } } - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_KDTREE_SINGLE; } - void saveIndex(FILE* stream) + void saveIndex(FILE* stream) CV_OVERRIDE { save_value(stream, size_); save_value(stream, dim_); @@ -153,7 +154,7 @@ public: } - void loadIndex(FILE* stream) + void loadIndex(FILE* stream) CV_OVERRIDE { load_value(stream, size_); load_value(stream, dim_); @@ -178,7 +179,7 @@ public: /** * Returns size of index. */ - size_t size() const + size_t size() const CV_OVERRIDE { return size_; } @@ -186,7 +187,7 @@ public: /** * Returns the length of an index feature. */ - size_t veclen() const + size_t veclen() const CV_OVERRIDE { return dim_; } @@ -195,7 +196,7 @@ public: * Computes the inde memory usage * Returns: memory used by the index */ - int usedMemory() const + int usedMemory() const CV_OVERRIDE { return (int)(pool_.usedMemory+pool_.wastedMemory+dataset_.rows*sizeof(int)); // pool memory and vind array memory } @@ -209,7 +210,7 @@ public: * \param[in] knn Number of nearest neighbors to return * \param[in] params Search parameters */ - void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) + void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) CV_OVERRIDE { assert(queries.cols == veclen()); assert(indices.rows >= queries.rows); @@ -224,7 +225,7 @@ public: } } - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return index_params_; } @@ -238,7 +239,7 @@ public: * vec = the vector for which to search the nearest neighbors * maxCheck = the maximum number of restarts (in a best-bin-first manner) */ - void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE { float epsError = 1+get_param(searchParams,"eps",0.0f); diff --git a/include/opencv2/flann/kmeans_index.h b/include/opencv2/flann/kmeans_index.h index b49b8dd..74bbf40 100644 --- a/include/opencv2/flann/kmeans_index.h +++ b/include/opencv2/flann/kmeans_index.h @@ -266,7 +266,7 @@ public: public: - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_KMEANS; } @@ -276,7 +276,7 @@ public: public: KMeansDistanceComputer(Distance _distance, const Matrix& _dataset, const int _branching, const int* _indices, const Matrix& _dcenters, const size_t _veclen, - int* _count, int* _belongs_to, std::vector& _radiuses, bool& _converged, cv::Mutex& _mtx) + int* _count, int* _belongs_to, std::vector& _radiuses, bool& _converged) : distance(_distance) , dataset(_dataset) , branching(_branching) @@ -287,11 +287,10 @@ public: , belongs_to(_belongs_to) , radiuses(_radiuses) , converged(_converged) - , mtx(_mtx) { } - void operator()(const cv::Range& range) const + void operator()(const cv::Range& range) const CV_OVERRIDE { const int begin = range.start; const int end = range.end; @@ -311,12 +310,10 @@ public: radiuses[new_centroid] = sq_dist; } if (new_centroid != belongs_to[i]) { - count[belongs_to[i]]--; - count[new_centroid]++; + CV_XADD(&count[belongs_to[i]], -1); + CV_XADD(&count[new_centroid], 1); belongs_to[i] = new_centroid; - mtx.lock(); converged = false; - mtx.unlock(); } } } @@ -332,7 +329,6 @@ public: int* belongs_to; std::vector& radiuses; bool& converged; - cv::Mutex& mtx; KMeansDistanceComputer& operator=( const KMeansDistanceComputer & ) { return *this; } }; @@ -398,7 +394,7 @@ public: /** * Returns size of index. */ - size_t size() const + size_t size() const CV_OVERRIDE { return size_; } @@ -406,7 +402,7 @@ public: /** * Returns the length of an index feature. */ - size_t veclen() const + size_t veclen() const CV_OVERRIDE { return veclen_; } @@ -421,7 +417,7 @@ public: * Computes the inde memory usage * Returns: memory used by the index */ - int usedMemory() const + int usedMemory() const CV_OVERRIDE { return pool_.usedMemory+pool_.wastedMemory+memoryCounter_; } @@ -429,7 +425,7 @@ public: /** * Builds the index */ - void buildIndex() + void buildIndex() CV_OVERRIDE { if (branching_<2) { throw FLANNException("Branching factor must be at least 2"); @@ -441,12 +437,14 @@ public: } root_ = pool_.allocate(); + std::memset(root_, 0, sizeof(KMeansNode)); + computeNodeStatistics(root_, indices_, (int)size_); computeClustering(root_, indices_, (int)size_, branching_,0); } - void saveIndex(FILE* stream) + void saveIndex(FILE* stream) CV_OVERRIDE { save_value(stream, branching_); save_value(stream, iterations_); @@ -458,7 +456,7 @@ public: } - void loadIndex(FILE* stream) + void loadIndex(FILE* stream) CV_OVERRIDE { load_value(stream, branching_); load_value(stream, iterations_); @@ -493,7 +491,7 @@ public: * vec = the vector for which to search the nearest neighbors * searchParams = parameters that influence the search algorithm (checks, cb_index) */ - void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE { int maxChecks = get_param(searchParams,"checks",32); @@ -552,7 +550,7 @@ public: return clusterCount; } - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return index_params_; } @@ -724,7 +722,7 @@ private: } cv::AutoBuffer centers_idx_buf(branching); - int* centers_idx = (int*)centers_idx_buf; + int* centers_idx = centers_idx_buf.data(); int centers_length; (this->*chooseCenters)(branching, indices, indices_length, centers_idx, centers_length); @@ -737,7 +735,7 @@ private: cv::AutoBuffer dcenters_buf(branching*veclen_); - Matrix dcenters((double*)dcenters_buf,branching,veclen_); + Matrix dcenters(dcenters_buf.data(), branching, veclen_); for (int i=0; i radiuses(branching); cv::AutoBuffer count_buf(branching); - int* count = (int*)count_buf; + int* count = count_buf.data(); for (int i=0; i belongs_to_buf(indices_length); - int* belongs_to = (int*)belongs_to_buf; + int* belongs_to = belongs_to_buf.data(); for (int i=0; i(), veclen_); node->childs[c] = pool_.allocate(); + std::memset(node->childs[c], 0, sizeof(KMeansNode)); node->childs[c]->radius = radiuses[c]; node->childs[c]->pivot = centers[c]; node->childs[c]->variance = variance; node->childs[c]->mean_radius = mean_radius; - node->childs[c]->indices = NULL; computeClustering(node->childs[c],indices+start, end-start, branching, level+1); start=end; } + + delete[] centers; } @@ -1049,7 +1048,7 @@ private: /** - * Helper function the descends in the hierarchical k-means tree by spliting those clusters that minimize + * Helper function the descends in the hierarchical k-means tree by splitting those clusters that minimize * the overall variance of the clustering. * Params: * root = root node diff --git a/include/opencv2/flann/linear_index.h b/include/opencv2/flann/linear_index.h index 5aa7a5c..ca3f44d 100644 --- a/include/opencv2/flann/linear_index.h +++ b/include/opencv2/flann/linear_index.h @@ -63,47 +63,47 @@ public: LinearIndex(const LinearIndex&); LinearIndex& operator=(const LinearIndex&); - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_LINEAR; } - size_t size() const + size_t size() const CV_OVERRIDE { return dataset_.rows; } - size_t veclen() const + size_t veclen() const CV_OVERRIDE { return dataset_.cols; } - int usedMemory() const + int usedMemory() const CV_OVERRIDE { return 0; } - void buildIndex() + void buildIndex() CV_OVERRIDE { /* nothing to do here for linear search */ } - void saveIndex(FILE*) + void saveIndex(FILE*) CV_OVERRIDE { /* nothing to do here for linear search */ } - void loadIndex(FILE*) + void loadIndex(FILE*) CV_OVERRIDE { /* nothing to do here for linear search */ index_params_["algorithm"] = getType(); } - void findNeighbors(ResultSet& resultSet, const ElementType* vec, const SearchParams& /*searchParams*/) + void findNeighbors(ResultSet& resultSet, const ElementType* vec, const SearchParams& /*searchParams*/) CV_OVERRIDE { ElementType* data = dataset_.data; for (size_t i = 0; i < dataset_.rows; ++i, data += dataset_.cols) { @@ -112,7 +112,7 @@ public: } } - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return index_params_; } diff --git a/include/opencv2/flann/logger.h b/include/opencv2/flann/logger.h index 24f3fb6..32618db 100644 --- a/include/opencv2/flann/logger.h +++ b/include/opencv2/flann/logger.h @@ -63,7 +63,12 @@ class Logger stream = stdout; } else { +#ifdef _MSC_VER + if (fopen_s(&stream, name, "w") != 0) + stream = NULL; +#else stream = fopen(name,"w"); +#endif if (stream == NULL) { stream = stdout; } diff --git a/include/opencv2/flann/lsh_index.h b/include/opencv2/flann/lsh_index.h index 4d4670e..42afe89 100644 --- a/include/opencv2/flann/lsh_index.h +++ b/include/opencv2/flann/lsh_index.h @@ -107,7 +107,7 @@ public: /** * Builds the index */ - void buildIndex() + void buildIndex() CV_OVERRIDE { tables_.resize(table_number_); for (unsigned int i = 0; i < table_number_; ++i) { @@ -119,13 +119,13 @@ public: } } - flann_algorithm_t getType() const + flann_algorithm_t getType() const CV_OVERRIDE { return FLANN_INDEX_LSH; } - void saveIndex(FILE* stream) + void saveIndex(FILE* stream) CV_OVERRIDE { save_value(stream,table_number_); save_value(stream,key_size_); @@ -133,7 +133,7 @@ public: save_value(stream, dataset_); } - void loadIndex(FILE* stream) + void loadIndex(FILE* stream) CV_OVERRIDE { load_value(stream, table_number_); load_value(stream, key_size_); @@ -151,7 +151,7 @@ public: /** * Returns size of index. */ - size_t size() const + size_t size() const CV_OVERRIDE { return dataset_.rows; } @@ -159,7 +159,7 @@ public: /** * Returns the length of an index feature. */ - size_t veclen() const + size_t veclen() const CV_OVERRIDE { return feature_size_; } @@ -168,13 +168,13 @@ public: * Computes the index memory usage * Returns: memory used by the index */ - int usedMemory() const + int usedMemory() const CV_OVERRIDE { return (int)(dataset_.rows * sizeof(int)); } - IndexParams getParameters() const + IndexParams getParameters() const CV_OVERRIDE { return index_params_; } @@ -187,7 +187,7 @@ public: * \param[in] knn Number of nearest neighbors to return * \param[in] params Search parameters */ - virtual void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) + virtual void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) CV_OVERRIDE { assert(queries.cols == veclen()); assert(indices.rows >= queries.rows); @@ -217,7 +217,7 @@ public: * vec = the vector for which to search the nearest neighbors * maxCheck = the maximum number of restarts (in a best-bin-first manner) */ - void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& /*searchParams*/) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& /*searchParams*/) CV_OVERRIDE { getNeighbors(vec, result); } diff --git a/include/opencv2/flann/lsh_table.h b/include/opencv2/flann/lsh_table.h index 582dcdb..b07a9d5 100644 --- a/include/opencv2/flann/lsh_table.h +++ b/include/opencv2/flann/lsh_table.h @@ -146,6 +146,9 @@ public: */ LshTable() { + key_size_ = 0; + feature_size_ = 0; + speed_level_ = kArray; } /** Default constructor @@ -155,8 +158,8 @@ public: */ LshTable(unsigned int feature_size, unsigned int key_size) { - (void)feature_size; - (void)key_size; + feature_size_ = feature_size; + CV_UNUSED(key_size); std::cerr << "LSH is not implemented for that type" << std::endl; assert(0); } @@ -265,7 +268,7 @@ private: { const size_t key_size_lower_bound = 1; //a value (size_t(1) << key_size) must fit the size_t type so key_size has to be strictly less than size of size_t - const size_t key_size_upper_bound = std::min(sizeof(BucketKey) * CHAR_BIT + 1, sizeof(size_t) * CHAR_BIT); + const size_t key_size_upper_bound = (std::min)(sizeof(BucketKey) * CHAR_BIT + 1, sizeof(size_t) * CHAR_BIT); if (key_size < key_size_lower_bound || key_size >= key_size_upper_bound) { CV_Error(cv::Error::StsBadArg, cv::format("Invalid key_size (=%d). Valid values for your system are %d <= key_size < %d.", (int)key_size, (int)key_size_lower_bound, (int)key_size_upper_bound)); @@ -330,6 +333,8 @@ private: */ unsigned int key_size_; + unsigned int feature_size_; + // Members only used for the unsigned char specialization /** The mask to apply to a feature to get the hash key * Only used in the unsigned char case @@ -343,14 +348,19 @@ private: template<> inline LshTable::LshTable(unsigned int feature_size, unsigned int subsignature_size) { + feature_size_ = feature_size; initialize(subsignature_size); // Allocate the mask - mask_ = std::vector((size_t)ceil((float)(feature_size * sizeof(char)) / (float)sizeof(size_t)), 0); + mask_ = std::vector((feature_size * sizeof(char) + sizeof(size_t) - 1) / sizeof(size_t), 0); // A bit brutal but fast to code - std::vector indices(feature_size * CHAR_BIT); - for (size_t i = 0; i < feature_size * CHAR_BIT; ++i) indices[i] = i; + std::vector indices(feature_size * CHAR_BIT); + for (size_t i = 0; i < feature_size * CHAR_BIT; ++i) indices[i] = (int)i; +#ifndef OPENCV_FLANN_USE_STD_RAND + cv::randShuffle(indices); +#else std::random_shuffle(indices.begin(), indices.end()); +#endif // Generate a random set of order of subsignature_size_ bits for (unsigned int i = 0; i < key_size_; ++i) { @@ -386,6 +396,7 @@ inline size_t LshTable::getKey(const unsigned char* feature) cons { // no need to check if T is dividable by sizeof(size_t) like in the Hamming // distance computation as we have a mask + // FIXIT: This is bad assumption, because we reading tail bytes after of the allocated features buffer const size_t* feature_block_ptr = reinterpret_cast ((const void*)feature); // Figure out the subsignature of the feature @@ -394,10 +405,20 @@ inline size_t LshTable::getKey(const unsigned char* feature) cons size_t subsignature = 0; size_t bit_index = 1; - for (std::vector::const_iterator pmask_block = mask_.begin(); pmask_block != mask_.end(); ++pmask_block) { + for (unsigned i = 0; i < feature_size_; i += sizeof(size_t)) { // get the mask and signature blocks - size_t feature_block = *feature_block_ptr; - size_t mask_block = *pmask_block; + size_t feature_block; + if (i <= feature_size_ - sizeof(size_t)) + { + feature_block = *feature_block_ptr; + } + else + { + size_t tmp = 0; + memcpy(&tmp, feature_block_ptr, feature_size_ - i); // preserve bytes order + feature_block = tmp; + } + size_t mask_block = mask_[i / sizeof(size_t)]; while (mask_block) { // Get the lowest set bit in the mask block size_t lowest_bit = mask_block & (-(ptrdiff_t)mask_block); diff --git a/include/opencv2/flann/matrix.h b/include/opencv2/flann/matrix.h index 51b6c63..f6092d1 100644 --- a/include/opencv2/flann/matrix.h +++ b/include/opencv2/flann/matrix.h @@ -66,7 +66,7 @@ public: /** * Convenience function for deallocating the storage data. */ - FLANN_DEPRECATED void free() + CV_DEPRECATED void free() { fprintf(stderr, "The cvflann::Matrix::free() method is deprecated " "and it does not do any memory deallocation any more. You are" diff --git a/include/opencv2/flann/miniflann.hpp b/include/opencv2/flann/miniflann.hpp index 02fa236..bda2ed4 100644 --- a/include/opencv2/flann/miniflann.hpp +++ b/include/opencv2/flann/miniflann.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef _OPENCV_MINIFLANN_HPP_ -#define _OPENCV_MINIFLANN_HPP_ +#ifndef OPENCV_MINIFLANN_HPP +#define OPENCV_MINIFLANN_HPP #include "opencv2/core.hpp" #include "opencv2/flann/defines.h" @@ -74,6 +74,10 @@ struct CV_EXPORTS IndexParams std::vector& numValues) const; void* params; + +private: + IndexParams(const IndexParams &); // copy disabled + IndexParams& operator=(const IndexParams &); // assign disabled }; struct CV_EXPORTS KDTreeIndexParams : public IndexParams diff --git a/include/opencv2/flann/random.h b/include/opencv2/flann/random.h index a3cf5ec..d678474 100644 --- a/include/opencv2/flann/random.h +++ b/include/opencv2/flann/random.h @@ -40,13 +40,31 @@ namespace cvflann { +inline int rand() +{ +#ifndef OPENCV_FLANN_USE_STD_RAND +# if INT_MAX == RAND_MAX + int v = cv::theRNG().next() & INT_MAX; +# else + int v = cv::theRNG().uniform(0, RAND_MAX + 1); +# endif +#else + int v = std::rand(); +#endif // OPENCV_FLANN_USE_STD_RAND + return v; +} + /** * Seeds the random number generator * @param seed Random seed */ inline void seed_random(unsigned int seed) { - srand(seed); +#ifndef OPENCV_FLANN_USE_STD_RAND + cv::theRNG() = cv::RNG(seed); +#else + std::srand(seed); +#endif } /* @@ -60,7 +78,7 @@ inline void seed_random(unsigned int seed) */ inline double rand_double(double high = 1.0, double low = 0) { - return low + ((high-low) * (std::rand() / (RAND_MAX + 1.0))); + return low + ((high-low) * (rand() / (RAND_MAX + 1.0))); } /** @@ -71,7 +89,7 @@ inline double rand_double(double high = 1.0, double low = 0) */ inline int rand_int(int high = RAND_MAX, int low = 0) { - return low + (int) ( double(high-low) * (std::rand() / (RAND_MAX + 1.0))); + return low + (int) ( double(high-low) * (rand() / (RAND_MAX + 1.0))); } /** @@ -107,7 +125,11 @@ public: for (int i = 0; i < size_; ++i) vals_[i] = i; // shuffle the elements in the array +#ifndef OPENCV_FLANN_USE_STD_RAND + cv::randShuffle(vals_); +#else std::random_shuffle(vals_.begin(), vals_.end()); +#endif counter_ = 0; } diff --git a/include/opencv2/flann/result_set.h b/include/opencv2/flann/result_set.h index 9750019..5c69ac2 100644 --- a/include/opencv2/flann/result_set.h +++ b/include/opencv2/flann/result_set.h @@ -109,13 +109,13 @@ public: return count; } - bool full() const + bool full() const CV_OVERRIDE { return count == capacity; } - void addPoint(DistanceType dist, int index) + void addPoint(DistanceType dist, int index) CV_OVERRIDE { if (dist >= worst_distance_) return; int i; @@ -139,7 +139,7 @@ public: worst_distance_ = dists[capacity-1]; } - DistanceType worstDist() const + DistanceType worstDist() const CV_OVERRIDE { return worst_distance_; } @@ -176,13 +176,13 @@ public: return count; } - bool full() const + bool full() const CV_OVERRIDE { return count == capacity; } - void addPoint(DistanceType dist, int index) + void addPoint(DistanceType dist, int index) CV_OVERRIDE { if (dist >= worst_distance_) return; int i; @@ -215,7 +215,7 @@ public: worst_distance_ = dists[capacity-1]; } - DistanceType worstDist() const + DistanceType worstDist() const CV_OVERRIDE { return worst_distance_; } @@ -303,14 +303,14 @@ public: /** Default cosntructor */ UniqueResultSet() : - worst_distance_(std::numeric_limits::max()) + is_full_(false), worst_distance_(std::numeric_limits::max()) { } /** Check the status of the set * @return true if we have k NN */ - inline bool full() const + inline bool full() const CV_OVERRIDE { return is_full_; } @@ -365,7 +365,7 @@ public: * If we don't have enough neighbors, it returns the max possible value * @return */ - inline DistanceType worstDist() const + inline DistanceType worstDist() const CV_OVERRIDE { return worst_distance_; } @@ -402,7 +402,7 @@ public: * @param dist distance for that neighbor * @param index index of that neighbor */ - inline void addPoint(DistanceType dist, int index) + inline void addPoint(DistanceType dist, int index) CV_OVERRIDE { // Don't do anything if we are worse than the worst if (dist >= worst_distance_) return; @@ -422,7 +422,7 @@ public: /** Remove all elements in the set */ - void clear() + void clear() CV_OVERRIDE { dist_indices_.clear(); worst_distance_ = std::numeric_limits::max(); @@ -461,14 +461,14 @@ public: * @param dist distance for that neighbor * @param index index of that neighbor */ - void addPoint(DistanceType dist, int index) + void addPoint(DistanceType dist, int index) CV_OVERRIDE { if (dist <= radius_) dist_indices_.insert(DistIndex(dist, index)); } /** Remove all elements in the set */ - inline void clear() + inline void clear() CV_OVERRIDE { dist_indices_.clear(); } @@ -477,7 +477,7 @@ public: /** Check the status of the set * @return alwys false */ - inline bool full() const + inline bool full() const CV_OVERRIDE { return true; } @@ -486,7 +486,7 @@ public: * If we don't have enough neighbors, it returns the max possible value * @return */ - inline DistanceType worstDist() const + inline DistanceType worstDist() const CV_OVERRIDE { return radius_; } diff --git a/include/opencv2/highgui.hpp b/include/opencv2/highgui.hpp index 9275ae7..994a1d1 100644 --- a/include/opencv2/highgui.hpp +++ b/include/opencv2/highgui.hpp @@ -40,12 +40,16 @@ // //M*/ -#ifndef __OPENCV_HIGHGUI_HPP__ -#define __OPENCV_HIGHGUI_HPP__ +#ifndef OPENCV_HIGHGUI_HPP +#define OPENCV_HIGHGUI_HPP #include "opencv2/core.hpp" +#ifdef HAVE_OPENCV_IMGCODECS #include "opencv2/imgcodecs.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEOIO #include "opencv2/videoio.hpp" +#endif /** @defgroup highgui High-level GUI @@ -79,49 +83,90 @@ It provides easy interface to: attached to the control panel is a trackbar, or the control panel is empty, a new buttonbar is created. Then, a new button is attached to it. - See below the example used to generate the figure: : + See below the example used to generate the figure: @code int main(int argc, char *argv[]) + { + int value = 50; int value2 = 0; - cvNamedWindow("main1",CV_WINDOW_NORMAL); - cvNamedWindow("main2",CV_WINDOW_AUTOSIZE | CV_GUI_NORMAL); - cvCreateTrackbar( "track1", "main1", &value, 255, NULL);//OK tested - char* nameb1 = "button1"; - char* nameb2 = "button2"; - cvCreateButton(nameb1,callbackButton,nameb1,CV_CHECKBOX,1); + namedWindow("main1",WINDOW_NORMAL); + namedWindow("main2",WINDOW_AUTOSIZE | CV_GUI_NORMAL); + createTrackbar( "track1", "main1", &value, 255, NULL); - cvCreateButton(nameb2,callbackButton,nameb2,CV_CHECKBOX,0); - cvCreateTrackbar( "track2", NULL, &value2, 255, NULL); - cvCreateButton("button5",callbackButton1,NULL,CV_RADIOBOX,0); - cvCreateButton("button6",callbackButton2,NULL,CV_RADIOBOX,1); + String nameb1 = "button1"; + String nameb2 = "button2"; - cvSetMouseCallback( "main2",on_mouse,NULL ); + createButton(nameb1,callbackButton,&nameb1,QT_CHECKBOX,1); + createButton(nameb2,callbackButton,NULL,QT_CHECKBOX,0); + createTrackbar( "track2", NULL, &value2, 255, NULL); + createButton("button5",callbackButton1,NULL,QT_RADIOBOX,0); + createButton("button6",callbackButton2,NULL,QT_RADIOBOX,1); - IplImage* img1 = cvLoadImage("files/flower.jpg"); - IplImage* img2 = cvCreateImage(cvGetSize(img1),8,3); - CvCapture* video = cvCaptureFromFile("files/hockey.avi"); - IplImage* img3 = cvCreateImage(cvGetSize(cvQueryFrame(video)),8,3); + setMouseCallback( "main2",on_mouse,NULL ); - while(cvWaitKey(33) != 27) + Mat img1 = imread("files/flower.jpg"); + VideoCapture video; + video.open("files/hockey.avi"); + + Mat img2,img3; + + while( waitKey(33) != 27 ) { - cvAddS(img1,cvScalarAll(value),img2); - cvAddS(cvQueryFrame(video),cvScalarAll(value2),img3); - cvShowImage("main1",img2); - cvShowImage("main2",img3); + img1.convertTo(img2,-1,1,value); + video >> img3; + + imshow("main1",img2); + imshow("main2",img3); } - cvDestroyAllWindows(); - cvReleaseImage(&img1); - cvReleaseImage(&img2); - cvReleaseImage(&img3); - cvReleaseCapture(&video); + destroyAllWindows(); + return 0; } @endcode + + @defgroup highgui_winrt WinRT support + + This figure explains new functionality implemented with WinRT GUI. The new GUI provides an Image control, + and a slider panel. Slider panel holds trackbars attached to it. + + Sliders are attached below the image control. Every new slider is added below the previous one. + + See below the example used to generate the figure: + @code + void sample_app::MainPage::ShowWindow() + { + static cv::String windowName("sample"); + cv::winrt_initContainer(this->cvContainer); + cv::namedWindow(windowName); // not required + + cv::Mat image = cv::imread("Assets/sample.jpg"); + cv::Mat converted = cv::Mat(image.rows, image.cols, CV_8UC4); + cv::cvtColor(image, converted, COLOR_BGR2BGRA); + cv::imshow(windowName, converted); // this will create window if it hasn't been created before + + int state = 42; + cv::TrackbarCallback callback = [](int pos, void* userdata) + { + if (pos == 0) { + cv::destroyWindow(windowName); + } + }; + cv::TrackbarCallback callbackTwin = [](int pos, void* userdata) + { + if (pos >= 70) { + cv::destroyAllWindows(); + } + }; + cv::createTrackbar("Sample trackbar", windowName, &state, 100, callback); + cv::createTrackbar("Twin brother", windowName, &state, 100, callbackTwin); + } + @endcode + @defgroup highgui_c C API @} */ @@ -133,108 +178,137 @@ namespace cv //! @addtogroup highgui //! @{ -// Flags for namedWindow -enum { WINDOW_NORMAL = 0x00000000, // the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size - WINDOW_AUTOSIZE = 0x00000001, // the user cannot resize the window, the size is constrainted by the image displayed - WINDOW_OPENGL = 0x00001000, // window with opengl support +//! Flags for cv::namedWindow +enum WindowFlags { + WINDOW_NORMAL = 0x00000000, //!< the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size. + WINDOW_AUTOSIZE = 0x00000001, //!< the user cannot resize the window, the size is constrainted by the image displayed. + WINDOW_OPENGL = 0x00001000, //!< window with opengl support. - WINDOW_FULLSCREEN = 1, // change the window to fullscreen - WINDOW_FREERATIO = 0x00000100, // the image expends as much as it can (no ratio constraint) - WINDOW_KEEPRATIO = 0x00000000 // the ratio of the image is respected + WINDOW_FULLSCREEN = 1, //!< change the window to fullscreen. + WINDOW_FREERATIO = 0x00000100, //!< the image expends as much as it can (no ratio constraint). + WINDOW_KEEPRATIO = 0x00000000, //!< the ratio of the image is respected. + WINDOW_GUI_EXPANDED=0x00000000, //!< status bar and tool bar + WINDOW_GUI_NORMAL = 0x00000010, //!< old fashious way + }; + +//! Flags for cv::setWindowProperty / cv::getWindowProperty +enum WindowPropertyFlags { + WND_PROP_FULLSCREEN = 0, //!< fullscreen property (can be WINDOW_NORMAL or WINDOW_FULLSCREEN). + WND_PROP_AUTOSIZE = 1, //!< autosize property (can be WINDOW_NORMAL or WINDOW_AUTOSIZE). + WND_PROP_ASPECT_RATIO = 2, //!< window's aspect ration (can be set to WINDOW_FREERATIO or WINDOW_KEEPRATIO). + WND_PROP_OPENGL = 3, //!< opengl support. + WND_PROP_VISIBLE = 4 //!< checks whether the window exists and is visible }; -// Flags for set / getWindowProperty -enum { WND_PROP_FULLSCREEN = 0, // fullscreen property (can be WINDOW_NORMAL or WINDOW_FULLSCREEN) - WND_PROP_AUTOSIZE = 1, // autosize property (can be WINDOW_NORMAL or WINDOW_AUTOSIZE) - WND_PROP_ASPECT_RATIO = 2, // window's aspect ration (can be set to WINDOW_FREERATIO or WINDOW_KEEPRATIO); - WND_PROP_OPENGL = 3 // opengl support +//! Mouse Events see cv::MouseCallback +enum MouseEventTypes { + EVENT_MOUSEMOVE = 0, //!< indicates that the mouse pointer has moved over the window. + EVENT_LBUTTONDOWN = 1, //!< indicates that the left mouse button is pressed. + EVENT_RBUTTONDOWN = 2, //!< indicates that the right mouse button is pressed. + EVENT_MBUTTONDOWN = 3, //!< indicates that the middle mouse button is pressed. + EVENT_LBUTTONUP = 4, //!< indicates that left mouse button is released. + EVENT_RBUTTONUP = 5, //!< indicates that right mouse button is released. + EVENT_MBUTTONUP = 6, //!< indicates that middle mouse button is released. + EVENT_LBUTTONDBLCLK = 7, //!< indicates that left mouse button is double clicked. + EVENT_RBUTTONDBLCLK = 8, //!< indicates that right mouse button is double clicked. + EVENT_MBUTTONDBLCLK = 9, //!< indicates that middle mouse button is double clicked. + EVENT_MOUSEWHEEL = 10,//!< positive and negative values mean forward and backward scrolling, respectively. + EVENT_MOUSEHWHEEL = 11 //!< positive and negative values mean right and left scrolling, respectively. }; -enum { EVENT_MOUSEMOVE = 0, - EVENT_LBUTTONDOWN = 1, - EVENT_RBUTTONDOWN = 2, - EVENT_MBUTTONDOWN = 3, - EVENT_LBUTTONUP = 4, - EVENT_RBUTTONUP = 5, - EVENT_MBUTTONUP = 6, - EVENT_LBUTTONDBLCLK = 7, - EVENT_RBUTTONDBLCLK = 8, - EVENT_MBUTTONDBLCLK = 9, - EVENT_MOUSEWHEEL = 10, - EVENT_MOUSEHWHEEL = 11 +//! Mouse Event Flags see cv::MouseCallback +enum MouseEventFlags { + EVENT_FLAG_LBUTTON = 1, //!< indicates that the left mouse button is down. + EVENT_FLAG_RBUTTON = 2, //!< indicates that the right mouse button is down. + EVENT_FLAG_MBUTTON = 4, //!< indicates that the middle mouse button is down. + EVENT_FLAG_CTRLKEY = 8, //!< indicates that CTRL Key is pressed. + EVENT_FLAG_SHIFTKEY = 16,//!< indicates that SHIFT Key is pressed. + EVENT_FLAG_ALTKEY = 32 //!< indicates that ALT Key is pressed. }; -enum { EVENT_FLAG_LBUTTON = 1, - EVENT_FLAG_RBUTTON = 2, - EVENT_FLAG_MBUTTON = 4, - EVENT_FLAG_CTRLKEY = 8, - EVENT_FLAG_SHIFTKEY = 16, - EVENT_FLAG_ALTKEY = 32 +//! Qt font weight +enum QtFontWeights { + QT_FONT_LIGHT = 25, //!< Weight of 25 + QT_FONT_NORMAL = 50, //!< Weight of 50 + QT_FONT_DEMIBOLD = 63, //!< Weight of 63 + QT_FONT_BOLD = 75, //!< Weight of 75 + QT_FONT_BLACK = 87 //!< Weight of 87 }; -// Qt font -enum { QT_FONT_LIGHT = 25, //QFont::Light, - QT_FONT_NORMAL = 50, //QFont::Normal, - QT_FONT_DEMIBOLD = 63, //QFont::DemiBold, - QT_FONT_BOLD = 75, //QFont::Bold, - QT_FONT_BLACK = 87 //QFont::Black +//! Qt font style +enum QtFontStyles { + QT_STYLE_NORMAL = 0, //!< Normal font. + QT_STYLE_ITALIC = 1, //!< Italic font. + QT_STYLE_OBLIQUE = 2 //!< Oblique font. }; -// Qt font style -enum { QT_STYLE_NORMAL = 0, //QFont::StyleNormal, - QT_STYLE_ITALIC = 1, //QFont::StyleItalic, - QT_STYLE_OBLIQUE = 2 //QFont::StyleOblique +//! Qt "button" type +enum QtButtonTypes { + QT_PUSH_BUTTON = 0, //!< Push button. + QT_CHECKBOX = 1, //!< Checkbox button. + QT_RADIOBOX = 2, //!< Radiobox button. + QT_NEW_BUTTONBAR = 1024 //!< Button should create a new buttonbar }; -// Qt "button" type -enum { QT_PUSH_BUTTON = 0, - QT_CHECKBOX = 1, - QT_RADIOBOX = 2 - }; - - +/** @brief Callback function for mouse events. see cv::setMouseCallback +@param event one of the cv::MouseEventTypes constants. +@param x The x-coordinate of the mouse event. +@param y The y-coordinate of the mouse event. +@param flags one of the cv::MouseEventFlags constants. +@param userdata The optional parameter. + */ typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata); + +/** @brief Callback function for Trackbar see cv::createTrackbar +@param pos current position of the specified trackbar. +@param userdata The optional parameter. + */ typedef void (*TrackbarCallback)(int pos, void* userdata); + +/** @brief Callback function defined to be called every frame. See cv::setOpenGlDrawCallback +@param userdata The optional parameter. + */ typedef void (*OpenGlDrawCallback)(void* userdata); + +/** @brief Callback function for a button created by cv::createButton +@param state current state of the button. It could be -1 for a push button, 0 or 1 for a check/radio box button. +@param userdata The optional parameter. + */ typedef void (*ButtonCallback)(int state, void* userdata); /** @brief Creates a window. -@param winname Name of the window in the window caption that may be used as a window identifier. -@param flags Flags of the window. The supported flags are: -> - **WINDOW_NORMAL** If this is set, the user can resize the window (no constraint). -> - **WINDOW_AUTOSIZE** If this is set, the window size is automatically adjusted to fit the -> displayed image (see imshow ), and you cannot change the window size manually. -> - **WINDOW_OPENGL** If this is set, the window will be created with OpenGL support. - The function namedWindow creates a window that can be used as a placeholder for images and trackbars. Created windows are referred to by their names. If a window with the same name already exists, the function does nothing. -You can call destroyWindow or destroyAllWindows to close the window and de-allocate any associated +You can call cv::destroyWindow or cv::destroyAllWindows to close the window and de-allocate any associated memory usage. For a simple program, you do not really have to call these functions because all the resources and windows of the application are closed automatically by the operating system upon exit. @note Qt backend supports additional flags: - - **CV_WINDOW_NORMAL or CV_WINDOW_AUTOSIZE:** CV_WINDOW_NORMAL enables you to resize the - window, whereas CV_WINDOW_AUTOSIZE adjusts automatically the window size to fit the + - **WINDOW_NORMAL or WINDOW_AUTOSIZE:** WINDOW_NORMAL enables you to resize the + window, whereas WINDOW_AUTOSIZE adjusts automatically the window size to fit the displayed image (see imshow ), and you cannot change the window size manually. - - **CV_WINDOW_FREERATIO or CV_WINDOW_KEEPRATIO:** CV_WINDOW_FREERATIO adjusts the image - with no respect to its ratio, whereas CV_WINDOW_KEEPRATIO keeps the image ratio. - - **CV_GUI_NORMAL or CV_GUI_EXPANDED:** CV_GUI_NORMAL is the old way to draw the window - without statusbar and toolbar, whereas CV_GUI_EXPANDED is a new enhanced GUI. -By default, flags == CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED + - **WINDOW_FREERATIO or WINDOW_KEEPRATIO:** WINDOW_FREERATIO adjusts the image + with no respect to its ratio, whereas WINDOW_KEEPRATIO keeps the image ratio. + - **WINDOW_GUI_NORMAL or WINDOW_GUI_EXPANDED:** WINDOW_GUI_NORMAL is the old way to draw the window + without statusbar and toolbar, whereas WINDOW_GUI_EXPANDED is a new enhanced GUI. +By default, flags == WINDOW_AUTOSIZE | WINDOW_KEEPRATIO | WINDOW_GUI_EXPANDED + +@param winname Name of the window in the window caption that may be used as a window identifier. +@param flags Flags of the window. The supported flags are: (cv::WindowFlags) */ CV_EXPORTS_W void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE); -/** @brief Destroys a window. - -@param winname Name of the window to be destroyed. +/** @brief Destroys the specified window. The function destroyWindow destroys the window with the given name. + +@param winname Name of the window to be destroyed. */ CV_EXPORTS_W void destroyWindow(const String& winname); @@ -246,9 +320,16 @@ CV_EXPORTS_W void destroyAllWindows(); CV_EXPORTS_W int startWindowThread(); -/** @brief Waits for a pressed key. +/** @brief Similar to #waitKey, but returns full key code. -@param delay Delay in milliseconds. 0 is the special value that means "forever". +@note + +Key code is implementation specific and depends on used backend: QT/GTK/Win32/etc + +*/ +CV_EXPORTS_W int waitKeyEx(int delay = 0); + +/** @brief Waits for a pressed key. The function waitKey waits for a key event infinitely (when \f$\texttt{delay}\leq 0\f$ ) or for delay milliseconds, when it is positive. Since the OS has a minimum time between switching threads, the @@ -266,131 +347,132 @@ takes care of event processing. The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active. + +@param delay Delay in milliseconds. 0 is the special value that means "forever". */ CV_EXPORTS_W int waitKey(int delay = 0); /** @brief Displays an image in the specified window. -@param winname Name of the window. -@param mat Image to be shown. - The function imshow displays an image in the specified window. If the window was created with the -CV_WINDOW_AUTOSIZE flag, the image is shown with its original size, however it is still limited by the screen resolution. +cv::WINDOW_AUTOSIZE flag, the image is shown with its original size, however it is still limited by the screen resolution. Otherwise, the image is scaled to fit the window. The function may scale the image, depending on its depth: - If the image is 8-bit unsigned, it is displayed as is. - If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the value range [0,255\*256] is mapped to [0,255]. -- If the image is 32-bit floating-point, the pixel values are multiplied by 255. That is, the +- If the image is 32-bit or 64-bit floating-point, the pixel values are multiplied by 255. That is, the value range [0,1] is mapped to [0,255]. -If window was created with OpenGL support, imshow also support ogl::Buffer , ogl::Texture2D and +If window was created with OpenGL support, cv::imshow also support ogl::Buffer , ogl::Texture2D and cuda::GpuMat as input. -If the window was not created before this function, it is assumed creating a window with CV_WINDOW_AUTOSIZE. +If the window was not created before this function, it is assumed creating a window with cv::WINDOW_AUTOSIZE. If you need to show an image that is bigger than the screen resolution, you will need to call namedWindow("", WINDOW_NORMAL) before the imshow. -@note This function should be followed by waitKey function which displays the image for specified -milliseconds. Otherwise, it won't display the image. For example, waitKey(0) will display the window -infinitely until any keypress (it is suitable for image display). waitKey(25) will display a frame +@note This function should be followed by cv::waitKey function which displays the image for specified +milliseconds. Otherwise, it won't display the image. For example, **waitKey(0)** will display the window +infinitely until any keypress (it is suitable for image display). **waitKey(25)** will display a frame for 25 ms, after which display will be automatically closed. (If you put it in a loop to read videos, it will display the video frame-by-frame) @note -[Windows Backend Only] Pressing Ctrl+C will copy the image to the clipboard. +[__Windows Backend Only__] Pressing Ctrl+C will copy the image to the clipboard. +[__Windows Backend Only__] Pressing Ctrl+S will show a dialog to save the image. + +@param winname Name of the window. +@param mat Image to be shown. */ CV_EXPORTS_W void imshow(const String& winname, InputArray mat); /** @brief Resizes window to the specified size -@param winname Window name -@param width The new window width -@param height The new window height - @note - The specified window size is for the image area. Toolbars are not counted. -- Only windows created without CV_WINDOW_AUTOSIZE flag can be resized. +- Only windows created without cv::WINDOW_AUTOSIZE flag can be resized. + +@param winname Window name. +@param width The new window width. +@param height The new window height. */ CV_EXPORTS_W void resizeWindow(const String& winname, int width, int height); +/** @overload +@param winname Window name. +@param size The new window size. +*/ +CV_EXPORTS_W void resizeWindow(const String& winname, const cv::Size& size); + /** @brief Moves window to the specified position -@param winname Window name -@param x The new x-coordinate of the window -@param y The new y-coordinate of the window +@param winname Name of the window. +@param x The new x-coordinate of the window. +@param y The new y-coordinate of the window. */ CV_EXPORTS_W void moveWindow(const String& winname, int x, int y); /** @brief Changes parameters of a window dynamically. -@param winname Name of the window. -@param prop_id Window property to edit. The following operation flags are available: - - **CV_WND_PROP_FULLSCREEN** Change if the window is fullscreen ( CV_WINDOW_NORMAL or - CV_WINDOW_FULLSCREEN ). - - **CV_WND_PROP_AUTOSIZE** Change if the window is resizable (CV_WINDOW_NORMAL or - CV_WINDOW_AUTOSIZE ). - - **CV_WND_PROP_ASPECTRATIO** Change if the aspect ratio of the image is preserved ( - CV_WINDOW_FREERATIO or CV_WINDOW_KEEPRATIO ). -@param prop_value New value of the window property. The following operation flags are available: - - **CV_WINDOW_NORMAL** Change the window to normal size or make the window resizable. - - **CV_WINDOW_AUTOSIZE** Constrain the size by the displayed image. The window is not - resizable. - - **CV_WINDOW_FULLSCREEN** Change the window to fullscreen. - - **CV_WINDOW_FREERATIO** Make the window resizable without any ratio constraints. - - **CV_WINDOW_KEEPRATIO** Make the window resizable, but preserve the proportions of the - displayed image. - The function setWindowProperty enables changing properties of a window. + +@param winname Name of the window. +@param prop_id Window property to edit. The supported operation flags are: (cv::WindowPropertyFlags) +@param prop_value New value of the window property. The supported flags are: (cv::WindowFlags) */ CV_EXPORTS_W void setWindowProperty(const String& winname, int prop_id, double prop_value); /** @brief Updates window title +@param winname Name of the window. +@param title New title. */ CV_EXPORTS_W void setWindowTitle(const String& winname, const String& title); /** @brief Provides parameters of a window. -@param winname Name of the window. -@param prop_id Window property to retrieve. The following operation flags are available: - - **CV_WND_PROP_FULLSCREEN** Change if the window is fullscreen ( CV_WINDOW_NORMAL or - CV_WINDOW_FULLSCREEN ). - - **CV_WND_PROP_AUTOSIZE** Change if the window is resizable (CV_WINDOW_NORMAL or - CV_WINDOW_AUTOSIZE ). - - **CV_WND_PROP_ASPECTRATIO** Change if the aspect ratio of the image is preserved - (CV_WINDOW_FREERATIO or CV_WINDOW_KEEPRATIO ). - -See setWindowProperty to know the meaning of the returned values. - The function getWindowProperty returns properties of a window. + +@param winname Name of the window. +@param prop_id Window property to retrieve. The following operation flags are available: (cv::WindowPropertyFlags) + +@sa setWindowProperty */ CV_EXPORTS_W double getWindowProperty(const String& winname, int prop_id); +/** @brief Provides rectangle of image in the window. + +The function getWindowImageRect returns the client screen coordinates, width and height of the image rendering area. + +@param winname Name of the window. + +@sa resizeWindow moveWindow + */ +CV_EXPORTS_W Rect getWindowImageRect(const String& winname); + +/** @example samples/cpp/create_mask.cpp +This program demonstrates using mouse events and how to make and use a mask image (black and white) . +*/ /** @brief Sets mouse handler for the specified window -@param winname Window name -@param onMouse Mouse callback. See OpenCV samples, such as -, on how to specify and -use the callback. +@param winname Name of the window. +@param onMouse Callback function for mouse events. See OpenCV samples on how to specify and use the callback. @param userdata The optional parameter passed to the callback. */ CV_EXPORTS void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0); -/** @brief Gets the mouse-wheel motion delta, when handling mouse-wheel events EVENT_MOUSEWHEEL and -EVENT_MOUSEHWHEEL. - -@param flags The mouse callback flags parameter. +/** @brief Gets the mouse-wheel motion delta, when handling mouse-wheel events cv::EVENT_MOUSEWHEEL and +cv::EVENT_MOUSEHWHEEL. For regular mice with a scroll-wheel, delta will be a multiple of 120. The value 120 corresponds to a one notch rotation of the wheel or the threshold for action to be taken and one such action should occur for each delta. Some high-precision mice with higher-resolution freely-rotating wheels may generate smaller values. -For EVENT_MOUSEWHEEL positive and negative values mean forward and backward scrolling, -respectively. For EVENT_MOUSEHWHEEL, where available, positive and negative values mean right and +For cv::EVENT_MOUSEWHEEL positive and negative values mean forward and backward scrolling, +respectively. For cv::EVENT_MOUSEHWHEEL, where available, positive and negative values mean right and left scrolling, respectively. With the C API, the macro CV_GET_WHEEL_DELTA(flags) can be used alternatively. @@ -398,11 +480,63 @@ With the C API, the macro CV_GET_WHEEL_DELTA(flags) can be used alternatively. @note Mouse-wheel events are currently supported only on Windows. + +@param flags The mouse callback flags parameter. */ CV_EXPORTS int getMouseWheelDelta(int flags); +/** @brief Selects ROI on the given image. +Function creates a window and allows user to select a ROI using mouse. +Controls: use `space` or `enter` to finish selection, use key `c` to cancel selection (function will return the zero cv::Rect). + +@param windowName name of the window where selection process will be shown. +@param img image to select a ROI. +@param showCrosshair if true crosshair of selection rectangle will be shown. +@param fromCenter if true center of selection will match initial mouse position. In opposite case a corner of +selection rectangle will correspont to the initial mouse position. +@return selected ROI or empty rect if selection canceled. + +@note The function sets it's own mouse callback for specified window using cv::setMouseCallback(windowName, ...). +After finish of work an empty callback will be set for the used window. + */ +CV_EXPORTS_W Rect selectROI(const String& windowName, InputArray img, bool showCrosshair = true, bool fromCenter = false); + +/** @overload + */ +CV_EXPORTS_W Rect selectROI(InputArray img, bool showCrosshair = true, bool fromCenter = false); + +/** @brief Selects ROIs on the given image. +Function creates a window and allows user to select a ROIs using mouse. +Controls: use `space` or `enter` to finish current selection and start a new one, +use `esc` to terminate multiple ROI selection process. + +@param windowName name of the window where selection process will be shown. +@param img image to select a ROI. +@param boundingBoxes selected ROIs. +@param showCrosshair if true crosshair of selection rectangle will be shown. +@param fromCenter if true center of selection will match initial mouse position. In opposite case a corner of +selection rectangle will correspont to the initial mouse position. + +@note The function sets it's own mouse callback for specified window using cv::setMouseCallback(windowName, ...). +After finish of work an empty callback will be set for the used window. + */ +CV_EXPORTS_W void selectROIs(const String& windowName, InputArray img, + CV_OUT std::vector& boundingBoxes, bool showCrosshair = true, bool fromCenter = false); + /** @brief Creates a trackbar and attaches it to the specified window. +The function createTrackbar creates a trackbar (a slider or range control) with the specified name +and range, assigns a variable value to be a position synchronized with the trackbar and specifies +the callback function onChange to be called on the trackbar position change. The created trackbar is +displayed in the specified window winname. + +@note + +[__Qt Backend Only__] winname can be empty (or NULL) if the trackbar should be attached to the +control panel. + +Clicking the label of each trackbar enables editing the trackbar values manually. + @param trackbarname Name of the created trackbar. @param winname Name of the window that will be used as a parent of the created trackbar. @param value Optional pointer to an integer variable whose value reflects the position of the @@ -414,23 +548,6 @@ position and the second parameter is the user data (see the next parameter). If the NULL pointer, no callbacks are called, but only value is updated. @param userdata User data that is passed as is to the callback. It can be used to handle trackbar events without using global variables. - -The function createTrackbar creates a trackbar (a slider or range control) with the specified name -and range, assigns a variable value to be a position synchronized with the trackbar and specifies -the callback function onChange to be called on the trackbar position change. The created trackbar is -displayed in the specified window winname. - -@note - -**[Qt Backend Only]** winname can be empty (or NULL) if the trackbar should be attached to the -control panel. - -Clicking the label of each trackbar enables editing the trackbar values manually. - -@note - -- An example of using the trackbar functionality can be found at - opencv_source_code/samples/cpp/connected_components.cpp */ CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname, int* value, int count, @@ -439,63 +556,77 @@ CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname, /** @brief Returns the trackbar position. -@param trackbarname Name of the trackbar. -@param winname Name of the window that is the parent of the trackbar. - The function returns the current position of the specified trackbar. @note -**[Qt Backend Only]** winname can be empty (or NULL) if the trackbar is attached to the control +[__Qt Backend Only__] winname can be empty (or NULL) if the trackbar is attached to the control panel. +@param trackbarname Name of the trackbar. +@param winname Name of the window that is the parent of the trackbar. */ CV_EXPORTS_W int getTrackbarPos(const String& trackbarname, const String& winname); /** @brief Sets the trackbar position. -@param trackbarname Name of the trackbar. -@param winname Name of the window that is the parent of trackbar. -@param pos New position. - The function sets the position of the specified trackbar in the specified window. @note -**[Qt Backend Only]** winname can be empty (or NULL) if the trackbar is attached to the control +[__Qt Backend Only__] winname can be empty (or NULL) if the trackbar is attached to the control panel. + +@param trackbarname Name of the trackbar. +@param winname Name of the window that is the parent of trackbar. +@param pos New position. */ CV_EXPORTS_W void setTrackbarPos(const String& trackbarname, const String& winname, int pos); /** @brief Sets the trackbar maximum position. -@param trackbarname Name of the trackbar. -@param winname Name of the window that is the parent of trackbar. -@param maxval New maximum position. - The function sets the maximum position of the specified trackbar in the specified window. @note -**[Qt Backend Only]** winname can be empty (or NULL) if the trackbar is attached to the control +[__Qt Backend Only__] winname can be empty (or NULL) if the trackbar is attached to the control panel. + +@param trackbarname Name of the trackbar. +@param winname Name of the window that is the parent of trackbar. +@param maxval New maximum position. */ CV_EXPORTS_W void setTrackbarMax(const String& trackbarname, const String& winname, int maxval); +/** @brief Sets the trackbar minimum position. + +The function sets the minimum position of the specified trackbar in the specified window. + +@note + +[__Qt Backend Only__] winname can be empty (or NULL) if the trackbar is attached to the control +panel. + +@param trackbarname Name of the trackbar. +@param winname Name of the window that is the parent of trackbar. +@param minval New minimum position. + */ +CV_EXPORTS_W void setTrackbarMin(const String& trackbarname, const String& winname, int minval); + //! @addtogroup highgui_opengl OpenGL support //! @{ +/** @brief Displays OpenGL 2D texture in the specified window. + +@param winname Name of the window. +@param tex OpenGL 2D texture data. + */ CV_EXPORTS void imshow(const String& winname, const ogl::Texture2D& tex); /** @brief Sets a callback function to be called to draw on top of displayed image. -@param winname Name of the window. -@param onOpenGlDraw Pointer to the function to be called every frame. This function should be -prototyped as void Foo(void\*) . -@param userdata Pointer passed to the callback function. *(Optional)* - The function setOpenGlDrawCallback can be used to draw 3D data on the window. See the example of -callback function below: : +callback function below: @code void on_opengl(void* param) { @@ -526,18 +657,23 @@ callback function below: : } } @endcode + +@param winname Name of the window. +@param onOpenGlDraw Pointer to the function to be called every frame. This function should be +prototyped as void Foo(void\*) . +@param userdata Pointer passed to the callback function.(__Optional__) */ CV_EXPORTS void setOpenGlDrawCallback(const String& winname, OpenGlDrawCallback onOpenGlDraw, void* userdata = 0); /** @brief Sets the specified window as current OpenGL context. -@param winname Window name +@param winname Name of the window. */ CV_EXPORTS void setOpenGlContext(const String& winname); -/** @brief Force window to redraw its context and call draw callback ( setOpenGlDrawCallback ). +/** @brief Force window to redraw its context and call draw callback ( See cv::setOpenGlDrawCallback ). -@param winname Window name +@param winname Name of the window. */ CV_EXPORTS void updateWindow(const String& winname); @@ -545,112 +681,120 @@ CV_EXPORTS void updateWindow(const String& winname); //! @addtogroup highgui_qt //! @{ -// Only for Qt +/** @brief QtFont available only for Qt. See cv::fontQt + */ struct QtFont { - const char* nameFont; // Qt: nameFont - Scalar color; // Qt: ColorFont -> cvScalar(blue_component, green_component, red_component[, alpha_component]) - int font_face; // Qt: bool italic - const int* ascii; // font data and metrics + const char* nameFont; //!< Name of the font + Scalar color; //!< Color of the font. Scalar(blue_component, green_component, red_component[, alpha_component]) + int font_face; //!< See cv::QtFontStyles + const int* ascii; //!< font data and metrics const int* greek; const int* cyrillic; float hscale, vscale; - float shear; // slope coefficient: 0 - normal, >0 - italic - int thickness; // Qt: weight - float dx; // horizontal interval between letters - int line_type; // Qt: PointSize + float shear; //!< slope coefficient: 0 - normal, >0 - italic + int thickness; //!< See cv::QtFontWeights + float dx; //!< horizontal interval between letters + int line_type; //!< PointSize }; /** @brief Creates the font to draw a text on an image. +The function fontQt creates a cv::QtFont object. This cv::QtFont is not compatible with putText . + +A basic usage of this function is the following: : +@code + QtFont font = fontQt("Times"); + addText( img1, "Hello World !", Point(50,50), font); +@endcode + @param nameFont Name of the font. The name should match the name of a system font (such as *Times*). If the font is not found, a default one is used. @param pointSize Size of the font. If not specified, equal zero or negative, the point size of the font is set to a system-dependent default value. Generally, this is 12 points. -@param color Color of the font in BGRA where A = 255 is fully transparent. Use the macro CV _ RGB +@param color Color of the font in BGRA where A = 255 is fully transparent. Use the macro CV_RGB for simplicity. -@param weight Font weight. The following operation flags are available: - - **CV_FONT_LIGHT** Weight of 25 - - **CV_FONT_NORMAL** Weight of 50 - - **CV_FONT_DEMIBOLD** Weight of 63 - - **CV_FONT_BOLD** Weight of 75 - - **CV_FONT_BLACK** Weight of 87 - - You can also specify a positive integer for better control. -@param style Font style. The following operation flags are available: - - **CV_STYLE_NORMAL** Normal font - - **CV_STYLE_ITALIC** Italic font - - **CV_STYLE_OBLIQUE** Oblique font +@param weight Font weight. Available operation flags are : cv::QtFontWeights You can also specify a positive integer for better control. +@param style Font style. Available operation flags are : cv::QtFontStyles @param spacing Spacing between characters. It can be negative or positive. - -The function fontQt creates a CvFont object. This CvFont is not compatible with putText . - -A basic usage of this function is the following: : -@code - CvFont font = fontQt(''Times''); - addText( img1, ``Hello World !'', Point(50,50), font); -@endcode */ CV_EXPORTS QtFont fontQt(const String& nameFont, int pointSize = -1, Scalar color = Scalar::all(0), int weight = QT_FONT_NORMAL, int style = QT_STYLE_NORMAL, int spacing = 0); -/** @brief Creates the font to draw a text on an image. +/** @brief Draws a text on the image. + +The function addText draws *text* on the image *img* using a specific font *font* (see example cv::fontQt +) @param img 8-bit 3-channel image where the text should be drawn. @param text Text to write on an image. @param org Point(x,y) where the text should start on an image. @param font Font to use to draw a text. - -The function addText draws *text* on an image *img* using a specific font *font* (see example fontQt -) */ CV_EXPORTS void addText( const Mat& img, const String& text, Point org, const QtFont& font); +/** @brief Draws a text on the image. + +@param img 8-bit 3-channel image where the text should be drawn. +@param text Text to write on an image. +@param org Point(x,y) where the text should start on an image. +@param nameFont Name of the font. The name should match the name of a system font (such as +*Times*). If the font is not found, a default one is used. +@param pointSize Size of the font. If not specified, equal zero or negative, the point size of the +font is set to a system-dependent default value. Generally, this is 12 points. +@param color Color of the font in BGRA where A = 255 is fully transparent. +@param weight Font weight. Available operation flags are : cv::QtFontWeights You can also specify a positive integer for better control. +@param style Font style. Available operation flags are : cv::QtFontStyles +@param spacing Spacing between characters. It can be negative or positive. + */ +CV_EXPORTS_W void addText(const Mat& img, const String& text, Point org, const String& nameFont, int pointSize = -1, Scalar color = Scalar::all(0), + int weight = QT_FONT_NORMAL, int style = QT_STYLE_NORMAL, int spacing = 0); + /** @brief Displays a text on a window image as an overlay for a specified duration. +The function displayOverlay displays useful information/tips on top of the window for a certain +amount of time *delayms*. The function does not modify the image, displayed in the window, that is, +after the specified delay the original content of the window is restored. + @param winname Name of the window. @param text Overlay text to write on a window image. @param delayms The period (in milliseconds), during which the overlay text is displayed. If this function is called before the previous overlay text timed out, the timer is restarted and the text is updated. If this value is zero, the text never disappears. - -The function displayOverlay displays useful information/tips on top of the window for a certain -amount of time *delayms*. The function does not modify the image, displayed in the window, that is, -after the specified delay the original content of the window is restored. */ -CV_EXPORTS void displayOverlay(const String& winname, const String& text, int delayms = 0); +CV_EXPORTS_W void displayOverlay(const String& winname, const String& text, int delayms = 0); /** @brief Displays a text on the window statusbar during the specified period of time. +The function displayStatusBar displays useful information/tips on top of the window for a certain +amount of time *delayms* . This information is displayed on the window statusbar (the window must be +created with the CV_GUI_EXPANDED flags). + @param winname Name of the window. @param text Text to write on the window statusbar. @param delayms Duration (in milliseconds) to display the text. If this function is called before the previous text timed out, the timer is restarted and the text is updated. If this value is zero, the text never disappears. - -The function displayOverlay displays useful information/tips on top of the window for a certain -amount of time *delayms* . This information is displayed on the window statusbar (the window must be -created with the CV_GUI_EXPANDED flags). */ -CV_EXPORTS void displayStatusBar(const String& winname, const String& text, int delayms = 0); +CV_EXPORTS_W void displayStatusBar(const String& winname, const String& text, int delayms = 0); /** @brief Saves parameters of the specified window. -@param windowName Name of the window. - The function saveWindowParameters saves size, location, flags, trackbars value, zoom and panning -location of the window window_name . +location of the window windowName. + +@param windowName Name of the window. */ CV_EXPORTS void saveWindowParameters(const String& windowName); /** @brief Loads parameters of the specified window. -@param windowName Name of the window. - The function loadWindowParameters loads size, location, flags, trackbars value, zoom and panning -location of the window window_name . +location of the window windowName. + +@param windowName Name of the window. */ CV_EXPORTS void loadWindowParameters(const String& windowName); @@ -660,32 +804,29 @@ CV_EXPORTS void stopLoop(); /** @brief Attaches a button to the control panel. -@param bar_name - Name of the button. +The function createButton attaches a button to the control panel. Each button is added to a +buttonbar to the right of the last button. A new buttonbar is created if nothing was attached to the +control panel before, or if the last element attached to the control panel was a trackbar or if the +QT_NEW_BUTTONBAR flag is added to the type. + +See below various examples of the cv::createButton function call: : +@code + createButton(NULL,callbackButton);//create a push button "button 0", that will call callbackButton. + createButton("button2",callbackButton,NULL,QT_CHECKBOX,0); + createButton("button3",callbackButton,&value); + createButton("button5",callbackButton1,NULL,QT_RADIOBOX); + createButton("button6",callbackButton2,NULL,QT_PUSH_BUTTON,1); + createButton("button6",callbackButton2,NULL,QT_PUSH_BUTTON|QT_NEW_BUTTONBAR);// create a push button in a new row +@endcode + +@param bar_name Name of the button. @param on_change Pointer to the function to be called every time the button changes its state. This function should be prototyped as void Foo(int state,\*void); . *state* is the current state of the button. It could be -1 for a push button, 0 or 1 for a check/radio box button. @param userdata Pointer passed to the callback function. -@param type Optional type of the button. - - **CV_PUSH_BUTTON** Push button - - **CV_CHECKBOX** Checkbox button - - **CV_RADIOBOX** Radiobox button. The radiobox on the same buttonbar (same line) are - exclusive, that is only one can be selected at a time. +@param type Optional type of the button. Available types are: (cv::QtButtonTypes) @param initial_button_state Default state of the button. Use for checkbox and radiobox. Its -value could be 0 or 1. *(Optional)* - -The function createButton attaches a button to the control panel. Each button is added to a -buttonbar to the right of the last button. A new buttonbar is created if nothing was attached to the -control panel before, or if the last element attached to the control panel was a trackbar. - -See below various examples of the createButton function call: : -@code - createButton(NULL,callbackButton);//create a push button "button 0", that will call callbackButton. - createButton("button2",callbackButton,NULL,CV_CHECKBOX,0); - createButton("button3",callbackButton,&value); - createButton("button5",callbackButton1,NULL,CV_RADIOBOX); - createButton("button6",callbackButton2,NULL,CV_PUSH_BUTTON,1); -@endcode +value could be 0 or 1. (__Optional__) */ CV_EXPORTS int createButton( const String& bar_name, ButtonCallback on_change, void* userdata = 0, int type = QT_PUSH_BUTTON, diff --git a/include/opencv2/highgui/highgui_c.h b/include/opencv2/highgui/highgui_c.h index 46d4c95..3541313 100644 --- a/include/opencv2/highgui/highgui_c.h +++ b/include/opencv2/highgui/highgui_c.h @@ -39,13 +39,17 @@ // //M*/ -#ifndef __OPENCV_HIGHGUI_H__ -#define __OPENCV_HIGHGUI_H__ +#ifndef OPENCV_HIGHGUI_H +#define OPENCV_HIGHGUI_H #include "opencv2/core/core_c.h" #include "opencv2/imgproc/imgproc_c.h" +#ifdef HAVE_OPENCV_IMGCODECS #include "opencv2/imgcodecs/imgcodecs_c.h" +#endif +#ifdef HAVE_OPENCV_VIDEOIO #include "opencv2/videoio/videoio_c.h" +#endif #ifdef __cplusplus extern "C" { @@ -107,6 +111,7 @@ enum CV_WND_PROP_AUTOSIZE = 1, //to change/get window's autosize property CV_WND_PROP_ASPECTRATIO= 2, //to change/get window's aspectratio property CV_WND_PROP_OPENGL = 3, //to change/get window's opengl support + CV_WND_PROP_VISIBLE = 4, //These 2 flags are used by cvNamedWindow and cvSet/GetWindowProperty CV_WINDOW_NORMAL = 0x00000000, //the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size @@ -130,6 +135,11 @@ CVAPI(int) cvNamedWindow( const char* name, int flags CV_DEFAULT(CV_WINDOW_AUTOS CVAPI(void) cvSetWindowProperty(const char* name, int prop_id, double prop_value); CVAPI(double) cvGetWindowProperty(const char* name, int prop_id); +#ifdef __cplusplus // FIXIT remove in OpenCV 4.0 +/* Get window image rectangle coordinates, width and height */ +CVAPI(cv::Rect)cvGetWindowImageRect(const char* name); +#endif + /* display image within window (highgui windows remember their content) */ CVAPI(void) cvShowImage( const char* name, const CvArr* image ); @@ -166,6 +176,7 @@ CVAPI(int) cvCreateTrackbar2( const char* trackbar_name, const char* window_name CVAPI(int) cvGetTrackbarPos( const char* trackbar_name, const char* window_name ); CVAPI(void) cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ); CVAPI(void) cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval); +CVAPI(void) cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval); enum { @@ -233,7 +244,7 @@ CVAPI(void) cvUpdateWindow(const char* window_name); #define set_preprocess_func cvSetPreprocessFuncWin32 #define set_postprocess_func cvSetPostprocessFuncWin32 -#if defined WIN32 || defined _WIN32 +#if defined _WIN32 CVAPI(void) cvSetPreprocessFuncWin32_(const void* callback); CVAPI(void) cvSetPostprocessFuncWin32_(const void* callback); diff --git a/include/opencv2/imgcodecs.hpp b/include/opencv2/imgcodecs.hpp index 91e44fb..4e79518 100644 --- a/include/opencv2/imgcodecs.hpp +++ b/include/opencv2/imgcodecs.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_IMGCODECS_HPP__ -#define __OPENCV_IMGCODECS_HPP__ +#ifndef OPENCV_IMGCODECS_HPP +#define OPENCV_IMGCODECS_HPP #include "opencv2/core.hpp" @@ -62,12 +62,19 @@ namespace cv //! Imread flags enum ImreadModes { - IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). - IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image. - IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image. - IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit. - IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format. - IMREAD_LOAD_GDAL = 8 //!< If set, use the gdal driver for loading the image. + IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). + IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion). + IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image. + IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit. + IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format. + IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image. + IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2. + IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2. + IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4. + IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4. + IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8. + IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8. + IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag. }; //! Imwrite flags @@ -78,45 +85,77 @@ enum ImwriteFlags { IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart. IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is 0 - don't use. IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is 0 - don't use. - IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. Default value is 3. - IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT. + IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting). + IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE. IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0. IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1. - IMWRITE_WEBP_QUALITY = 64 //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used. + IMWRITE_EXR_TYPE = (3 << 4) + 0, /* 48 */ //!< override EXR storage type (FLOAT (FP32) is default) + IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used. + IMWRITE_PAM_TUPLETYPE = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format + IMWRITE_TIFF_RESUNIT = 256,//!< For TIFF, use to specify which DPI resolution unit to set; see libtiff documentation for valid values + IMWRITE_TIFF_XDPI = 257,//!< For TIFF, use to specify the X direction DPI + IMWRITE_TIFF_YDPI = 258 //!< For TIFF, use to specify the Y direction DPI }; -//! Imwrite PNG specific flags +enum ImwriteEXRTypeFlags { + /*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */ + IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16) + IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default) + }; + +//! Imwrite PNG specific flags used to tune the compression algorithm. +/** These flags will be modify the way of PNG image compression and will be passed to the underlying zlib processing stage. + +- The effect of IMWRITE_PNG_STRATEGY_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between IMWRITE_PNG_STRATEGY_DEFAULT and IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY. +- IMWRITE_PNG_STRATEGY_RLE is designed to be almost as fast as IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY, but give better compression for PNG image data. +- The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. +- IMWRITE_PNG_STRATEGY_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. +*/ enum ImwritePNGFlags { - IMWRITE_PNG_STRATEGY_DEFAULT = 0, - IMWRITE_PNG_STRATEGY_FILTERED = 1, - IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY = 2, - IMWRITE_PNG_STRATEGY_RLE = 3, - IMWRITE_PNG_STRATEGY_FIXED = 4 + IMWRITE_PNG_STRATEGY_DEFAULT = 0, //!< Use this value for normal data. + IMWRITE_PNG_STRATEGY_FILTERED = 1, //!< Use this value for data produced by a filter (or predictor).Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. + IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY = 2, //!< Use this value to force Huffman encoding only (no string match). + IMWRITE_PNG_STRATEGY_RLE = 3, //!< Use this value to limit match distances to one (run-length encoding). + IMWRITE_PNG_STRATEGY_FIXED = 4 //!< Using this value prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. + }; + +//! Imwrite PAM specific tupletype flags used to define the 'TUPETYPE' field of a PAM file. +enum ImwritePAMFlags { + IMWRITE_PAM_FORMAT_NULL = 0, + IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1, + IMWRITE_PAM_FORMAT_GRAYSCALE = 2, + IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3, + IMWRITE_PAM_FORMAT_RGB = 4, + IMWRITE_PAM_FORMAT_RGB_ALPHA = 5, }; /** @brief Loads an image from a file. @anchor imread -@param filename Name of file to be loaded. -@param flags Flag that can take values of @ref cv::ImreadModes - The function imread loads an image from the specified file and returns it. If the image cannot be read (because of missing file, improper permissions, unsupported or invalid format), the function -returns an empty matrix ( Mat::data==NULL ). Currently, the following file formats are supported: +returns an empty matrix ( Mat::data==NULL ). + +Currently, the following file formats are supported: - Windows bitmaps - \*.bmp, \*.dib (always supported) -- JPEG files - \*.jpeg, \*.jpg, \*.jpe (see the *Notes* section) -- JPEG 2000 files - \*.jp2 (see the *Notes* section) -- Portable Network Graphics - \*.png (see the *Notes* section) -- WebP - \*.webp (see the *Notes* section) -- Portable image format - \*.pbm, \*.pgm, \*.ppm (always supported) +- JPEG files - \*.jpeg, \*.jpg, \*.jpe (see the *Note* section) +- JPEG 2000 files - \*.jp2 (see the *Note* section) +- Portable Network Graphics - \*.png (see the *Note* section) +- WebP - \*.webp (see the *Note* section) +- Portable image format - \*.pbm, \*.pgm, \*.ppm \*.pxm, \*.pnm (always supported) - Sun rasters - \*.sr, \*.ras (always supported) -- TIFF files - \*.tiff, \*.tif (see the *Notes* section) +- TIFF files - \*.tiff, \*.tif (see the *Note* section) +- OpenEXR Image files - \*.exr (see the *Note* section) +- Radiance HDR - \*.hdr, \*.pic (always supported) +- Raster and Vector geospatial data supported by GDAL (see the *Note* section) @note - - The function determines the type of an image by the content, not by the file extension. +- In the case of color images, the decoded images will have the channels stored in **B G R** order. +- When using IMREAD_GRAYSCALE, the codec's internal grayscale conversion will be used, if available. + Results may differ to the output of cvtColor() - On Microsoft Windows\* OS and MacOSX\*, the codecs shipped with an OpenCV image (libjpeg, libpng, libtiff, and libjasper) are used by default. So, OpenCV can always read JPEGs, PNGs, and TIFFs. On MacOSX, there is also an option to use native MacOSX image readers. But beware @@ -126,119 +165,89 @@ returns an empty matrix ( Mat::data==NULL ). Currently, the following file forma codecs supplied with an OS image. Install the relevant packages (do not forget the development files, for example, "libjpeg-dev", in Debian\* and Ubuntu\*) to get the codec support or turn on the OPENCV_BUILD_3RDPARTY_LIBS flag in CMake. - -@note In the case of color images, the decoded images will have the channels stored in B G R order. - */ -CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR ); - -/** @brief Loads a multi-page image from a file. (see imread for details.) +- In the case you set *WITH_GDAL* flag to true in CMake and @ref IMREAD_LOAD_GDAL to load the image, + then the [GDAL](http://www.gdal.org) driver will be used in order to decode the image, supporting + the following formats: [Raster](http://www.gdal.org/formats_list.html), + [Vector](http://www.gdal.org/ogr_formats.html). +- If EXIF information are embedded in the image file, the EXIF orientation will be taken into account + and thus the image will be rotated accordingly except if the flag @ref IMREAD_IGNORE_ORIENTATION is passed. +- By default number of pixels must be less than 2^30. Limit can be set using system + variable OPENCV_IO_MAX_IMAGE_PIXELS @param filename Name of file to be loaded. -@param flags Flag that can take values of @ref cv::ImreadModes, default with IMREAD_ANYCOLOR. -@param mats A vector of Mat objects holding each page, if more than one. - +@param flags Flag that can take values of cv::ImreadModes */ -CV_EXPORTS_W bool imreadmulti(const String& filename, std::vector& mats, int flags = IMREAD_ANYCOLOR); +CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR ); + +/** @brief Loads a multi-page image from a file. + +The function imreadmulti loads a multi-page image from the specified file into a vector of Mat objects. +@param filename Name of file to be loaded. +@param flags Flag that can take values of cv::ImreadModes, default with cv::IMREAD_ANYCOLOR. +@param mats A vector of Mat objects holding each page, if more than one. +@sa cv::imread +*/ +CV_EXPORTS_W bool imreadmulti(const String& filename, CV_OUT std::vector& mats, int flags = IMREAD_ANYCOLOR); /** @brief Saves an image to a specified file. -@param filename Name of the file. -@param img Image to be saved. -@param params Format-specific save parameters encoded as pairs, see @ref cv::ImwriteFlags -paramId_1, paramValue_1, paramId_2, paramValue_2, ... . - The function imwrite saves the image to the specified file. The image format is chosen based on the -filename extension (see imread for the list of extensions). Only 8-bit (or 16-bit unsigned (CV_16U) -in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with 'BGR' channel order) images -can be saved using this function. If the format, depth or channel order is different, use -Mat::convertTo , and cvtColor to convert it before saving. Or, use the universal FileStorage I/O +filename extension (see cv::imread for the list of extensions). In general, only 8-bit +single-channel or 3-channel (with 'BGR' channel order) images +can be saved using this function, with these exceptions: + +- 16-bit unsigned (CV_16U) images can be saved in the case of PNG, JPEG 2000, and TIFF formats +- 32-bit float (CV_32F) images can be saved in TIFF, OpenEXR, and Radiance HDR formats; 3-channel +(CV_32FC3) TIFF images will be saved using the LogLuv high dynamic range encoding (4 bytes per pixel) +- PNG images with an alpha channel can be saved using this function. To do this, create +8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels +should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535 (see the code sample below). + +If the format, depth or channel order is different, use +Mat::convertTo and cv::cvtColor to convert it before saving. Or, use the universal FileStorage I/O functions to save the image to XML or YAML format. -It is possible to store PNG images with an alpha channel using this function. To do this, create -8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels -should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535. The sample below -shows how to create such a BGRA image and store to PNG file. It also demonstrates how to set custom -compression parameters : -@code - #include - #include - #include - - using namespace cv; - using namespace std; - - void createAlphaMat(Mat &mat) - { - CV_Assert(mat.channels() == 4); - for (int i = 0; i < mat.rows; ++i) { - for (int j = 0; j < mat.cols; ++j) { - Vec4b& bgra = mat.at(i, j); - bgra[0] = UCHAR_MAX; // Blue - bgra[1] = saturate_cast((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX); // Green - bgra[2] = saturate_cast((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX); // Red - bgra[3] = saturate_cast(0.5 * (bgra[1] + bgra[2])); // Alpha - } - } - } - - int main(int argv, char **argc) - { - // Create mat with alpha channel - Mat mat(480, 640, CV_8UC4); - createAlphaMat(mat); - - vector compression_params; - compression_params.push_back(IMWRITE_PNG_COMPRESSION); - compression_params.push_back(9); - - try { - imwrite("alpha.png", mat, compression_params); - } - catch (runtime_error& ex) { - fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what()); - return 1; - } - - fprintf(stdout, "Saved PNG file with alpha data.\n"); - return 0; - } -@endcode - */ +The sample below shows how to create a BGRA image and save it to a PNG file. It also demonstrates how to set custom +compression parameters: +@include snippets/imgcodecs_imwrite.cpp +@param filename Name of the file. +@param img Image to be saved. +@param params Format-specific parameters encoded as pairs (paramId_1, paramValue_1, paramId_2, paramValue_2, ... .) see cv::ImwriteFlags +*/ CV_EXPORTS_W bool imwrite( const String& filename, InputArray img, const std::vector& params = std::vector()); -/** @overload */ -CV_EXPORTS_W Mat imdecode( InputArray buf, int flags ); - /** @brief Reads an image from a buffer in memory. +The function imdecode reads an image from the specified buffer in the memory. If the buffer is too short or +contains invalid data, the function returns an empty matrix ( Mat::data==NULL ). + +See cv::imread for the list of supported formats and flags description. + +@note In the case of color images, the decoded images will have the channels stored in **B G R** order. @param buf Input array or vector of bytes. -@param flags The same flags as in imread, see @ref cv::ImreadModes. +@param flags The same flags as in cv::imread, see cv::ImreadModes. +*/ +CV_EXPORTS_W Mat imdecode( InputArray buf, int flags ); + +/** @overload +@param buf +@param flags @param dst The optional output placeholder for the decoded matrix. It can save the image reallocations when the function is called repeatedly for images of the same size. - -The function reads an image from the specified buffer in the memory. If the buffer is too short or -contains invalid data, the empty matrix/image is returned. - -See imread for the list of supported formats and flags description. - -@note In the case of color images, the decoded images will have the channels stored in B G R order. - */ +*/ CV_EXPORTS Mat imdecode( InputArray buf, int flags, Mat* dst); /** @brief Encodes an image into a memory buffer. +The function imencode compresses the image and stores it in the memory buffer that is resized to fit the +result. See cv::imwrite for the list of supported formats and flags description. + @param ext File extension that defines the output format. @param img Image to be written. @param buf Output buffer resized to fit the compressed image. -@param params Format-specific parameters. See imwrite and @ref cv::ImwriteFlags. - -The function compresses the image and stores it in the memory buffer that is resized to fit the -result. See imwrite for the list of supported formats and flags description. - -@note cvEncodeImage returns single-row matrix of type CV_8UC1 that contains encoded image as array -of bytes. - */ +@param params Format-specific parameters. See cv::imwrite and cv::ImwriteFlags. +*/ CV_EXPORTS_W bool imencode( const String& ext, InputArray img, CV_OUT std::vector& buf, const std::vector& params = std::vector()); @@ -247,4 +256,4 @@ CV_EXPORTS_W bool imencode( const String& ext, InputArray img, } // cv -#endif //__OPENCV_IMGCODECS_HPP__ +#endif //OPENCV_IMGCODECS_HPP diff --git a/include/opencv2/imgcodecs/imgcodecs_c.h b/include/opencv2/imgcodecs/imgcodecs_c.h index ad793cc..c36dac3 100644 --- a/include/opencv2/imgcodecs/imgcodecs_c.h +++ b/include/opencv2/imgcodecs/imgcodecs_c.h @@ -39,8 +39,8 @@ // //M*/ -#ifndef __OPENCV_IMGCODECS_H__ -#define __OPENCV_IMGCODECS_H__ +#ifndef OPENCV_IMGCODECS_H +#define OPENCV_IMGCODECS_H #include "opencv2/core/core_c.h" @@ -63,7 +63,9 @@ enum /* any depth, ? */ CV_LOAD_IMAGE_ANYDEPTH =2, /* ?, any color */ - CV_LOAD_IMAGE_ANYCOLOR =4 + CV_LOAD_IMAGE_ANYCOLOR =4, +/* ?, no rotate */ + CV_LOAD_IMAGE_IGNORE_ORIENTATION =128 }; /* load image from file @@ -92,9 +94,19 @@ enum CV_IMWRITE_PNG_STRATEGY_RLE =3, CV_IMWRITE_PNG_STRATEGY_FIXED =4, CV_IMWRITE_PXM_BINARY =32, - CV_IMWRITE_WEBP_QUALITY =64 + CV_IMWRITE_EXR_TYPE = 48, + CV_IMWRITE_WEBP_QUALITY =64, + CV_IMWRITE_PAM_TUPLETYPE = 128, + CV_IMWRITE_PAM_FORMAT_NULL = 0, + CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1, + CV_IMWRITE_PAM_FORMAT_GRAYSCALE = 2, + CV_IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3, + CV_IMWRITE_PAM_FORMAT_RGB = 4, + CV_IMWRITE_PAM_FORMAT_RGB_ALPHA = 5, }; + + /* save image to file */ CVAPI(int) cvSaveImage( const char* filename, const CvArr* image, const int* params CV_DEFAULT(0) ); @@ -134,4 +146,4 @@ CVAPI(int) cvHaveImageWriter(const char* filename); } #endif -#endif // __OPENCV_IMGCODECS_H__ +#endif // OPENCV_IMGCODECS_H diff --git a/include/opencv2/imgcodecs/ios.h b/include/opencv2/imgcodecs/ios.h index fbd6371..a90c6d3 100644 --- a/include/opencv2/imgcodecs/ios.h +++ b/include/opencv2/imgcodecs/ios.h @@ -50,8 +50,8 @@ //! @addtogroup imgcodecs_ios //! @{ -UIImage* MatToUIImage(const cv::Mat& image); -void UIImageToMat(const UIImage* image, - cv::Mat& m, bool alphaExist = false); +CV_EXPORTS UIImage* MatToUIImage(const cv::Mat& image); +CV_EXPORTS void UIImageToMat(const UIImage* image, + cv::Mat& m, bool alphaExist = false); //! @} diff --git a/include/opencv2/imgproc.hpp b/include/opencv2/imgproc.hpp index 5c18545..14a63f3 100644 --- a/include/opencv2/imgproc.hpp +++ b/include/opencv2/imgproc.hpp @@ -40,13 +40,16 @@ // //M*/ -#ifndef __OPENCV_IMGPROC_HPP__ -#define __OPENCV_IMGPROC_HPP__ +#ifndef OPENCV_IMGPROC_HPP +#define OPENCV_IMGPROC_HPP #include "opencv2/core.hpp" /** - @defgroup imgproc Image processing + @defgroup imgproc Image Processing + +This module includes image-processing functions. + @{ @defgroup imgproc_filter Image Filtering @@ -67,7 +70,7 @@ processing the left-most pixels in each row, you need pixels to the left of them of the image. You can let these pixels be the same as the left-most image pixels ("replicated border" extrapolation method), or assume that all the non-existing pixels are zeros ("constant border" extrapolation method), and so on. OpenCV enables you to specify the extrapolation method. -For details, see cv::BorderTypes +For details, see #BorderTypes @anchor filter_depths ### Depth combinations @@ -102,7 +105,7 @@ the simplest and the fastest resize, need to solve two main problems with the ab previous section, for some \f$(x,y)\f$, either one of \f$f_x(x,y)\f$, or \f$f_y(x,y)\f$, or both of them may fall outside of the image. In this case, an extrapolation method needs to be used. OpenCV provides the same selection of extrapolation methods as in the filtering functions. In -addition, it provides the method BORDER_TRANSPARENT. This means that the corresponding pixels in +addition, it provides the method #BORDER_TRANSPARENT. This means that the corresponding pixels in the destination image will not be modified at all. - Interpolation of pixel values. Usually \f$f_x(x,y)\f$ and \f$f_y(x,y)\f$ are floating-point @@ -117,6 +120,8 @@ f_y(x,y))\f$, and then the value of the polynomial at \f$(f_x(x,y), f_y(x,y))\f$ interpolated pixel value. In OpenCV, you can choose between several interpolation methods. See resize for details. +@note The geometrical transformations do not work with `CV_8S` or `CV_32S` images. + @defgroup imgproc_misc Miscellaneous Image Transformations @defgroup imgproc_draw Drawing Functions @@ -146,6 +151,7 @@ case, the color[3] is simply copied to the repainted pixels. Thus, if you want t semi-transparent shapes, you can paint them in a separate buffer and then blend it with the main image. + @defgroup imgproc_color_conversions Color Space Conversions @defgroup imgproc_colormap ColorMaps in OpenCV The human perception isn't built for observing fine changes in grayscale images. Human eyes are more @@ -157,42 +163,22 @@ In OpenCV you only need applyColorMap to apply a colormap on a given image. The code reads the path to an image from command line, applies a Jet colormap on it and shows the result: -@code -#include -#include -#include -#include -using namespace cv; +@include snippets/imgproc_applyColorMap.cpp -#include -using namespace std; +@see #ColormapTypes -int main(int argc, const char *argv[]) -{ - // We need an input image. (can be grayscale or color) - if (argc < 2) - { - cerr << "We need an image to process here. Please run: colorMap [path_to_image]" << endl; - return -1; - } - Mat img_in = imread(argv[1]); - if(img_in.empty()) - { - cerr << "Sample image (" << argv[1] << ") is empty. Please adjust your path, so it points to a valid input image!" << endl; - return -1; - } - // Holds the colormap version of the image: - Mat img_color; - // Apply the colormap: - applyColorMap(img_in, img_color, COLORMAP_JET); - // Show the result: - imshow("colorMap", img_color); - waitKey(0); - return 0; -} -@endcode + @defgroup imgproc_subdiv2d Planar Subdivision -@see cv::ColormapTypes +The Subdiv2D class described in this section is used to perform various planar subdivision on +a set of 2D points (represented as vector of Point2f). OpenCV subdivides a plane into triangles +using the Delaunay's algorithm, which corresponds to the dual graph of the Voronoi diagram. +In the figure below, the Delaunay's triangulation is marked with black lines and the Voronoi +diagram with red lines. + +![Delaunay triangulation (black) and Voronoi (red)](pics/delaunay_voronoi.png) + +The subdivisions can be used for the 3D piece-wise transformation of a plane, morphing, fast +location of points on the plane, building special graphs (such as NNG,RNG), and so forth. @defgroup imgproc_hist Histograms @defgroup imgproc_shape Structural Analysis and Shape Descriptors @@ -200,6 +186,11 @@ int main(int argc, const char *argv[]) @defgroup imgproc_feature Feature Detection @defgroup imgproc_object Object Detection @defgroup imgproc_c C API + @defgroup imgproc_hal Hardware Acceleration Layer + @{ + @defgroup imgproc_hal_functions Functions + @defgroup imgproc_hal_interface Interface + @} @} */ @@ -215,8 +206,8 @@ namespace cv //! type of morphological operation enum MorphTypes{ - MORPH_ERODE = 0, //!< see cv::erode - MORPH_DILATE = 1, //!< see cv::dilate + MORPH_ERODE = 0, //!< see #erode + MORPH_DILATE = 1, //!< see #dilate MORPH_OPEN = 2, //!< an opening operation //!< \f[\texttt{dst} = \mathrm{open} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \mathrm{erode} ( \texttt{src} , \texttt{element} ))\f] MORPH_CLOSE = 3, //!< a closing operation @@ -225,8 +216,10 @@ enum MorphTypes{ //!< \f[\texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} )\f] MORPH_TOPHAT = 5, //!< "top hat" //!< \f[\texttt{dst} = \mathrm{tophat} ( \texttt{src} , \texttt{element} )= \texttt{src} - \mathrm{open} ( \texttt{src} , \texttt{element} )\f] - MORPH_BLACKHAT = 6 //!< "black hat" + MORPH_BLACKHAT = 6, //!< "black hat" //!< \f[\texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src}\f] + MORPH_HITMISS = 7 //!< "hit or miss" + //!< .- Only supported for CV_8UC1 binary images. A tutorial can be found in the documentation }; //! shape of the structuring element @@ -257,6 +250,8 @@ enum InterpolationFlags{ INTER_AREA = 3, /** Lanczos interpolation over 8x8 neighborhood */ INTER_LANCZOS4 = 4, + /** Bit exact bilinear interpolation */ + INTER_LINEAR_EXACT = 5, /** mask for interpolation codes */ INTER_MAX = 7, /** flag, fills all of the destination image pixels. If some of them correspond to outliers in the @@ -264,13 +259,22 @@ enum InterpolationFlags{ WARP_FILL_OUTLIERS = 8, /** flag, inverse transformation - For example, polar transforms: - - flag is __not__ set: \f$dst( \phi , \rho ) = src(x,y)\f$ - - flag is set: \f$dst(x,y) = src( \phi , \rho )\f$ + For example, #linearPolar or #logPolar transforms: + - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$ + - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$ */ WARP_INVERSE_MAP = 16 }; +/** \brief Specify the polar mapping mode +@sa warpPolar +*/ +enum WarpPolarMode +{ + WARP_POLAR_LINEAR = 0, ///< Remaps an image to/from polar space. + WARP_POLAR_LOG = 256 ///< Remaps an image to/from semilog-polar space. +}; + enum InterpolationMasks { INTER_BITS = 5, INTER_BITS2 = INTER_BITS * 2, @@ -284,7 +288,7 @@ enum InterpolationMasks { //! @{ //! Distance types for Distance Transform and M-estimators -//! @see cv::distanceTransform, cv::fitLine +//! @see distanceTransform, fitLine enum DistanceTypes { DIST_USER = -1, //!< User defined distance DIST_L1 = 1, //!< distance = |x1-x2| + |y1-y2| @@ -317,7 +321,7 @@ enum ThresholdTypes { }; //! adaptive threshold algorithm -//! see cv::adaptiveThreshold +//! @see adaptiveThreshold enum AdaptiveThresholdTypes { /** the threshold value \f$T(x,y)\f$ is a mean of the \f$\texttt{blockSize} \times \texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$ minus C */ @@ -325,7 +329,7 @@ enum AdaptiveThresholdTypes { /** the threshold value \f$T(x, y)\f$ is a weighted sum (cross-correlation with a Gaussian window) of the \f$\texttt{blockSize} \times \texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$ minus C . The default sigma (standard deviation) is used for the specified blockSize . See - cv::getGaussianKernel*/ + #getGaussianKernel*/ ADAPTIVE_THRESH_GAUSSIAN_C = 1 }; @@ -353,7 +357,9 @@ enum GrabCutModes { automatically initialized with GC_BGD .*/ GC_INIT_WITH_MASK = 1, /** The value means that the algorithm should just resume. */ - GC_EVAL = 2 + GC_EVAL = 2, + /** The value means that the algorithm should just run the grabCut algorithm (a single iteration) with the fixed model */ + GC_EVAL_FREEZE_MODEL = 3 }; //! distanceTransform algorithm flags @@ -393,6 +399,13 @@ enum ConnectedComponentsTypes { CC_STAT_MAX = 5 }; +//! connected components algorithm +enum ConnectedComponentsAlgorithmsTypes { + CCL_WU = 0, //!< SAUF algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity + CCL_DEFAULT = -1, //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity + CCL_GRANA = 1 //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity +}; + //! mode of the contour retrieval algorithm enum RetrievalModes { /** retrieves only the extreme outer contours. It sets `hierarchy[i][2]=hierarchy[i][3]=-1` for @@ -425,8 +438,25 @@ enum ContourApproximationModes { CHAIN_APPROX_TC89_KCOS = 4 }; +/** @brief Shape matching methods + +\f$A\f$ denotes object1,\f$B\f$ denotes object2 + +\f$\begin{array}{l} m^A_i = \mathrm{sign} (h^A_i) \cdot \log{h^A_i} \\ m^B_i = \mathrm{sign} (h^B_i) \cdot \log{h^B_i} \end{array}\f$ + +and \f$h^A_i, h^B_i\f$ are the Hu moments of \f$A\f$ and \f$B\f$ , respectively. +*/ +enum ShapeMatchModes { + CONTOURS_MATCH_I1 =1, //!< \f[I_1(A,B) = \sum _{i=1...7} \left | \frac{1}{m^A_i} - \frac{1}{m^B_i} \right |\f] + CONTOURS_MATCH_I2 =2, //!< \f[I_2(A,B) = \sum _{i=1...7} \left | m^A_i - m^B_i \right |\f] + CONTOURS_MATCH_I3 =3 //!< \f[I_3(A,B) = \max _{i=1...7} \frac{ \left| m^A_i - m^B_i \right| }{ \left| m^A_i \right| }\f] +}; + //! @} imgproc_shape +//! @addtogroup imgproc_feature +//! @{ + //! Variants of a Hough transform enum HoughModes { @@ -447,7 +477,6 @@ enum HoughModes { }; //! Variants of Line Segment %Detector -//! @ingroup imgproc_feature enum LineSegmentDetectorModes { LSD_REFINE_NONE = 0, //!< No refinement applied LSD_REFINE_STD = 1, //!< Standard refinement is applied. E.g. breaking arches into smaller straighter line approximations. @@ -455,6 +484,8 @@ enum LineSegmentDetectorModes { //!< refined through increase of precision, decrement in size, etc. }; +//! @} imgproc_feature + /** Histogram comparison methods @ingroup imgproc_hist */ @@ -485,9 +516,9 @@ enum HistCompMethods { HISTCMP_KL_DIV = 5 }; -/** the color conversion code +/** the color conversion codes @see @ref imgproc_color_conversions -@ingroup imgproc_misc +@ingroup imgproc_color_conversions */ enum ColorConversionCodes { COLOR_BGR2BGRA = 0, //!< add alpha channel to RGB or BGR image @@ -572,7 +603,7 @@ enum ColorConversionCodes { COLOR_HLS2BGR = 60, COLOR_HLS2RGB = 61, - COLOR_BGR2HSV_FULL = 66, //!< + COLOR_BGR2HSV_FULL = 66, COLOR_RGB2HSV_FULL = 67, COLOR_BGR2HLS_FULL = 68, COLOR_RGB2HLS_FULL = 69, @@ -742,20 +773,32 @@ enum ColorConversionCodes { COLOR_BayerRG2RGB_EA = COLOR_BayerBG2BGR_EA, COLOR_BayerGR2RGB_EA = COLOR_BayerGB2BGR_EA, + //! Demosaicing with alpha channel + COLOR_BayerBG2BGRA = 139, + COLOR_BayerGB2BGRA = 140, + COLOR_BayerRG2BGRA = 141, + COLOR_BayerGR2BGRA = 142, - COLOR_COLORCVT_MAX = 139 + COLOR_BayerBG2RGBA = COLOR_BayerRG2BGRA, + COLOR_BayerGB2RGBA = COLOR_BayerGR2BGRA, + COLOR_BayerRG2RGBA = COLOR_BayerBG2BGRA, + COLOR_BayerGR2RGBA = COLOR_BayerGB2BGRA, + + COLOR_COLORCVT_MAX = 143 }; -/** types of intersection between rectangles -@ingroup imgproc_shape -*/ +//! @addtogroup imgproc_shape +//! @{ + +//! types of intersection between rectangles enum RectanglesIntersectTypes { INTERSECT_NONE = 0, //!< No intersection INTERSECT_PARTIAL = 1, //!< There is a partial intersection INTERSECT_FULL = 2 //!< One of the rectangle is fully enclosed in the other }; -//! finds arbitrary template in the grayscale image using Generalized Hough Transform +/** @brief finds arbitrary template in the grayscale image using Generalized Hough Transform +*/ class CV_EXPORTS GeneralizedHough : public Algorithm { public: @@ -788,8 +831,10 @@ public: virtual int getMaxBufferSize() const = 0; }; -//! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122. -//! Detects position only without traslation and rotation +/** @brief finds arbitrary template in the grayscale image using Generalized Hough Transform + +Detects position only without translation and rotation @cite Ballard1981 . +*/ class CV_EXPORTS GeneralizedHoughBallard : public GeneralizedHough { public: @@ -802,8 +847,10 @@ public: virtual int getVotesThreshold() const = 0; }; -//! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038. -//! Detects position, traslation and rotation +/** @brief finds arbitrary template in the grayscale image using Generalized Hough Transform + +Detects position, translation and rotation @cite Guil1999 . +*/ class CV_EXPORTS GeneralizedHoughGuil : public GeneralizedHough { public: @@ -856,32 +903,62 @@ public: virtual int getPosThresh() const = 0; }; +//! @} imgproc_shape +//! @addtogroup imgproc_hist +//! @{ + +/** @brief Base class for Contrast Limited Adaptive Histogram Equalization. +*/ class CV_EXPORTS_W CLAHE : public Algorithm { public: + /** @brief Equalizes the histogram of a grayscale image using Contrast Limited Adaptive Histogram Equalization. + + @param src Source image of type CV_8UC1 or CV_16UC1. + @param dst Destination image. + */ CV_WRAP virtual void apply(InputArray src, OutputArray dst) = 0; + /** @brief Sets threshold for contrast limiting. + + @param clipLimit threshold value. + */ CV_WRAP virtual void setClipLimit(double clipLimit) = 0; + + //! Returns threshold value for contrast limiting. CV_WRAP virtual double getClipLimit() const = 0; + /** @brief Sets size of grid for histogram equalization. Input image will be divided into + equally sized rectangular tiles. + + @param tileGridSize defines the number of tiles in row and column. + */ CV_WRAP virtual void setTilesGridSize(Size tileGridSize) = 0; + + //!@brief Returns Size defines the number of tiles in row and column. CV_WRAP virtual Size getTilesGridSize() const = 0; CV_WRAP virtual void collectGarbage() = 0; }; +//! @} imgproc_hist + +//! @addtogroup imgproc_subdiv2d +//! @{ class CV_EXPORTS_W Subdiv2D { public: - enum { PTLOC_ERROR = -2, - PTLOC_OUTSIDE_RECT = -1, - PTLOC_INSIDE = 0, - PTLOC_VERTEX = 1, - PTLOC_ON_EDGE = 2 + /** Subdiv2D point location cases */ + enum { PTLOC_ERROR = -2, //!< Point location error + PTLOC_OUTSIDE_RECT = -1, //!< Point outside the subdivision bounding rect + PTLOC_INSIDE = 0, //!< Point inside some facet + PTLOC_VERTEX = 1, //!< Point coincides with one of the subdivision vertices + PTLOC_ON_EDGE = 2 //!< Point on some edge }; + /** Subdiv2D edge type navigation (see: getEdge()) */ enum { NEXT_AROUND_ORG = 0x00, NEXT_AROUND_DST = 0x22, PREV_AROUND_ORG = 0x11, @@ -892,27 +969,190 @@ public: PREV_AROUND_RIGHT = 0x02 }; + /** creates an empty Subdiv2D object. + To create a new empty Delaunay subdivision you need to use the #initDelaunay function. + */ CV_WRAP Subdiv2D(); + + /** @overload + + @param rect Rectangle that includes all of the 2D points that are to be added to the subdivision. + + The function creates an empty Delaunay subdivision where 2D points can be added using the function + insert() . All of the points to be added must be within the specified rectangle, otherwise a runtime + error is raised. + */ CV_WRAP Subdiv2D(Rect rect); + + /** @brief Creates a new empty Delaunay subdivision + + @param rect Rectangle that includes all of the 2D points that are to be added to the subdivision. + + */ CV_WRAP void initDelaunay(Rect rect); + /** @brief Insert a single point into a Delaunay triangulation. + + @param pt Point to insert. + + The function inserts a single point into a subdivision and modifies the subdivision topology + appropriately. If a point with the same coordinates exists already, no new point is added. + @returns the ID of the point. + + @note If the point is outside of the triangulation specified rect a runtime error is raised. + */ CV_WRAP int insert(Point2f pt); + + /** @brief Insert multiple points into a Delaunay triangulation. + + @param ptvec Points to insert. + + The function inserts a vector of points into a subdivision and modifies the subdivision topology + appropriately. + */ CV_WRAP void insert(const std::vector& ptvec); + + /** @brief Returns the location of a point within a Delaunay triangulation. + + @param pt Point to locate. + @param edge Output edge that the point belongs to or is located to the right of it. + @param vertex Optional output vertex the input point coincides with. + + The function locates the input point within the subdivision and gives one of the triangle edges + or vertices. + + @returns an integer which specify one of the following five cases for point location: + - The point falls into some facet. The function returns #PTLOC_INSIDE and edge will contain one of + edges of the facet. + - The point falls onto the edge. The function returns #PTLOC_ON_EDGE and edge will contain this edge. + - The point coincides with one of the subdivision vertices. The function returns #PTLOC_VERTEX and + vertex will contain a pointer to the vertex. + - The point is outside the subdivision reference rectangle. The function returns #PTLOC_OUTSIDE_RECT + and no pointers are filled. + - One of input arguments is invalid. A runtime error is raised or, if silent or "parent" error + processing mode is selected, #PTLOC_ERROR is returned. + */ CV_WRAP int locate(Point2f pt, CV_OUT int& edge, CV_OUT int& vertex); + /** @brief Finds the subdivision vertex closest to the given point. + + @param pt Input point. + @param nearestPt Output subdivision vertex point. + + The function is another function that locates the input point within the subdivision. It finds the + subdivision vertex that is the closest to the input point. It is not necessarily one of vertices + of the facet containing the input point, though the facet (located using locate() ) is used as a + starting point. + + @returns vertex ID. + */ CV_WRAP int findNearest(Point2f pt, CV_OUT Point2f* nearestPt = 0); + + /** @brief Returns a list of all edges. + + @param edgeList Output vector. + + The function gives each edge as a 4 numbers vector, where each two are one of the edge + vertices. i.e. org_x = v[0], org_y = v[1], dst_x = v[2], dst_y = v[3]. + */ CV_WRAP void getEdgeList(CV_OUT std::vector& edgeList) const; + + /** @brief Returns a list of the leading edge ID connected to each triangle. + + @param leadingEdgeList Output vector. + + The function gives one edge ID for each triangle. + */ + CV_WRAP void getLeadingEdgeList(CV_OUT std::vector& leadingEdgeList) const; + + /** @brief Returns a list of all triangles. + + @param triangleList Output vector. + + The function gives each triangle as a 6 numbers vector, where each two are one of the triangle + vertices. i.e. p1_x = v[0], p1_y = v[1], p2_x = v[2], p2_y = v[3], p3_x = v[4], p3_y = v[5]. + */ CV_WRAP void getTriangleList(CV_OUT std::vector& triangleList) const; + + /** @brief Returns a list of all Voroni facets. + + @param idx Vector of vertices IDs to consider. For all vertices you can pass empty vector. + @param facetList Output vector of the Voroni facets. + @param facetCenters Output vector of the Voroni facets center points. + + */ CV_WRAP void getVoronoiFacetList(const std::vector& idx, CV_OUT std::vector >& facetList, CV_OUT std::vector& facetCenters); + /** @brief Returns vertex location from vertex ID. + + @param vertex vertex ID. + @param firstEdge Optional. The first edge ID which is connected to the vertex. + @returns vertex (x,y) + + */ CV_WRAP Point2f getVertex(int vertex, CV_OUT int* firstEdge = 0) const; + /** @brief Returns one of the edges related to the given edge. + + @param edge Subdivision edge ID. + @param nextEdgeType Parameter specifying which of the related edges to return. + The following values are possible: + - NEXT_AROUND_ORG next around the edge origin ( eOnext on the picture below if e is the input edge) + - NEXT_AROUND_DST next around the edge vertex ( eDnext ) + - PREV_AROUND_ORG previous around the edge origin (reversed eRnext ) + - PREV_AROUND_DST previous around the edge destination (reversed eLnext ) + - NEXT_AROUND_LEFT next around the left facet ( eLnext ) + - NEXT_AROUND_RIGHT next around the right facet ( eRnext ) + - PREV_AROUND_LEFT previous around the left facet (reversed eOnext ) + - PREV_AROUND_RIGHT previous around the right facet (reversed eDnext ) + + ![sample output](pics/quadedge.png) + + @returns edge ID related to the input edge. + */ CV_WRAP int getEdge( int edge, int nextEdgeType ) const; + + /** @brief Returns next edge around the edge origin. + + @param edge Subdivision edge ID. + + @returns an integer which is next edge ID around the edge origin: eOnext on the + picture above if e is the input edge). + */ CV_WRAP int nextEdge(int edge) const; + + /** @brief Returns another edge of the same quad-edge. + + @param edge Subdivision edge ID. + @param rotate Parameter specifying which of the edges of the same quad-edge as the input + one to return. The following values are possible: + - 0 - the input edge ( e on the picture below if e is the input edge) + - 1 - the rotated edge ( eRot ) + - 2 - the reversed edge (reversed e (in green)) + - 3 - the reversed rotated edge (reversed eRot (in green)) + + @returns one of the edges ID of the same quad-edge as the input edge. + */ CV_WRAP int rotateEdge(int edge, int rotate) const; CV_WRAP int symEdge(int edge) const; + + /** @brief Returns the edge origin. + + @param edge Subdivision edge ID. + @param orgpt Output vertex location. + + @returns vertex ID. + */ CV_WRAP int edgeOrg(int edge, CV_OUT Point2f* orgpt = 0) const; + + /** @brief Returns the edge destination. + + @param edge Subdivision edge ID. + @param dstpt Output vertex location. + + @returns vertex ID. + */ CV_WRAP int edgeDst(int edge, CV_OUT Point2f* dstpt = 0) const; protected: @@ -951,22 +1191,29 @@ protected: int pt[4]; }; + //! All of the vertices std::vector vtx; + //! All of the edges std::vector qedges; int freeQEdge; int freePoint; bool validGeometry; int recentEdge; + //! Top left corner of the bounding rect Point2f topLeft; + //! Bottom right corner of the bounding rect Point2f bottomRight; }; +//! @} imgproc_subdiv2d + //! @addtogroup imgproc_feature //! @{ -/** @example lsd_lines.cpp +/** @example samples/cpp/lsd_lines.cpp An example using the LineSegmentDetector +\image html building_lsd.png "Sample output image" width=434 height=300 */ /** @brief Line segment detector class @@ -995,14 +1242,14 @@ public: - -1 corresponds to 10 mean false alarms - 0 corresponds to 1 mean false alarm - 1 corresponds to 0.1 mean false alarms - This vector will be calculated only when the objects type is LSD_REFINE_ADV. + This vector will be calculated only when the objects type is #LSD_REFINE_ADV. */ CV_WRAP virtual void detect(InputArray _image, OutputArray _lines, OutputArray width = noArray(), OutputArray prec = noArray(), OutputArray nfa = noArray()) = 0; /** @brief Draws the line segments on a given image. - @param _image The image, where the liens will be drawn. Should be bigger or equal to the image, + @param _image The image, where the lines will be drawn. Should be bigger or equal to the image, where the lines were found. @param lines A vector of the lines that needed to be drawn. */ @@ -1026,12 +1273,12 @@ public: The LineSegmentDetector algorithm is defined using the standard values. Only advanced users may want to edit those, as to tailor it for their own application. -@param _refine The way found lines will be refined, see cv::LineSegmentDetectorModes +@param _refine The way found lines will be refined, see #LineSegmentDetectorModes @param _scale The scale of the image that will be used to find the lines. Range (0..1]. @param _sigma_scale Sigma for Gaussian filter. It is computed as sigma = _sigma_scale/_scale. @param _quant Bound to the quantization error on the gradient norm. @param _ang_th Gradient angle tolerance in degrees. -@param _log_eps Detection threshold: -log10(NFA) \> log_eps. Used only when advancent refinement +@param _log_eps Detection threshold: -log10(NFA) \> log_eps. Used only when advance refinement is chosen. @param _density_th Minimal density of aligned region points in the enclosing rectangle. @param _n_bins Number of bins in pseudo-ordering of gradient modulus. @@ -1060,7 +1307,7 @@ smoothing kernels (a symmetrical kernel with sum of weights equal to 1) and hand You may also use the higher-level GaussianBlur. @param ksize Aperture size. It should be odd ( \f$\texttt{ksize} \mod 2 = 1\f$ ) and positive. @param sigma Gaussian standard deviation. If it is non-positive, it is computed from ksize as -`sigma = 0.3\*((ksize-1)\*0.5 - 1) + 0.8`. +`sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8`. @param ktype Type of filter coefficients. It can be CV_32F or CV_64F . @sa sepFilter2D, getDerivKernels, getStructuringElement, GaussianBlur */ @@ -1069,8 +1316,8 @@ CV_EXPORTS_W Mat getGaussianKernel( int ksize, double sigma, int ktype = CV_64F /** @brief Returns filter coefficients for computing spatial image derivatives. The function computes and returns the filter coefficients for spatial image derivatives. When -`ksize=CV_SCHARR`, the Scharr \f$3 \times 3\f$ kernels are generated (see cv::Scharr). Otherwise, Sobel -kernels are generated (see cv::Sobel). The filters are normally passed to sepFilter2D or to +`ksize=CV_SCHARR`, the Scharr \f$3 \times 3\f$ kernels are generated (see #Scharr). Otherwise, Sobel +kernels are generated (see #Sobel). The filters are normally passed to #sepFilter2D or to @param kx Output matrix of row filter coefficients. It has the type ktype . @param ky Output matrix of column filter coefficients. It has the type ktype . @@ -1109,11 +1356,11 @@ static inline Scalar morphologyDefaultBorderValue() { return Scalar::all(DBL_MAX /** @brief Returns a structuring element of the specified size and shape for morphological operations. -The function constructs and returns the structuring element that can be further passed to cv::erode, -cv::dilate or cv::morphologyEx. But you can also construct an arbitrary binary mask yourself and use it as +The function constructs and returns the structuring element that can be further passed to #erode, +#dilate or #morphologyEx. But you can also construct an arbitrary binary mask yourself and use it as the structuring element. -@param shape Element shape that could be one of cv::MorphShapes +@param shape Element shape that could be one of #MorphShapes @param ksize Size of the structuring element. @param anchor Anchor position within the element. The default value \f$(-1, -1)\f$ means that the anchor is at the center. Note that only the shape of a cross-shaped element depends on the anchor @@ -1122,12 +1369,20 @@ operation is shifted. */ CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1)); +/** @example samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp +Sample code for simple filters +![Sample screenshot](Smoothing_Tutorial_Result_Median_Filter.jpg) +Check @ref tutorial_gausian_median_blur_bilateral_filter "the corresponding tutorial" for more details + */ + /** @brief Blurs an image using the median filter. The function smoothes an image using the median filter with the \f$\texttt{ksize} \times \texttt{ksize}\f$ aperture. Each channel of a multi-channel image is processed independently. In-place operation is supported. +@note The median filter uses #BORDER_REPLICATE internally to cope with border pixels, see #BorderTypes + @param src input 1-, 3-, or 4-channel image; when ksize is 3 or 5, the image depth should be CV_8U, CV_16U, or CV_32F, for larger aperture sizes, it can only be CV_8U. @param dst destination array of the same size and type as src. @@ -1149,10 +1404,10 @@ positive and odd. Or, they can be zero's and then they are computed from sigma. @param sigmaX Gaussian kernel standard deviation in X direction. @param sigmaY Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be equal to sigmaX, if both sigmas are zeros, they are computed from ksize.width and ksize.height, -respectively (see cv::getGaussianKernel for details); to fully control the result regardless of +respectively (see #getGaussianKernel for details); to fully control the result regardless of possible future modifications of all this semantics, it is recommended to specify all of ksize, sigmaX, and sigmaY. -@param borderType pixel extrapolation method, see cv::BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes @sa sepFilter2D, filter2D, blur, boxFilter, bilateralFilter, medianBlur */ @@ -1186,7 +1441,7 @@ in larger areas of semi-equal color. farther pixels will influence each other as long as their colors are close enough (see sigmaColor ). When d\>0, it specifies the neighborhood size regardless of sigmaSpace. Otherwise, d is proportional to sigmaSpace. -@param borderType border mode used to extrapolate pixels outside of the image, see cv::BorderTypes +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes */ CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, @@ -1194,7 +1449,7 @@ CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d, /** @brief Blurs an image using the box filter. -The function smoothes an image using the kernel: +The function smooths an image using the kernel: \f[\texttt{K} = \alpha \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \end{bmatrix}\f] @@ -1204,7 +1459,7 @@ where Unnormalized box filter is useful for computing various integral characteristics over each pixel neighborhood, such as covariance matrices of image derivatives (used in dense optical flow -algorithms, and so on). If you need to compute pixel sums over variable-size windows, use cv::integral. +algorithms, and so on). If you need to compute pixel sums over variable-size windows, use #integral. @param src input image. @param dst output image of the same size and type as src. @@ -1213,7 +1468,7 @@ algorithms, and so on). If you need to compute pixel sums over variable-size win @param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel center. @param normalize flag, specifying whether the kernel is normalized by its area or not. -@param borderType border mode used to extrapolate pixels outside of the image, see cv::BorderTypes +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes @sa blur, bilateralFilter, GaussianBlur, medianBlur, integral */ CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth, @@ -1229,24 +1484,24 @@ pixel values which overlap the filter placed over the pixel \f$ (x, y) \f$. The unnormalized square box filter can be useful in computing local image statistics such as the the local variance and standard deviation around the neighborhood of a pixel. -@param _src input image -@param _dst output image of the same size and type as _src +@param src input image +@param dst output image of the same size and type as _src @param ddepth the output image depth (-1 to use src.depth()) @param ksize kernel size @param anchor kernel anchor point. The default value of Point(-1, -1) denotes that the anchor is at the kernel center. @param normalize flag, specifying whether the kernel is to be normalized by it's area or not. -@param borderType border mode used to extrapolate pixels outside of the image, see cv::BorderTypes +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes @sa boxFilter */ -CV_EXPORTS_W void sqrBoxFilter( InputArray _src, OutputArray _dst, int ddepth, +CV_EXPORTS_W void sqrBoxFilter( InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor = Point(-1, -1), bool normalize = true, int borderType = BORDER_DEFAULT ); /** @brief Blurs an image using the normalized box filter. -The function smoothes an image using the kernel: +The function smooths an image using the kernel: \f[\texttt{K} = \frac{1}{\texttt{ksize.width*ksize.height}} \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \end{bmatrix}\f] @@ -1259,7 +1514,7 @@ the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. @param ksize blurring kernel size. @param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel center. -@param borderType border mode used to extrapolate pixels outside of the image, see cv::BorderTypes +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes @sa boxFilter, bilateralFilter, GaussianBlur, medianBlur */ CV_EXPORTS_W void blur( InputArray src, OutputArray dst, @@ -1277,7 +1532,7 @@ The function does actually compute correlation, not the convolution: \f[\texttt{dst} (x,y) = \sum _{ \stackrel{0\leq x' < \texttt{kernel.cols},}{0\leq y' < \texttt{kernel.rows}} } \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} )\f] That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip -the kernel using cv::flip and set the new anchor to `(kernel.cols - anchor.x - 1, kernel.rows - +the kernel using #flip and set the new anchor to `(kernel.cols - anchor.x - 1, kernel.rows - anchor.y - 1)`. The function uses the DFT-based algorithm in case of sufficiently large kernels (~`11 x 11` or @@ -1293,7 +1548,7 @@ separate color planes using split and process them individually. the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor is at the kernel center. @param delta optional value added to the filtered pixels before storing them in dst. -@param borderType pixel extrapolation method, see cv::BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes @sa sepFilter2D, dft, matchTemplate */ CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth, @@ -1314,7 +1569,7 @@ kernel kernelY. The final result shifted by delta is stored in dst . @param anchor Anchor position within the kernel. The default value \f$(-1,-1)\f$ means that the anchor is at the kernel center. @param delta Value added to the filtered results before storing them. -@param borderType Pixel extrapolation method, see cv::BorderTypes +@param borderType Pixel extrapolation method, see #BorderTypes @sa filter2D, Sobel, GaussianBlur, boxFilter, blur */ CV_EXPORTS_W void sepFilter2D( InputArray src, OutputArray dst, int ddepth, @@ -1322,6 +1577,12 @@ CV_EXPORTS_W void sepFilter2D( InputArray src, OutputArray dst, int ddepth, Point anchor = Point(-1,-1), double delta = 0, int borderType = BORDER_DEFAULT ); +/** @example samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp +Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector +![Sample screenshot](Sobel_Derivatives_Tutorial_Result.jpg) +Check @ref tutorial_sobel_derivatives "the corresponding tutorial" for more details +*/ + /** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator. In all cases except one, the \f$\texttt{ksize} \times \texttt{ksize}\f$ separable kernel is used to @@ -1329,7 +1590,7 @@ calculate the derivative. When \f$\texttt{ksize = 1}\f$, the \f$3 \times 1\f$ or kernel is used (that is, no Gaussian smoothing is done). `ksize = 1` can only be used for the first or the second x- or y- derivatives. -There is also the special value `ksize = CV_SCHARR (-1)` that corresponds to the \f$3\times3\f$ Scharr +There is also the special value `ksize = #CV_SCHARR (-1)` that corresponds to the \f$3\times3\f$ Scharr filter that may give more accurate results than the \f$3\times3\f$ Sobel. The Scharr aperture is \f[\vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3}\f] @@ -1359,9 +1620,9 @@ The second case corresponds to a kernel of: @param dy order of the derivative y. @param ksize size of the extended Sobel kernel; it must be 1, 3, 5, or 7. @param scale optional scale factor for the computed derivative values; by default, no scaling is -applied (see cv::getDerivKernels for details). +applied (see #getDerivKernels for details). @param delta optional delta value that is added to the results prior to storing them in dst. -@param borderType pixel extrapolation method, see cv::BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes @sa Scharr, Laplacian, sepFilter2D, filter2D, GaussianBlur, cartToPolar */ CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth, @@ -1369,6 +1630,28 @@ CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT ); +/** @brief Calculates the first order image derivative in both x and y using a Sobel operator + +Equivalent to calling: + +@code +Sobel( src, dx, CV_16SC1, 1, 0, 3 ); +Sobel( src, dy, CV_16SC1, 0, 1, 3 ); +@endcode + +@param src input image. +@param dx output image with first-order derivative in x. +@param dy output image with first-order derivative in y. +@param ksize size of Sobel kernel. It must be 3. +@param borderType pixel extrapolation method, see #BorderTypes + +@sa Sobel + */ + +CV_EXPORTS_W void spatialGradient( InputArray src, OutputArray dx, + OutputArray dy, int ksize = 3, + int borderType = BORDER_DEFAULT ); + /** @brief Calculates the first x- or y- image derivative using Scharr operator. The function computes the first x- or y- spatial image derivative using the Scharr operator. The @@ -1378,7 +1661,7 @@ call is equivalent to -\f[\texttt{Sobel(src, dst, ddepth, dx, dy, CV\_SCHARR, scale, delta, borderType)} .\f] +\f[\texttt{Sobel(src, dst, ddepth, dx, dy, CV_SCHARR, scale, delta, borderType)} .\f] @param src input image. @param dst output image of the same size and the same number of channels as src. @@ -1386,17 +1669,17 @@ is equivalent to @param dx order of the derivative x. @param dy order of the derivative y. @param scale optional scale factor for the computed derivative values; by default, no scaling is -applied (see getDerivKernels for details). +applied (see #getDerivKernels for details). @param delta optional delta value that is added to the results prior to storing them in dst. -@param borderType pixel extrapolation method, see cv::BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes @sa cartToPolar */ CV_EXPORTS_W void Scharr( InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT ); -/** @example laplace.cpp - An example using Laplace transformations for edge detection +/** @example samples/cpp/laplace.cpp +An example using Laplace transformations for edge detection */ /** @brief Calculates the Laplacian of an image. @@ -1414,12 +1697,12 @@ with the following \f$3 \times 3\f$ aperture: @param src Source image. @param dst Destination image of the same size and the same number of channels as src . @param ddepth Desired depth of the destination image. -@param ksize Aperture size used to compute the second-derivative filters. See getDerivKernels for +@param ksize Aperture size used to compute the second-derivative filters. See #getDerivKernels for details. The size must be positive and odd. @param scale Optional scale factor for the computed Laplacian values. By default, no scaling is -applied. See getDerivKernels for details. +applied. See #getDerivKernels for details. @param delta Optional delta value that is added to the results prior to storing them in dst . -@param borderType Pixel extrapolation method, see cv::BorderTypes +@param borderType Pixel extrapolation method, see #BorderTypes @sa Sobel, Scharr */ CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth, @@ -1431,13 +1714,15 @@ CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth, //! @addtogroup imgproc_feature //! @{ -/** @example edge.cpp - An example on using the canny edge detector +/** @example samples/cpp/edge.cpp +This program demonstrates usage of the Canny edge detector + +Check @ref tutorial_canny_detector "the corresponding tutorial" for more details */ /** @brief Finds edges in an image using the Canny algorithm @cite Canny86 . -The function finds edges in the input image image and marks them in the output map edges using the +The function finds edges in the input image and marks them in the output map edges using the Canny algorithm. The smallest value between threshold1 and threshold2 is used for edge linking. The largest value is used to find initial segments of strong edges. See @@ -1456,6 +1741,25 @@ CV_EXPORTS_W void Canny( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false ); +/** \overload + +Finds edges in an image using the Canny algorithm with custom image gradient. + +@param dx 16-bit x derivative of input image (CV_16SC1 or CV_16SC3). +@param dy 16-bit y derivative of input image (same type as dx). +@param edges output edge map; single channels 8-bit image, which has the same size as image . +@param threshold1 first threshold for the hysteresis procedure. +@param threshold2 second threshold for the hysteresis procedure. +@param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm +\f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude ( +L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough ( +L2gradient=false ). + */ +CV_EXPORTS_W void Canny( InputArray dx, InputArray dy, + OutputArray edges, + double threshold1, double threshold2, + bool L2gradient = false ); + /** @brief Calculates the minimal eigenvalue of gradient matrices for corner detection. The function is similar to cornerEigenValsAndVecs but it calculates and stores only the minimal @@ -1465,9 +1769,9 @@ of the formulae in the cornerEigenValsAndVecs description. @param src Input single-channel 8-bit or floating-point image. @param dst Image to store the minimal eigenvalues. It has the type CV_32FC1 and the same size as src . -@param blockSize Neighborhood size (see the details on cornerEigenValsAndVecs ). +@param blockSize Neighborhood size (see the details on #cornerEigenValsAndVecs ). @param ksize Aperture parameter for the Sobel operator. -@param borderType Pixel extrapolation method. See cv::BorderTypes. +@param borderType Pixel extrapolation method. See #BorderTypes. */ CV_EXPORTS_W void cornerMinEigenVal( InputArray src, OutputArray dst, int blockSize, int ksize = 3, @@ -1487,10 +1791,10 @@ Corners in the image can be found as the local maxima of this response map. @param src Input single-channel 8-bit or floating-point image. @param dst Image to store the Harris detector responses. It has the type CV_32FC1 and the same size as src . -@param blockSize Neighborhood size (see the details on cornerEigenValsAndVecs ). +@param blockSize Neighborhood size (see the details on #cornerEigenValsAndVecs ). @param ksize Aperture parameter for the Sobel operator. -@param k Harris detector free parameter. See the formula below. -@param borderType Pixel extrapolation method. See cv::BorderTypes. +@param k Harris detector free parameter. See the formula above. +@param borderType Pixel extrapolation method. See #BorderTypes. */ CV_EXPORTS_W void cornerHarris( InputArray src, OutputArray dst, int blockSize, int ksize, double k, @@ -1518,7 +1822,7 @@ The output of the function can be used for robust edge or corner detection. @param dst Image to store the results. It has the same size as src and the type CV_32FC(6) . @param blockSize Neighborhood size (see details below). @param ksize Aperture parameter for the Sobel operator. -@param borderType Pixel extrapolation method. See cv::BorderTypes. +@param borderType Pixel extrapolation method. See #BorderTypes. @sa cornerMinEigenVal, cornerHarris, preCornerDetect */ @@ -1547,7 +1851,7 @@ The corners can be found as local maximums of the functions, as shown below: @param src Source single-channel 8-bit of floating-point image. @param dst Output image that has the type CV_32F and the same size as src . @param ksize %Aperture size of the Sobel . -@param borderType Pixel extrapolation method. See cv::BorderTypes. +@param borderType Pixel extrapolation method. See #BorderTypes. */ CV_EXPORTS_W void preCornerDetect( InputArray src, OutputArray dst, int ksize, int borderType = BORDER_DEFAULT ); @@ -1569,7 +1873,7 @@ where \f${DI_{p_i}}\f$ is an image gradient at one of the points \f$p_i\f$ in a value of \f$q\f$ is to be found so that \f$\epsilon_i\f$ is minimized. A system of equations may be set up with \f$\epsilon_i\f$ set to zero: -\f[\sum _i(DI_{p_i} \cdot {DI_{p_i}}^T) - \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T \cdot p_i)\f] +\f[\sum _i(DI_{p_i} \cdot {DI_{p_i}}^T) \cdot q - \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T \cdot p_i)\f] where the gradients are summed within a neighborhood ("search window") of \f$q\f$ . Calling the first gradient term \f$G\f$ and the second gradient term \f$b\f$ gives: @@ -1579,11 +1883,11 @@ gradient term \f$G\f$ and the second gradient term \f$b\f$ gives: The algorithm sets the center of the neighborhood window at this new center \f$q\f$ and then iterates until the center stays within a set threshold. -@param image Input image. +@param image Input single-channel, 8-bit or float image. @param corners Initial coordinates of the input corners and refined coordinates provided for output. @param winSize Half of the side length of the search window. For example, if winSize=Size(5,5) , -then a \f$5*2+1 \times 5*2+1 = 11 \times 11\f$ search window is used. +then a \f$(5*2+1) \times (5*2+1) = 11 \times 11\f$ search window is used. @param zeroZone Half of the size of the dead region in the middle of the search zone over which the summation in the formula below is not done. It is used sometimes to avoid possible singularities of the autocorrelation matrix. The value of (-1,-1) indicates that there is no such @@ -1602,7 +1906,7 @@ The function finds the most prominent corners in the image or in the specified i described in @cite Shi94 - Function calculates the corner quality measure at every source image pixel using the - cornerMinEigenVal or cornerHarris . + #cornerMinEigenVal or #cornerHarris . - Function performs a non-maximum suppression (the local maximums in *3 x 3* neighborhood are retained). - The corners with the minimal eigenvalue less than @@ -1620,10 +1924,11 @@ with qualityLevel=B . @param image Input 8-bit or floating-point 32-bit, single-channel image. @param corners Output vector of detected corners. @param maxCorners Maximum number of corners to return. If there are more corners than are found, -the strongest of them is returned. +the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set +and all detected corners are returned. @param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue -(see cornerMinEigenVal ) or the Harris function response (see cornerHarris ). The corners with the +(see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the quality measure less than the product are rejected. For example, if the best corner has the quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure less than 15 are rejected. @@ -1632,19 +1937,26 @@ less than 15 are rejected. CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected. @param blockSize Size of an average block for computing a derivative covariation matrix over each pixel neighborhood. See cornerEigenValsAndVecs . -@param useHarrisDetector Parameter indicating whether to use a Harris detector (see cornerHarris) -or cornerMinEigenVal. +@param useHarrisDetector Parameter indicating whether to use a Harris detector (see #cornerHarris) +or #cornerMinEigenVal. @param k Free parameter of the Harris detector. @sa cornerMinEigenVal, cornerHarris, calcOpticalFlowPyrLK, estimateRigidTransform, */ + CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners, int maxCorners, double qualityLevel, double minDistance, InputArray mask = noArray(), int blockSize = 3, bool useHarrisDetector = false, double k = 0.04 ); -/** @example houghlines.cpp +CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners, + int maxCorners, double qualityLevel, double minDistance, + InputArray mask, int blockSize, + int gradientSize, bool useHarrisDetector = false, + double k = 0.04 ); +/** @example samples/cpp/tutorial_code/ImgTrans/houghlines.cpp An example using the Hough line detector +![Sample input image](Hough_Lines_Tutorial_Original_Image.jpg) ![Output image](Hough_Lines_Tutorial_Result.jpg) */ /** @brief Finds lines in a binary image using the standard Hough transform. @@ -1654,10 +1966,11 @@ detection. See for a good ex transform. @param image 8-bit, single-channel binary source image. The image may be modified by the function. -@param lines Output vector of lines. Each line is represented by a two-element vector -\f$(\rho, \theta)\f$ . \f$\rho\f$ is the distance from the coordinate origin \f$(0,0)\f$ (top-left corner of +@param lines Output vector of lines. Each line is represented by a 2 or 3 element vector +\f$(\rho, \theta)\f$ or \f$(\rho, \theta, \textrm{votes})\f$ . \f$\rho\f$ is the distance from the coordinate origin \f$(0,0)\f$ (top-left corner of the image). \f$\theta\f$ is the line rotation angle in radians ( \f$0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line}\f$ ). +\f$\textrm{votes}\f$ is the value of accumulator. @param rho Distance resolution of the accumulator in pixels. @param theta Angle resolution of the accumulator in radians. @param threshold Accumulator threshold parameter. Only those lines are returned that get enough @@ -1683,57 +1996,7 @@ The function implements the probabilistic Hough transform algorithm for line det in @cite Matas00 See the line detection example below: - -@code - #include - #include - - using namespace cv; - - int main(int argc, char** argv) - { - Mat src, dst, color_dst; - if( argc != 2 || !(src=imread(argv[1], 0)).data) - return -1; - - Canny( src, dst, 50, 200, 3 ); - cvtColor( dst, color_dst, COLOR_GRAY2BGR ); - - #if 0 - vector lines; - HoughLines( dst, lines, 1, CV_PI/180, 100 ); - - for( size_t i = 0; i < lines.size(); i++ ) - { - float rho = lines[i][0]; - float theta = lines[i][1]; - double a = cos(theta), b = sin(theta); - double x0 = a*rho, y0 = b*rho; - Point pt1(cvRound(x0 + 1000*(-b)), - cvRound(y0 + 1000*(a))); - Point pt2(cvRound(x0 - 1000*(-b)), - cvRound(y0 - 1000*(a))); - line( color_dst, pt1, pt2, Scalar(0,0,255), 3, 8 ); - } - #else - vector lines; - HoughLinesP( dst, lines, 1, CV_PI/180, 80, 30, 10 ); - for( size_t i = 0; i < lines.size(); i++ ) - { - line( color_dst, Point(lines[i][0], lines[i][1]), - Point(lines[i][2], lines[i][3]), Scalar(0,0,255), 3, 8 ); - } - #endif - namedWindow( "Source", 1 ); - imshow( "Source", src ); - - namedWindow( "Detected Lines", 1 ); - imshow( "Detected Lines", color_dst ); - - waitKey(0); - return 0; - } -@endcode +@include snippets/imgproc_HoughLinesP.cpp This is a sample picture the function parameters have been tuned for: ![image](pics/building.jpg) @@ -1759,7 +2022,28 @@ CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0 ); -/** @example houghcircles.cpp +/** @brief Finds lines in a set of points using the standard Hough transform. + +The function finds lines in a set of points using a modification of the Hough transform. +@include snippets/imgproc_HoughLinesPointSet.cpp +@param _point Input vector of points. Each vector must be encoded as a Point vector \f$(x,y)\f$. Type must be CV_32FC2 or CV_32SC2. +@param _lines Output vector of found lines. Each vector is encoded as a vector \f$(votes, rho, theta)\f$. +The larger the value of 'votes', the higher the reliability of the Hough line. +@param lines_max Max count of hough lines. +@param threshold Accumulator threshold parameter. Only those lines are returned that get enough +votes ( \f$>\texttt{threshold}\f$ ) +@param min_rho Minimum Distance value of the accumulator in pixels. +@param max_rho Maximum Distance value of the accumulator in pixels. +@param rho_step Distance resolution of the accumulator in pixels. +@param min_theta Minimum angle value of the accumulator in radians. +@param max_theta Maximum angle value of the accumulator in radians. +@param theta_step Angle resolution of the accumulator in radians. + */ +CV_EXPORTS_W void HoughLinesPointSet( InputArray _point, OutputArray _lines, int lines_max, int threshold, + double min_rho, double max_rho, double rho_step, + double min_theta, double max_theta, double theta_step ); + +/** @example samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp An example using the Hough circle detector */ @@ -1768,62 +2052,32 @@ An example using the Hough circle detector The function finds circles in a grayscale image using a modification of the Hough transform. Example: : -@code - #include - #include - #include - - using namespace cv; - - int main(int argc, char** argv) - { - Mat img, gray; - if( argc != 2 && !(img=imread(argv[1], 1)).data) - return -1; - cvtColor(img, gray, COLOR_BGR2GRAY); - // smooth it, otherwise a lot of false circles may be detected - GaussianBlur( gray, gray, Size(9, 9), 2, 2 ); - vector circles; - HoughCircles(gray, circles, HOUGH_GRADIENT, - 2, gray->rows/4, 200, 100 ); - for( size_t i = 0; i < circles.size(); i++ ) - { - Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); - int radius = cvRound(circles[i][2]); - // draw the circle center - circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 ); - // draw the circle outline - circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 ); - } - namedWindow( "circles", 1 ); - imshow( "circles", img ); - return 0; - } -@endcode +@include snippets/imgproc_HoughLinesCircles.cpp @note Usually the function detects the centers of circles well. However, it may fail to find correct radii. You can assist to the function by specifying the radius range ( minRadius and maxRadius ) if -you know it. Or, you may ignore the returned radius, use only the center, and find the correct -radius using an additional procedure. +you know it. Or, you may set maxRadius to a negative number to return centers only without radius +search, and find the correct radius using an additional procedure. @param image 8-bit, single-channel, grayscale input image. -@param circles Output vector of found circles. Each vector is encoded as a 3-element -floating-point vector \f$(x, y, radius)\f$ . -@param method Detection method, see cv::HoughModes. Currently, the only implemented method is HOUGH_GRADIENT +@param circles Output vector of found circles. Each vector is encoded as 3 or 4 element +floating-point vector \f$(x, y, radius)\f$ or \f$(x, y, radius, votes)\f$ . +@param method Detection method, see #HoughModes. Currently, the only implemented method is #HOUGH_GRADIENT @param dp Inverse ratio of the accumulator resolution to the image resolution. For example, if dp=1 , the accumulator has the same resolution as the input image. If dp=2 , the accumulator has half as big width and height. @param minDist Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed. -@param param1 First method-specific parameter. In case of CV_HOUGH_GRADIENT , it is the higher +@param param1 First method-specific parameter. In case of #HOUGH_GRADIENT , it is the higher threshold of the two passed to the Canny edge detector (the lower one is twice smaller). -@param param2 Second method-specific parameter. In case of CV_HOUGH_GRADIENT , it is the +@param param2 Second method-specific parameter. In case of #HOUGH_GRADIENT , it is the accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first. @param minRadius Minimum circle radius. -@param maxRadius Maximum circle radius. +@param maxRadius Maximum circle radius. If <= 0, uses the maximum image dimension. If < 0, returns +centers without finding the radius. @sa fitEllipse, minEnclosingCircle */ @@ -1837,8 +2091,10 @@ CV_EXPORTS_W void HoughCircles( InputArray image, OutputArray circles, //! @addtogroup imgproc_filter //! @{ -/** @example morphology2.cpp - An example using the morphological operations +/** @example samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp +Advanced morphology Transformations sample code +![Sample screenshot](Morphology_2_Tutorial_Result.jpg) +Check @ref tutorial_opening_closing_hats "the corresponding tutorial" for more details */ /** @brief Erodes an image by using a specific structuring element. @@ -1855,11 +2111,11 @@ case of multi-channel images, each channel is processed independently. CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. @param dst output image of the same size and type as src. @param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular -structuring element is used. Kernel can be created using getStructuringElement. +structuring element is used. Kernel can be created using #getStructuringElement. @param anchor position of the anchor within the element; default value (-1, -1) means that the anchor is at the element center. @param iterations number of times erosion is applied. -@param borderType pixel extrapolation method, see cv::BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes @param borderValue border value in case of a constant border @sa dilate, morphologyEx, getStructuringElement */ @@ -1868,6 +2124,12 @@ CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() ); +/** @example samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp +Erosion and Dilation sample code +![Sample Screenshot-Erosion](Morphology_1_Tutorial_Erosion_Result.jpg)![Sample Screenshot-Dilation](Morphology_1_Tutorial_Dilation_Result.jpg) +Check @ref tutorial_erosion_dilatation "the corresponding tutorial" for more details +*/ + /** @brief Dilates an image by using a specific structuring element. The function dilates the source image using the specified structuring element that determines the @@ -1879,13 +2141,13 @@ case of multi-channel images, each channel is processed independently. @param src input image; the number of channels can be arbitrary, but the depth should be one of CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. -@param dst output image of the same size and type as src\`. +@param dst output image of the same size and type as src. @param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular -structuring element is used. Kernel can be created using getStructuringElement +structuring element is used. Kernel can be created using #getStructuringElement @param anchor position of the anchor within the element; default value (-1, -1) means that the anchor is at the element center. @param iterations number of times dilation is applied. -@param borderType pixel extrapolation method, see cv::BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes @param borderValue border value in case of a constant border @sa erode, morphologyEx, getStructuringElement */ @@ -1896,7 +2158,7 @@ CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel, /** @brief Performs advanced morphological transformations. -The function can perform advanced morphological transformations using an erosion and dilation as +The function cv::morphologyEx can perform advanced morphological transformations using an erosion and dilation as basic operations. Any of the operations can be done in-place. In case of multi-channel images, each channel is @@ -1904,16 +2166,19 @@ processed independently. @param src Source image. The number of channels can be arbitrary. The depth should be one of CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. -@param dst Destination image of the same size and type as src\` . -@param kernel Structuring element. It can be created using getStructuringElement. +@param dst Destination image of the same size and type as source image. +@param op Type of a morphological operation, see #MorphTypes +@param kernel Structuring element. It can be created using #getStructuringElement. @param anchor Anchor position with the kernel. Negative values mean that the anchor is at the kernel center. -@param op Type of a morphological operation, see cv::MorphTypes @param iterations Number of times erosion and dilation are applied. -@param borderType Pixel extrapolation method, see cv::BorderTypes +@param borderType Pixel extrapolation method, see #BorderTypes @param borderValue Border value in case of a constant border. The default value has a special meaning. @sa dilate, erode, getStructuringElement +@note The number of iterations is the number of times erosion or dilatation operation will be applied. +For instance, an opening operation (#MORPH_OPEN) with two iterations is equivalent to apply +successively: erode -> erode -> dilate -> dilate (and not erode -> dilate -> erode -> dilate). */ CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel, @@ -1942,8 +2207,8 @@ way: // specify fx and fy and let the function compute the destination image size. resize(src, dst, Size(), 0.5, 0.5, interpolation); @endcode -To shrink an image, it will generally look best with CV_INTER_AREA interpolation, whereas to -enlarge an image, it will generally look best with CV_INTER_CUBIC (slow) or CV_INTER_LINEAR +To shrink an image, it will generally look best with #INTER_AREA interpolation, whereas to +enlarge an image, it will generally look best with c#INTER_CUBIC (slow) or #INTER_LINEAR (faster but still looks OK). @param src input image. @@ -1956,7 +2221,7 @@ src.size(), fx, and fy; the type of dst is the same as of src. \f[\texttt{(double)dsize.width/src.cols}\f] @param fy scale factor along the vertical axis; when it equals 0, it is computed as \f[\texttt{(double)dsize.height/src.rows}\f] -@param interpolation interpolation method, see cv::InterpolationFlags +@param interpolation interpolation method, see #InterpolationFlags @sa warpAffine, warpPerspective, remap */ @@ -1970,19 +2235,19 @@ The function warpAffine transforms the source image using the specified matrix: \f[\texttt{dst} (x,y) = \texttt{src} ( \texttt{M} _{11} x + \texttt{M} _{12} y + \texttt{M} _{13}, \texttt{M} _{21} x + \texttt{M} _{22} y + \texttt{M} _{23})\f] -when the flag WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted -with cv::invertAffineTransform and then put in the formula above instead of M. The function cannot +when the flag #WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted +with #invertAffineTransform and then put in the formula above instead of M. The function cannot operate in-place. @param src input image. @param dst output image that has the size dsize and the same type as src . @param M \f$2\times 3\f$ transformation matrix. @param dsize size of the output image. -@param flags combination of interpolation methods (see cv::InterpolationFlags) and the optional -flag WARP_INVERSE_MAP that means that M is the inverse transformation ( +@param flags combination of interpolation methods (see #InterpolationFlags) and the optional +flag #WARP_INVERSE_MAP that means that M is the inverse transformation ( \f$\texttt{dst}\rightarrow\texttt{src}\f$ ). -@param borderMode pixel extrapolation method (see cv::BorderTypes); when -borderMode=BORDER_TRANSPARENT, it means that the pixels in the destination image corresponding to +@param borderMode pixel extrapolation method (see #BorderTypes); when +borderMode=#BORDER_TRANSPARENT, it means that the pixels in the destination image corresponding to the "outliers" in the source image are not modified by the function. @param borderValue value used in case of a constant border; by default, it is 0. @@ -1994,6 +2259,10 @@ CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst, int borderMode = BORDER_CONSTANT, const Scalar& borderValue = Scalar()); +/** @example samples/cpp/warpPerspective_demo.cpp +An example program shows using cv::findHomography and cv::warpPerspective for image warping +*/ + /** @brief Applies a perspective transformation to an image. The function warpPerspective transforms the source image using the specified matrix: @@ -2001,17 +2270,17 @@ The function warpPerspective transforms the source image using the specified mat \f[\texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right )\f] -when the flag WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted with invert +when the flag #WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted with invert and then put in the formula above instead of M. The function cannot operate in-place. @param src input image. @param dst output image that has the size dsize and the same type as src . @param M \f$3\times 3\f$ transformation matrix. @param dsize size of the output image. -@param flags combination of interpolation methods (INTER_LINEAR or INTER_NEAREST) and the -optional flag WARP_INVERSE_MAP, that sets M as the inverse transformation ( +@param flags combination of interpolation methods (#INTER_LINEAR or #INTER_NEAREST) and the +optional flag #WARP_INVERSE_MAP, that sets M as the inverse transformation ( \f$\texttt{dst}\rightarrow\texttt{src}\f$ ). -@param borderMode pixel extrapolation method (BORDER_CONSTANT or BORDER_REPLICATE). +@param borderMode pixel extrapolation method (#BORDER_CONSTANT or #BORDER_REPLICATE). @param borderValue value used in case of a constant border; by default, it equals 0. @sa warpAffine, resize, remap, getRectSubPix, perspectiveTransform @@ -2045,12 +2314,14 @@ CV_32FC1, or CV_32FC2. See convertMaps for details on converting a floating poin representation to fixed-point for speed. @param map2 The second map of y values having the type CV_16UC1, CV_32FC1, or none (empty map if map1 is (x,y) points), respectively. -@param interpolation Interpolation method (see cv::InterpolationFlags). The method INTER_AREA is +@param interpolation Interpolation method (see #InterpolationFlags). The method #INTER_AREA is not supported by this function. -@param borderMode Pixel extrapolation method (see cv::BorderTypes). When -borderMode=BORDER_TRANSPARENT, it means that the pixels in the destination image that +@param borderMode Pixel extrapolation method (see #BorderTypes). When +borderMode=#BORDER_TRANSPARENT, it means that the pixels in the destination image that corresponds to the "outliers" in the source image are not modified by the function. @param borderValue Value used in case of a constant border. By default, it is 0. +@note +Due to current implementation limitations the size of an input and output images should be less than 32767x32767. */ CV_EXPORTS_W void remap( InputArray src, OutputArray dst, InputArray map1, InputArray map2, @@ -2063,13 +2334,13 @@ The function converts a pair of maps for remap from one representation to anothe options ( (map1.type(), map2.type()) \f$\rightarrow\f$ (dstmap1.type(), dstmap2.type()) ) are supported: -- \f$\texttt{(CV\_32FC1, CV\_32FC1)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)}\f$. This is the +- \f$\texttt{(CV_32FC1, CV_32FC1)} \rightarrow \texttt{(CV_16SC2, CV_16UC1)}\f$. This is the most frequently used conversion operation, in which the original floating-point maps (see remap ) are converted to a more compact and much faster fixed-point representation. The first output array contains the rounded coordinates and the second array (created only when nninterpolation=false ) contains indices in the interpolation tables. -- \f$\texttt{(CV\_32FC2)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)}\f$. The same as above but +- \f$\texttt{(CV_32FC2)} \rightarrow \texttt{(CV_16SC2, CV_16UC1)}\f$. The same as above but the original maps are stored in one 2-channel matrix. - Reverse conversion. Obviously, the reconstructed floating-point maps will not be exactly the same @@ -2119,7 +2390,7 @@ CV_EXPORTS Mat getPerspectiveTransform( const Point2f src[], const Point2f dst[] The function calculates the \f$2 \times 3\f$ matrix of an affine transform so that: -\f[\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] +\f[\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] where @@ -2149,7 +2420,7 @@ CV_EXPORTS_W void invertAffineTransform( InputArray M, OutputArray iM ); The function calculates the \f$3 \times 3\f$ matrix of a perspective transform so that: -\f[\begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] +\f[\begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] where @@ -2168,13 +2439,12 @@ CV_EXPORTS_W Mat getAffineTransform( InputArray src, InputArray dst ); The function getRectSubPix extracts pixels from src: -\f[dst(x, y) = src(x + \texttt{center.x} - ( \texttt{dst.cols} -1)*0.5, y + \texttt{center.y} - ( \texttt{dst.rows} -1)*0.5)\f] +\f[patch(x, y) = src(x + \texttt{center.x} - ( \texttt{dst.cols} -1)*0.5, y + \texttt{center.y} - ( \texttt{dst.rows} -1)*0.5)\f] where the values of the pixels at non-integer coordinates are retrieved using bilinear -interpolation. Every channel of multi-channel images is processed independently. While the center of -the rectangle must be inside the image, parts of the rectangle may be outside. In this case, the -replication border mode (see cv::BorderTypes) is used to extrapolate the pixel values outside of -the image. +interpolation. Every channel of multi-channel images is processed independently. Also +the image should be a single channel or three channel image. While the center of the +rectangle must be inside the image, parts of the rectangle may be outside. @param image Source image. @param patchSize Size of the extracted patch. @@ -2188,48 +2458,185 @@ source image. The center must be inside the image. CV_EXPORTS_W void getRectSubPix( InputArray image, Size patchSize, Point2f center, OutputArray patch, int patchType = -1 ); -/** @example polar_transforms.cpp +/** @example samples/cpp/polar_transforms.cpp An example using the cv::linearPolar and cv::logPolar operations */ -/** @brief Remaps an image to log-polar space. +/** @brief Remaps an image to semilog-polar coordinates space. + +@deprecated This function produces same result as cv::warpPolar(src, dst, src.size(), center, maxRadius, flags+WARP_POLAR_LOG); + +@internal +Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image d)"): +\f[\begin{array}{l} + dst( \rho , \phi ) = src(x,y) \\ + dst.size() \leftarrow src.size() +\end{array}\f] -transforms the source image using the following transformation: -\f[dst( \phi , \rho ) = src(x,y)\f] where -\f[\rho = M \cdot \log{\sqrt{x^2 + y^2}} , \phi =atan(y/x)\f] +\f[\begin{array}{l} + I = (dx,dy) = (x - center.x,y - center.y) \\ + \rho = M \cdot log_e(\texttt{magnitude} (I)) ,\\ + \phi = Kangle \cdot \texttt{angle} (I) \\ +\end{array}\f] + +and +\f[\begin{array}{l} + M = src.cols / log_e(maxRadius) \\ + Kangle = src.rows / 2\Pi \\ +\end{array}\f] The function emulates the human "foveal" vision and can be used for fast scale and -rotation-invariant template matching, for object tracking and so forth. The function can not operate -in-place. - +rotation-invariant template matching, for object tracking and so forth. @param src Source image -@param dst Destination image +@param dst Destination image. It will have same size and type as src. @param center The transformation center; where the output precision is maximal -@param M Magnitude scale parameter. -@param flags A combination of interpolation methods, see cv::InterpolationFlags - */ +@param M Magnitude scale parameter. It determines the radius of the bounding circle to transform too. +@param flags A combination of interpolation methods, see #InterpolationFlags + +@note +- The function can not operate in-place. +- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees. + +@sa cv::linearPolar +@endinternal +*/ CV_EXPORTS_W void logPolar( InputArray src, OutputArray dst, Point2f center, double M, int flags ); -/** @brief Remaps an image to polar space. +/** @brief Remaps an image to polar coordinates space. + +@deprecated This function produces same result as cv::warpPolar(src, dst, src.size(), center, maxRadius, flags) + +@internal +Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image c)"): +\f[\begin{array}{l} + dst( \rho , \phi ) = src(x,y) \\ + dst.size() \leftarrow src.size() +\end{array}\f] -transforms the source image using the following transformation: -\f[dst( \phi , \rho ) = src(x,y)\f] where -\f[\rho = (src.width/maxRadius) \cdot \sqrt{x^2 + y^2} , \phi =atan(y/x)\f] +\f[\begin{array}{l} + I = (dx,dy) = (x - center.x,y - center.y) \\ + \rho = Kmag \cdot \texttt{magnitude} (I) ,\\ + \phi = angle \cdot \texttt{angle} (I) +\end{array}\f] + +and +\f[\begin{array}{l} + Kx = src.cols / maxRadius \\ + Ky = src.rows / 2\Pi +\end{array}\f] -The function can not operate in-place. @param src Source image -@param dst Destination image +@param dst Destination image. It will have same size and type as src. @param center The transformation center; -@param maxRadius Inverse magnitude scale parameter -@param flags A combination of interpolation methods, see cv::InterpolationFlags - */ +@param maxRadius The radius of the bounding circle to transform. It determines the inverse magnitude scale parameter too. +@param flags A combination of interpolation methods, see #InterpolationFlags + +@note +- The function can not operate in-place. +- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees. + +@sa cv::logPolar +@endinternal +*/ CV_EXPORTS_W void linearPolar( InputArray src, OutputArray dst, Point2f center, double maxRadius, int flags ); + +/** \brief Remaps an image to polar or semilog-polar coordinates space + +@anchor polar_remaps_reference_image +![Polar remaps reference](pics/polar_remap_doc.png) + +Transform the source image using the following transformation: +\f[ +dst(\rho , \phi ) = src(x,y) +\f] + +where +\f[ +\begin{array}{l} +\vec{I} = (x - center.x, \;y - center.y) \\ +\phi = Kangle \cdot \texttt{angle} (\vec{I}) \\ +\rho = \left\{\begin{matrix} +Klin \cdot \texttt{magnitude} (\vec{I}) & default \\ +Klog \cdot log_e(\texttt{magnitude} (\vec{I})) & if \; semilog \\ +\end{matrix}\right. +\end{array} +\f] + +and +\f[ +\begin{array}{l} +Kangle = dsize.height / 2\Pi \\ +Klin = dsize.width / maxRadius \\ +Klog = dsize.width / log_e(maxRadius) \\ +\end{array} +\f] + + +\par Linear vs semilog mapping + +Polar mapping can be linear or semi-log. Add one of #WarpPolarMode to `flags` to specify the polar mapping mode. + +Linear is the default mode. + +The semilog mapping emulates the human "foveal" vision that permit very high acuity on the line of sight (central vision) +in contrast to peripheral vision where acuity is minor. + +\par Option on `dsize`: + +- if both values in `dsize <=0 ` (default), +the destination image will have (almost) same area of source bounding circle: +\f[\begin{array}{l} +dsize.area \leftarrow (maxRadius^2 \cdot \Pi) \\ +dsize.width = \texttt{cvRound}(maxRadius) \\ +dsize.height = \texttt{cvRound}(maxRadius \cdot \Pi) \\ +\end{array}\f] + + +- if only `dsize.height <= 0`, +the destination image area will be proportional to the bounding circle area but scaled by `Kx * Kx`: +\f[\begin{array}{l} +dsize.height = \texttt{cvRound}(dsize.width \cdot \Pi) \\ +\end{array} +\f] + +- if both values in `dsize > 0 `, +the destination image will have the given size therefore the area of the bounding circle will be scaled to `dsize`. + + +\par Reverse mapping + +You can get reverse mapping adding #WARP_INVERSE_MAP to `flags` +\snippet polar_transforms.cpp InverseMap + +In addiction, to calculate the original coordinate from a polar mapped coordinate \f$(rho, phi)->(x, y)\f$: +\snippet polar_transforms.cpp InverseCoordinate + +@param src Source image. +@param dst Destination image. It will have same type as src. +@param dsize The destination image size (see description for valid options). +@param center The transformation center. +@param maxRadius The radius of the bounding circle to transform. It determines the inverse magnitude scale parameter too. +@param flags A combination of interpolation methods, #InterpolationFlags + #WarpPolarMode. + - Add #WARP_POLAR_LINEAR to select linear polar mapping (default) + - Add #WARP_POLAR_LOG to select semilog polar mapping + - Add #WARP_INVERSE_MAP for reverse mapping. +@note +- The function can not operate in-place. +- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees. +- This function uses #remap. Due to current implementation limitations the size of an input and output images should be less than 32767x32767. + +@sa cv::remap +*/ +CV_EXPORTS_W void warpPolar(InputArray src, OutputArray dst, Size dsize, + Point2f center, double maxRadius, int flags); + + //! @} imgproc_transform //! @addtogroup imgproc_misc @@ -2244,7 +2651,7 @@ CV_EXPORTS_AS(integral2) void integral( InputArray src, OutputArray sum, /** @brief Calculates the integral of an image. -The functions calculate one or more integral images for the source image as follows: +The function calculates one or more integral images for the source image as follows: \f[\texttt{sum} (X,Y) = \sum _{x 1) @param type Created array type */ CV_EXPORTS_W void createHanningWindow(OutputArray dst, Size winSize, int type); @@ -2427,24 +2833,25 @@ CV_EXPORTS_W void createHanningWindow(OutputArray dst, Size winSize, int type); /** @brief Applies a fixed-level threshold to each array element. -The function applies fixed-level thresholding to a single-channel array. The function is typically -used to get a bi-level (binary) image out of a grayscale image ( cv::compare could be also used for +The function applies fixed-level thresholding to a multiple-channel array. The function is typically +used to get a bi-level (binary) image out of a grayscale image ( #compare could be also used for this purpose) or for removing a noise, that is, filtering out pixels with too small or too large values. There are several types of thresholding supported by the function. They are determined by type parameter. -Also, the special values cv::THRESH_OTSU or cv::THRESH_TRIANGLE may be combined with one of the +Also, the special values #THRESH_OTSU or #THRESH_TRIANGLE may be combined with one of the above values. In these cases, the function determines the optimal threshold value using the Otsu's -or Triangle algorithm and uses it instead of the specified thresh . The function returns the -computed threshold value. Currently, the Otsu's and Triangle methods are implemented only for 8-bit -images. +or Triangle algorithm and uses it instead of the specified thresh. -@param src input array (single-channel, 8-bit or 32-bit floating point). -@param dst output array of the same size and type as src. +@note Currently, the Otsu's and Triangle methods are implemented only for 8-bit single-channel images. + +@param src input array (multiple-channel, 8-bit or 32-bit floating point). +@param dst output array of the same size and type and the same number of channels as src. @param thresh threshold value. -@param maxval maximum value to use with the THRESH_BINARY and THRESH_BINARY_INV thresholding +@param maxval maximum value to use with the #THRESH_BINARY and #THRESH_BINARY_INV thresholding types. -@param type thresholding type (see the cv::ThresholdTypes). +@param type thresholding type (see #ThresholdTypes). +@return the computed threshold value if Otsu's or Triangle methods used. @sa adaptiveThreshold, findContours, compare, min, max */ @@ -2466,9 +2873,10 @@ The function can process the image in-place. @param src Source 8-bit single-channel image. @param dst Destination image of the same size and the same type as src. @param maxValue Non-zero value assigned to the pixels for which the condition is satisfied -@param adaptiveMethod Adaptive thresholding algorithm to use, see cv::AdaptiveThresholdTypes -@param thresholdType Thresholding type that must be either THRESH_BINARY or THRESH_BINARY_INV, -see cv::ThresholdTypes. +@param adaptiveMethod Adaptive thresholding algorithm to use, see #AdaptiveThresholdTypes. +The #BORDER_REPLICATE | #BORDER_ISOLATED is used to process boundaries. +@param thresholdType Thresholding type that must be either #THRESH_BINARY or #THRESH_BINARY_INV, +see #ThresholdTypes. @param blockSize Size of a pixel neighborhood that is used to calculate a threshold value for the pixel: 3, 5, 7, and so on. @param C Constant subtracted from the mean or weighted mean (see the details below). Normally, it @@ -2485,6 +2893,10 @@ CV_EXPORTS_W void adaptiveThreshold( InputArray src, OutputArray dst, //! @addtogroup imgproc_filter //! @{ +/** @example samples/cpp/tutorial_code/ImgProc/Pyramids/Pyramids.cpp +An example using pyrDown and pyrUp functions +*/ + /** @brief Blurs an image and downsamples it. By default, size of the output image is computed as `Size((src.cols+1)/2, (src.rows+1)/2)`, but in @@ -2502,7 +2914,7 @@ Then, it downsamples the image by rejecting even rows and columns. @param src input image. @param dst output image; it has the specified size and the same type as src. @param dstsize size of the output image. -@param borderType Pixel extrapolation method, see cv::BorderTypes (BORDER_CONSTANT isn't supported) +@param borderType Pixel extrapolation method, see #BorderTypes (#BORDER_CONSTANT isn't supported) */ CV_EXPORTS_W void pyrDown( InputArray src, OutputArray dst, const Size& dstsize = Size(), int borderType = BORDER_DEFAULT ); @@ -2522,7 +2934,7 @@ pyrDown multiplied by 4. @param src input image. @param dst output image. It has the specified size and the same type as src . @param dstsize size of the output image. -@param borderType Pixel extrapolation method, see cv::BorderTypes (only BORDER_DEFAULT is supported) +@param borderType Pixel extrapolation method, see #BorderTypes (only #BORDER_DEFAULT is supported) */ CV_EXPORTS_W void pyrUp( InputArray src, OutputArray dst, const Size& dstsize = Size(), int borderType = BORDER_DEFAULT ); @@ -2536,7 +2948,7 @@ pyrDown to the previously built pyramid layers, starting from `dst[0]==src`. @param dst Destination vector of maxlevel+1 images of the same type as src. dst[0] will be the same as src. dst[1] is the next pyramid layer, a smoothed and down-sized src, and so on. @param maxlevel 0-based index of the last (the smallest) pyramid layer. It must be non-negative. -@param borderType Pixel extrapolation method, see cv::BorderTypes (BORDER_CONSTANT isn't supported) +@param borderType Pixel extrapolation method, see #BorderTypes (#BORDER_CONSTANT isn't supported) */ CV_EXPORTS void buildPyramid( InputArray src, OutputArrayOfArrays dst, int maxlevel, int borderType = BORDER_DEFAULT ); @@ -2550,7 +2962,7 @@ CV_EXPORTS void buildPyramid( InputArray src, OutputArrayOfArrays dst, The function transforms an image to compensate radial and tangential lens distortion. -The function is simply a combination of cv::initUndistortRectifyMap (with unity R ) and cv::remap +The function is simply a combination of #initUndistortRectifyMap (with unity R ) and #remap (with bilinear interpolation). See the former function for details of the transformation being performed. @@ -2558,10 +2970,10 @@ Those pixels in the destination image, for which there is no correspondent pixel image, are filled with zeros (black color). A particular subset of the source image that will be visible in the corrected image can be regulated -by newCameraMatrix. You can use cv::getOptimalNewCameraMatrix to compute the appropriate +by newCameraMatrix. You can use #getOptimalNewCameraMatrix to compute the appropriate newCameraMatrix depending on your requirements. -The camera matrix and the distortion parameters can be determined using cv::calibrateCamera. If +The camera matrix and the distortion parameters can be determined using #calibrateCamera. If the resolution of images is different from the resolution used at the calibration stage, \f$f_x, f_y, c_x\f$ and \f$c_y\f$ need to be scaled accordingly, while the distortion coefficients remain the same. @@ -2570,8 +2982,8 @@ the same. @param dst Output (corrected) image that has the same size and type as src . @param cameraMatrix Input camera matrix \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . @param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])\f$ of 4, 5, or 8 elements. If the vector is -NULL/empty, the zero distortion coefficients are assumed. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. @param newCameraMatrix Camera matrix of the distorted image. By default, it is the same as cameraMatrix but you may additionally scale and shift the result by using a different matrix. */ @@ -2586,8 +2998,8 @@ The function computes the joint undistortion and rectification transformation an result in the form of maps for remap. The undistorted image looks like original, as if it is captured with a camera using the camera matrix =newCameraMatrix and zero distortion. In case of a monocular camera, newCameraMatrix is usually equal to cameraMatrix, or it can be computed by -cv::getOptimalNewCameraMatrix for a better control over scaling. In case of a stereo camera, -newCameraMatrix is normally set to P1 or P2 computed by cv::stereoRectify . +#getOptimalNewCameraMatrix for a better control over scaling. In case of a stereo camera, +newCameraMatrix is normally set to P1 or P2 computed by #stereoRectify . Also, this new camera is oriented differently in the coordinate space, according to R. That, for example, helps to align two heads of a stereo camera so that the epipolar lines on both images @@ -2597,13 +3009,33 @@ The function actually builds the maps for the inverse mapping algorithm that is is, for each pixel \f$(u, v)\f$ in the destination (corrected and rectified) image, the function computes the corresponding coordinates in the source image (that is, in the original image from camera). The following process is applied: -\f[\begin{array}{l} x \leftarrow (u - {c'}_x)/{f'}_x \\ y \leftarrow (v - {c'}_y)/{f'}_y \\{[X\,Y\,W]} ^T \leftarrow R^{-1}*[x \, y \, 1]^T \\ x' \leftarrow X/W \\ y' \leftarrow Y/W \\ x" \leftarrow x' (1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + 2p_1 x' y' + p_2(r^2 + 2 x'^2) \\ y" \leftarrow y' (1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' \\ map_x(u,v) \leftarrow x" f_x + c_x \\ map_y(u,v) \leftarrow y" f_y + c_y \end{array}\f] -where \f$(k_1, k_2, p_1, p_2[, k_3])\f$ are the distortion coefficients. +\f[ +\begin{array}{l} +x \leftarrow (u - {c'}_x)/{f'}_x \\ +y \leftarrow (v - {c'}_y)/{f'}_y \\ +{[X\,Y\,W]} ^T \leftarrow R^{-1}*[x \, y \, 1]^T \\ +x' \leftarrow X/W \\ +y' \leftarrow Y/W \\ +r^2 \leftarrow x'^2 + y'^2 \\ +x'' \leftarrow x' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} ++ 2p_1 x' y' + p_2(r^2 + 2 x'^2) + s_1 r^2 + s_2 r^4\\ +y'' \leftarrow y' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} ++ p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' + s_3 r^2 + s_4 r^4 \\ +s\vecthree{x'''}{y'''}{1} = +\vecthreethree{R_{33}(\tau_x, \tau_y)}{0}{-R_{13}((\tau_x, \tau_y)} +{0}{R_{33}(\tau_x, \tau_y)}{-R_{23}(\tau_x, \tau_y)} +{0}{0}{1} R(\tau_x, \tau_y) \vecthree{x''}{y''}{1}\\ +map_x(u,v) \leftarrow x''' f_x + c_x \\ +map_y(u,v) \leftarrow y''' f_y + c_y +\end{array} +\f] +where \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +are the distortion coefficients. In case of a stereo camera, this function is called twice: once for each camera head, after -stereoRectify, which in its turn is called after cv::stereoCalibrate. But if the stereo camera +stereoRectify, which in its turn is called after #stereoCalibrate. But if the stereo camera was not calibrated, it is still possible to compute the rectification transformations directly from -the fundamental matrix using cv::stereoRectifyUncalibrated. For each camera, the function computes +the fundamental matrix using #stereoRectifyUncalibrated. For each camera, the function computes homography H as the rectification transformation in a pixel domain, not a rotation matrix R in 3D space. R can be computed from H as \f[\texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix}\f] @@ -2611,14 +3043,14 @@ where cameraMatrix can be chosen arbitrarily. @param cameraMatrix Input camera matrix \f$A=\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . @param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])\f$ of 4, 5, or 8 elements. If the vector is -NULL/empty, the zero distortion coefficients are assumed. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. @param R Optional rectification transformation in the object space (3x3 matrix). R1 or R2 , -computed by stereoRectify can be passed here. If the matrix is empty, the identity transformation +computed by #stereoRectify can be passed here. If the matrix is empty, the identity transformation is assumed. In cvInitUndistortMap R assumed to be an identity matrix. @param newCameraMatrix New camera matrix \f$A'=\vecthreethree{f_x'}{0}{c_x'}{0}{f_y'}{c_y'}{0}{0}{1}\f$. @param size Undistorted image size. -@param m1type Type of the first output map that can be CV_32FC1 or CV_16SC2, see cv::convertMaps +@param m1type Type of the first output map that can be CV_32FC1, CV_32FC2 or CV_16SC2, see #convertMaps @param map1 The first output map. @param map2 The second output map. */ @@ -2626,7 +3058,7 @@ CV_EXPORTS_W void initUndistortRectifyMap( InputArray cameraMatrix, InputArray d InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2 ); -//! initializes maps for cv::remap() for wide-angle +//! initializes maps for #remap for wide-angle CV_EXPORTS_W float initWideAngleProjMap( InputArray cameraMatrix, InputArray distCoeffs, Size imageSize, int destImageWidth, int m1type, OutputArray map1, OutputArray map2, @@ -2643,7 +3075,7 @@ In the latter case, the new camera matrix will be: where \f$f_x\f$ and \f$f_y\f$ are \f$(0,0)\f$ and \f$(1,1)\f$ elements of cameraMatrix, respectively. -By default, the undistortion functions in OpenCV (see initUndistortRectifyMap, undistort) do not +By default, the undistortion functions in OpenCV (see #initUndistortRectifyMap, #undistort) do not move the principal point. However, when you work with stereo, it is important to move the principal points in both views to the same y-coordinate (which is required by most of stereo correspondence algorithms), and may be to the same x-coordinate too. So, you can form the new camera matrix for @@ -2659,24 +3091,27 @@ CV_EXPORTS_W Mat getDefaultNewCameraMatrix( InputArray cameraMatrix, Size imgsiz /** @brief Computes the ideal point coordinates from the observed point coordinates. -The function is similar to cv::undistort and cv::initUndistortRectifyMap but it operates on a +The function is similar to #undistort and #initUndistortRectifyMap but it operates on a sparse set of points instead of a raster image. Also the function performs a reverse transformation to projectPoints. In case of a 3D object, it does not reconstruct its 3D coordinates, but for a planar object, it does, up to a translation vector, if the proper R is specified. -@code - // (u,v) is the input point, (u', v') is the output point - // camera_matrix=[fx 0 cx; 0 fy cy; 0 0 1] - // P=[fx' 0 cx' tx; 0 fy' cy' ty; 0 0 1 tz] - x" = (u - cx)/fx - y" = (v - cy)/fy - (x',y') = undistort(x",y",dist_coeffs) - [X,Y,W]T = R*[x' y' 1]T - x = X/W, y = Y/W - // only performed if P=[fx' 0 cx' [tx]; 0 fy' cy' [ty]; 0 0 1 [tz]] is specified - u' = x*fx' + cx' - v' = y*fy' + cy', -@endcode -where cv::undistort is an approximate iterative algorithm that estimates the normalized original + +For each observed point coordinate \f$(u, v)\f$ the function computes: +\f[ +\begin{array}{l} +x^{"} \leftarrow (u - c_x)/f_x \\ +y^{"} \leftarrow (v - c_y)/f_y \\ +(x',y') = undistort(x^{"},y^{"}, \texttt{distCoeffs}) \\ +{[X\,Y\,W]} ^T \leftarrow R*[x' \, y' \, 1]^T \\ +x \leftarrow X/W \\ +y \leftarrow Y/W \\ +\text{only performed if P is specified:} \\ +u' \leftarrow x {f'}_x + {c'}_x \\ +v' \leftarrow y {f'}_y + {c'}_y +\end{array} +\f] + +where *undistort* is an approximate iterative algorithm that estimates the normalized original point coordinates out of the normalized distorted point coordinates ("normalized" means that the coordinates do not depend on the camera matrix). @@ -2687,90 +3122,41 @@ The function can be used for both a stereo camera head or a monocular camera (wh transformation. If matrix P is identity or omitted, dst will contain normalized point coordinates. @param cameraMatrix Camera matrix \f$\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . @param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])\f$ of 4, 5, or 8 elements. If the vector is -NULL/empty, the zero distortion coefficients are assumed. +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. @param R Rectification transformation in the object space (3x3 matrix). R1 or R2 computed by -cv::stereoRectify can be passed here. If the matrix is empty, the identity transformation is used. -@param P New camera matrix (3x3) or new projection matrix (3x4). P1 or P2 computed by -cv::stereoRectify can be passed here. If the matrix is empty, the identity new camera matrix is used. +#stereoRectify can be passed here. If the matrix is empty, the identity transformation is used. +@param P New camera matrix (3x3) or new projection matrix (3x4) \f$\begin{bmatrix} {f'}_x & 0 & {c'}_x & t_x \\ 0 & {f'}_y & {c'}_y & t_y \\ 0 & 0 & 1 & t_z \end{bmatrix}\f$. P1 or P2 computed by +#stereoRectify can be passed here. If the matrix is empty, the identity new camera matrix is used. */ CV_EXPORTS_W void undistortPoints( InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray distCoeffs, InputArray R = noArray(), InputArray P = noArray()); +/** @overload + @note Default version of #undistortPoints does 5 iterations to compute undistorted points. + + */ +CV_EXPORTS_AS(undistortPointsIter) void undistortPoints( InputArray src, OutputArray dst, + InputArray cameraMatrix, InputArray distCoeffs, + InputArray R, InputArray P, TermCriteria criteria); //! @} imgproc_transform //! @addtogroup imgproc_hist //! @{ -/** @example demhist.cpp +/** @example samples/cpp/demhist.cpp An example for creating histograms of an image */ /** @brief Calculates a histogram of a set of arrays. -The functions calcHist calculate the histogram of one or more arrays. The elements of a tuple used +The function cv::calcHist calculates the histogram of one or more arrays. The elements of a tuple used to increment a histogram bin are taken from the corresponding input arrays at the same location. The sample below shows how to compute a 2D Hue-Saturation histogram for a color image. : -@code - #include - #include +@include snippets/imgproc_calcHist.cpp - using namespace cv; - - int main( int argc, char** argv ) - { - Mat src, hsv; - if( argc != 2 || !(src=imread(argv[1], 1)).data ) - return -1; - - cvtColor(src, hsv, COLOR_BGR2HSV); - - // Quantize the hue to 30 levels - // and the saturation to 32 levels - int hbins = 30, sbins = 32; - int histSize[] = {hbins, sbins}; - // hue varies from 0 to 179, see cvtColor - float hranges[] = { 0, 180 }; - // saturation varies from 0 (black-gray-white) to - // 255 (pure spectrum color) - float sranges[] = { 0, 256 }; - const float* ranges[] = { hranges, sranges }; - MatND hist; - // we compute the histogram from the 0-th and 1-st channels - int channels[] = {0, 1}; - - calcHist( &hsv, 1, channels, Mat(), // do not use mask - hist, 2, histSize, ranges, - true, // the histogram is uniform - false ); - double maxVal=0; - minMaxLoc(hist, 0, &maxVal, 0, 0); - - int scale = 10; - Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3); - - for( int h = 0; h < hbins; h++ ) - for( int s = 0; s < sbins; s++ ) - { - float binVal = hist.at(h, s); - int intensity = cvRound(binVal*255/maxVal); - rectangle( histImg, Point(h*scale, s*scale), - Point( (h+1)*scale - 1, (s+1)*scale - 1), - Scalar::all(intensity), - CV_FILLED ); - } - - namedWindow( "Source", 1 ); - imshow( "Source", src ); - - namedWindow( "H-S Histogram", 1 ); - imshow( "H-S Histogram", histImg ); - waitKey(); - } -@endcode - -@param images Source arrays. They all should have the same depth, CV_8U or CV_32F , and the same +@param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same size. Each of them can have an arbitrary number of channels. @param nimages Number of source images. @param channels List of the dims channels used to compute the histogram. The first array channels @@ -2803,7 +3189,7 @@ CV_EXPORTS void calcHist( const Mat* images, int nimages, /** @overload -this variant uses cv::SparseMat for output +this variant uses %SparseMat for output */ CV_EXPORTS void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask, @@ -2821,8 +3207,8 @@ CV_EXPORTS_W void calcHist( InputArrayOfArrays images, /** @brief Calculates the back projection of a histogram. -The functions calcBackProject calculate the back project of the histogram. That is, similarly to -cv::calcHist , at each location (x, y) the function collects the values from the selected channels +The function cv::calcBackProject calculates the back project of the histogram. That is, similarly to +#calcHist , at each location (x, y) the function collects the values from the selected channels in the input images and finds the corresponding histogram bin. But instead of incrementing it, the function reads the bin value, scales it by scale , and stores in backProject(x,y) . In terms of statistics, the function computes probability of each element value in respect with the empirical @@ -2842,7 +3228,7 @@ component. This is an approximate algorithm of the CamShift color object tracker. -@param images Source arrays. They all should have the same depth, CV_8U or CV_32F , and the same +@param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same size. Each of them can have an arbitrary number of channels. @param nimages Number of source images. @param channels The list of channels used to compute the back projection. The number of channels @@ -2852,11 +3238,11 @@ images[0].channels() + images[1].channels()-1, and so on. @param hist Input histogram that can be dense or sparse. @param backProject Destination back projection array that is a single-channel array of the same size and depth as images[0] . -@param ranges Array of arrays of the histogram bin boundaries in each dimension. See calcHist . +@param ranges Array of arrays of the histogram bin boundaries in each dimension. See #calcHist . @param scale Optional scale factor for the output back projection. @param uniform Flag indicating whether the histogram is uniform or not (see above). -@sa cv::calcHist, cv::compareHist +@sa calcHist, compareHist */ CV_EXPORTS void calcBackProject( const Mat* images, int nimages, const int* channels, InputArray hist, @@ -2877,18 +3263,18 @@ CV_EXPORTS_W void calcBackProject( InputArrayOfArrays images, const std::vector< /** @brief Compares two histograms. -The function compare two dense or two sparse histograms using the specified method. +The function cv::compareHist compares two dense or two sparse histograms using the specified method. The function returns \f$d(H_1, H_2)\f$ . While the function works well with 1-, 2-, 3-dimensional dense histograms, it may not be suitable for high-dimensional sparse histograms. In such histograms, because of aliasing and sampling problems, the coordinates of non-zero histogram bins can slightly shift. To compare such histograms -or more general sparse configurations of weighted points, consider using the cv::EMD function. +or more general sparse configurations of weighted points, consider using the #EMD function. @param H1 First compared histogram. @param H2 Second compared histogram of the same size as H1 . -@param method Comparison method, see cv::HistCompMethods +@param method Comparison method, see #HistCompMethods */ CV_EXPORTS_W double compareHist( InputArray H1, InputArray H2, int method ); @@ -2912,6 +3298,14 @@ The algorithm normalizes the brightness and increases the contrast of the image. */ CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst ); +/** @brief Creates a smart pointer to a cv::CLAHE class and initializes it. + +@param clipLimit Threshold for contrast limiting. +@param tileGridSize Size of grid for histogram equalization. Input image will be divided into +equally sized rectangular tiles. tileGridSize defines the number of tiles in row and column. + */ +CV_EXPORTS_W Ptr createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8)); + /** @brief Computes the "minimal work" distance between two weighted point configurations. The function computes the earth mover distance and/or a lower boundary of the distance between the @@ -2925,11 +3319,13 @@ same object. @param signature1 First signature, a \f$\texttt{size1}\times \texttt{dims}+1\f$ floating-point matrix. Each row stores the point weight followed by the point coordinates. The matrix is allowed to have -a single column (weights only) if the user-defined cost matrix is used. +a single column (weights only) if the user-defined cost matrix is used. The weights must be +non-negative and have at least one non-zero value. @param signature2 Second signature of the same format as signature1 , though the number of rows may be different. The total weights may be different. In this case an extra "dummy" point is added -to either signature1 or signature2 . -@param distType Used metric. See cv::DistanceTypes. +to either signature1 or signature2. The weights must be non-negative and have at least one non-zero +value. +@param distType Used metric. See #DistanceTypes. @param cost User-defined \f$\texttt{size1}\times \texttt{size2}\f$ cost matrix. Also, if a cost matrix is used, lower boundary lowerBound cannot be calculated because it needs a metric function. @param lowerBound Optional input/output parameter: lower boundary of a distance between the two @@ -2948,11 +3344,15 @@ CV_EXPORTS float EMD( InputArray signature1, InputArray signature2, int distType, InputArray cost=noArray(), float* lowerBound = 0, OutputArray flow = noArray() ); +CV_EXPORTS_AS(EMD) float wrapperEMD( InputArray signature1, InputArray signature2, + int distType, InputArray cost=noArray(), + CV_IN_OUT Ptr lowerBound = Ptr(), OutputArray flow = noArray() ); + //! @} imgproc_hist -/** @example watershed.cpp +/** @example samples/cpp/watershed.cpp An example using the watershed algorithm - */ +*/ /** @brief Performs a marker-based image segmentation using the watershed algorithm. @@ -2962,7 +3362,7 @@ algorithm, described in @cite Meyer92 . Before passing the image to the function, you have to roughly outline the desired regions in the image markers with positive (\>0) indices. So, every region is represented as one or more connected components with the pixel values 1, 2, 3, and so on. Such markers can be retrieved from a binary -mask using findContours and drawContours (see the watershed.cpp demo). The markers are "seeds" of +mask using #findContours and #drawContours (see the watershed.cpp demo). The markers are "seeds" of the future image regions. All the other pixels in markers , whose relation to the outlined regions is not known and should be defined by the algorithm, should be set to 0's. In the function output, each pixel in markers is set to a value of the "seed" components or to -1 at boundaries between the @@ -3030,9 +3430,10 @@ CV_EXPORTS_W void pyrMeanShiftFiltering( InputArray src, OutputArray dst, //! @addtogroup imgproc_misc //! @{ -/** @example grabcut.cpp +/** @example samples/cpp/grabcut.cpp An example using the GrabCut algorithm - */ +![Sample Screenshot](grabcut_output1.jpg) +*/ /** @brief Runs the GrabCut algorithm. @@ -3040,33 +3441,32 @@ The function implements the [GrabCut image segmentation algorithm](http://en.wik @param img Input 8-bit 3-channel image. @param mask Input/output 8-bit single-channel mask. The mask is initialized by the function when -mode is set to GC_INIT_WITH_RECT. Its elements may have one of the cv::GrabCutClasses. +mode is set to #GC_INIT_WITH_RECT. Its elements may have one of the #GrabCutClasses. @param rect ROI containing a segmented object. The pixels outside of the ROI are marked as -"obvious background". The parameter is only used when mode==GC_INIT_WITH_RECT . +"obvious background". The parameter is only used when mode==#GC_INIT_WITH_RECT . @param bgdModel Temporary array for the background model. Do not modify it while you are processing the same image. @param fgdModel Temporary arrays for the foreground model. Do not modify it while you are processing the same image. @param iterCount Number of iterations the algorithm should make before returning the result. Note -that the result can be refined with further calls with mode==GC_INIT_WITH_MASK or +that the result can be refined with further calls with mode==#GC_INIT_WITH_MASK or mode==GC_EVAL . -@param mode Operation mode that could be one of the cv::GrabCutModes +@param mode Operation mode that could be one of the #GrabCutModes */ CV_EXPORTS_W void grabCut( InputArray img, InputOutputArray mask, Rect rect, InputOutputArray bgdModel, InputOutputArray fgdModel, int iterCount, int mode = GC_EVAL ); -/** @example distrans.cpp -An example on using the distance transform\ +/** @example samples/cpp/distrans.cpp +An example on using the distance transform */ - /** @brief Calculates the distance to the closest zero pixel for each pixel of the source image. -The functions distanceTransform calculate the approximate or precise distance from every binary +The function cv::distanceTransform calculates the approximate or precise distance from every binary image pixel to the nearest zero pixel. For zero image pixels, the distance will obviously be zero. -When maskSize == DIST_MASK_PRECISE and distanceType == DIST_L2 , the function runs the +When maskSize == #DIST_MASK_PRECISE and distanceType == #DIST_L2 , the function runs the algorithm described in @cite Felzenszwalb04 . This algorithm is parallelized with the TBB library. In other cases, the algorithm @cite Borgefors86 is used. This means that for a pixel the function @@ -3075,8 +3475,8 @@ diagonal, or knight's move (the latest is available for a \f$5\times 5\f$ mask). distance is calculated as a sum of these basic distances. Since the distance function should be symmetric, all of the horizontal and vertical shifts must have the same cost (denoted as a ), all the diagonal shifts must have the same cost (denoted as `b`), and all knight's moves must have the -same cost (denoted as `c`). For the cv::DIST_C and cv::DIST_L1 types, the distance is calculated -precisely, whereas for cv::DIST_L2 (Euclidean distance) the distance can be calculated only with a +same cost (denoted as `c`). For the #DIST_C and #DIST_L1 types, the distance is calculated +precisely, whereas for #DIST_L2 (Euclidean distance) the distance can be calculated only with a relative error (a \f$5\times 5\f$ mask gives more accurate results). For `a`,`b`, and `c`, OpenCV uses the values suggested in the original paper: - DIST_L1: `a = 1, b = 2` @@ -3085,21 +3485,21 @@ uses the values suggested in the original paper: - `5 x 5`: `a=1, b=1.4, c=2.1969` - DIST_C: `a = 1, b = 1` -Typically, for a fast, coarse distance estimation DIST_L2, a \f$3\times 3\f$ mask is used. For a -more accurate distance estimation DIST_L2, a \f$5\times 5\f$ mask or the precise algorithm is used. +Typically, for a fast, coarse distance estimation #DIST_L2, a \f$3\times 3\f$ mask is used. For a +more accurate distance estimation #DIST_L2, a \f$5\times 5\f$ mask or the precise algorithm is used. Note that both the precise and the approximate algorithms are linear on the number of pixels. This variant of the function does not only compute the minimum distance for each pixel \f$(x, y)\f$ but also identifies the nearest connected component consisting of zero pixels -(labelType==DIST_LABEL_CCOMP) or the nearest zero pixel (labelType==DIST_LABEL_PIXEL). Index of the -component/pixel is stored in `labels(x, y)`. When labelType==DIST_LABEL_CCOMP, the function +(labelType==#DIST_LABEL_CCOMP) or the nearest zero pixel (labelType==#DIST_LABEL_PIXEL). Index of the +component/pixel is stored in `labels(x, y)`. When labelType==#DIST_LABEL_CCOMP, the function automatically finds connected components of zero pixels in the input image and marks them with -distinct labels. When labelType==DIST_LABEL_CCOMP, the function scans through the input image and +distinct labels. When labelType==#DIST_LABEL_CCOMP, the function scans through the input image and marks all the zero pixels with distinct labels. In this mode, the complexity is still linear. That is, the function provides a very fast way to compute the Voronoi diagram for a binary image. Currently, the second variant can use only the -approximate distance transform algorithm, i.e. maskSize=DIST_MASK_PRECISE is not supported +approximate distance transform algorithm, i.e. maskSize=#DIST_MASK_PRECISE is not supported yet. @param src 8-bit, single-channel (binary) source image. @@ -3107,12 +3507,12 @@ yet. single-channel image of the same size as src. @param labels Output 2D array of labels (the discrete Voronoi diagram). It has the type CV_32SC1 and the same size as src. -@param distanceType Type of distance, see cv::DistanceTypes -@param maskSize Size of the distance transform mask, see cv::DistanceTransformMasks. -DIST_MASK_PRECISE is not supported by this variant. In case of the DIST_L1 or DIST_C distance type, +@param distanceType Type of distance, see #DistanceTypes +@param maskSize Size of the distance transform mask, see #DistanceTransformMasks. +#DIST_MASK_PRECISE is not supported by this variant. In case of the #DIST_L1 or #DIST_C distance type, the parameter is forced to 3 because a \f$3\times 3\f$ mask gives the same result as \f$5\times 5\f$ or any larger aperture. -@param labelType Type of the label array to build, see cv::DistanceTransformLabelTypes. +@param labelType Type of the label array to build, see #DistanceTransformLabelTypes. */ CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray src, OutputArray dst, OutputArray labels, int distanceType, int maskSize, @@ -3122,18 +3522,18 @@ CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray sr @param src 8-bit, single-channel (binary) source image. @param dst Output image with calculated distances. It is a 8-bit or 32-bit floating-point, single-channel image of the same size as src . -@param distanceType Type of distance, see cv::DistanceTypes -@param maskSize Size of the distance transform mask, see cv::DistanceTransformMasks. In case of the -DIST_L1 or DIST_C distance type, the parameter is forced to 3 because a \f$3\times 3\f$ mask gives +@param distanceType Type of distance, see #DistanceTypes +@param maskSize Size of the distance transform mask, see #DistanceTransformMasks. In case of the +#DIST_L1 or #DIST_C distance type, the parameter is forced to 3 because a \f$3\times 3\f$ mask gives the same result as \f$5\times 5\f$ or any larger aperture. @param dstType Type of output image. It can be CV_8U or CV_32F. Type CV_8U can be used only for -the first variant of the function and distanceType == DIST_L1. +the first variant of the function and distanceType == #DIST_L1. */ CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst, int distanceType, int maskSize, int dstType=CV_32F); -/** @example ffilldemo.cpp - An example using the FloodFill technique +/** @example samples/cpp/ffilldemo.cpp +An example using the FloodFill technique */ /** @overload @@ -3147,7 +3547,7 @@ CV_EXPORTS int floodFill( InputOutputArray image, /** @brief Fills a connected component with the given color. -The functions floodFill fill a connected component starting from the seed point with the specified +The function cv::floodFill fills a connected component starting from the seed point with the specified color. The connectivity is determined by the color/brightness closeness of the neighbor pixels. The pixel at \f$(x,y)\f$ is considered to belong to the repainted domain if: @@ -3184,14 +3584,15 @@ Use these functions to either mark a connected component with the specified colo a mask and then extract the contour, or copy the region to another image, and so on. @param image Input/output 1- or 3-channel, 8-bit, or floating-point image. It is modified by the -function unless the FLOODFILL_MASK_ONLY flag is set in the second variant of the function. See +function unless the #FLOODFILL_MASK_ONLY flag is set in the second variant of the function. See the details below. @param mask Operation mask that should be a single-channel 8-bit image, 2 pixels wider and 2 pixels taller than image. Since this is both an input and output parameter, you must take responsibility of initializing it. Flood-filling cannot go across non-zero pixels in the input mask. For example, an edge detector output can be used as a mask to stop filling at edges. On output, pixels in the mask corresponding to filled pixels in the image are set to 1 or to the a value specified in flags -as described below. It is therefore possible to use the same mask in multiple calls to the function +as described below. Additionally, the function fills the border of the mask with ones to simplify +internal processing. It is therefore possible to use the same mask in multiple calls to the function to make sure the filled areas do not overlap. @param seedPoint Starting point. @param newVal New value of the repainted domain pixels. @@ -3208,7 +3609,7 @@ will be considered. The next 8 bits (8-16) contain a value between 1 and 255 wit the mask (the default value is 1). For example, 4 | ( 255 \<\< 8 ) will consider 4 nearest neighbours and fill the mask with a value of 255. The following additional options occupy higher bits and therefore may be further combined with the connectivity and mask fill values using -bit-wise or (|), see cv::FloodFillFlags. +bit-wise or (|), see #FloodFillFlags. @note Since the mask is larger than the filled image, a pixel \f$(x, y)\f$ in image corresponds to the pixel \f$(x+1, y+1)\f$ in the mask . @@ -3220,6 +3621,20 @@ CV_EXPORTS_W int floodFill( InputOutputArray image, InputOutputArray mask, Scalar loDiff = Scalar(), Scalar upDiff = Scalar(), int flags = 4 ); +//! Performs linear blending of two images: +//! \f[ \texttt{dst}(i,j) = \texttt{weights1}(i,j)*\texttt{src1}(i,j) + \texttt{weights2}(i,j)*\texttt{src2}(i,j) \f] +//! @param src1 It has a type of CV_8UC(n) or CV_32FC(n), where n is a positive integer. +//! @param src2 It has the same type and size as src1. +//! @param weights1 It has a type of CV_32FC1 and the same size with src1. +//! @param weights2 It has a type of CV_32FC1 and the same size with src1. +//! @param dst It is created if it does not have the same size and type with src1. +CV_EXPORTS void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst); + +//! @} imgproc_misc + +//! @addtogroup imgproc_color_conversions +//! @{ + /** @brief Converts an image from one color space to another. The function converts an input image from one color space to another. In case of a transformation @@ -3238,13 +3653,13 @@ In case of linear transformations, the range does not matter. But in case of a n transformation, an input RGB image should be normalized to the proper value range to get the correct results, for example, for RGB \f$\rightarrow\f$ L\*u\*v\* transformation. For example, if you have a 32-bit floating-point image directly converted from an 8-bit image without any scaling, then it will -have the 0..255 value range instead of 0..1 assumed by the function. So, before calling cvtColor , +have the 0..255 value range instead of 0..1 assumed by the function. So, before calling #cvtColor , you need first to scale the image down: @code img *= 1./255; cvtColor(img, img, COLOR_BGR2Luv); @endcode -If you use cvtColor with 8-bit images, the conversion will have some information lost. For many +If you use #cvtColor with 8-bit images, the conversion will have some information lost. For many applications, this will not be noticeable but it is recommended to use 32-bit images in applications that need the full range of colors or that convert an image before an operation and then convert back. @@ -3255,7 +3670,7 @@ range: 255 for CV_8U, 65535 for CV_16U, 1 for CV_32F. @param src input image: 8-bit unsigned, 16-bit unsigned ( CV_16UC... ), or single-precision floating-point. @param dst output image of the same size and depth as src. -@param code color space conversion code (see cv::ColorConversionCodes). +@param code color space conversion code (see #ColorConversionCodes). @param dstCn number of channels in the destination image; if the parameter is 0, the number of the channels is derived automatically from src and code. @@ -3263,10 +3678,59 @@ channels is derived automatically from src and code. */ CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 ); -//! @} imgproc_misc +/** @brief Converts an image from one color space to another where the source image is +stored in two planes. -// main function for all demosaicing procceses -CV_EXPORTS_W void demosaicing(InputArray _src, OutputArray _dst, int code, int dcn = 0); +This function only supports YUV420 to RGB conversion as of now. + +@param src1: 8-bit image (#CV_8U) of the Y plane. +@param src2: image containing interleaved U/V plane. +@param dst: output image. +@param code: Specifies the type of conversion. It can take any of the following values: +- #COLOR_YUV2BGR_NV12 +- #COLOR_YUV2RGB_NV12 +- #COLOR_YUV2BGRA_NV12 +- #COLOR_YUV2RGBA_NV12 +- #COLOR_YUV2BGR_NV21 +- #COLOR_YUV2RGB_NV21 +- #COLOR_YUV2BGRA_NV21 +- #COLOR_YUV2RGBA_NV21 +*/ +CV_EXPORTS_W void cvtColorTwoPlane( InputArray src1, InputArray src2, OutputArray dst, int code ); + +/** @brief main function for all demosaicing processes + +@param src input image: 8-bit unsigned or 16-bit unsigned. +@param dst output image of the same size and depth as src. +@param code Color space conversion code (see the description below). +@param dstCn number of channels in the destination image; if the parameter is 0, the number of the +channels is derived automatically from src and code. + +The function can do the following transformations: + +- Demosaicing using bilinear interpolation + + #COLOR_BayerBG2BGR , #COLOR_BayerGB2BGR , #COLOR_BayerRG2BGR , #COLOR_BayerGR2BGR + + #COLOR_BayerBG2GRAY , #COLOR_BayerGB2GRAY , #COLOR_BayerRG2GRAY , #COLOR_BayerGR2GRAY + +- Demosaicing using Variable Number of Gradients. + + #COLOR_BayerBG2BGR_VNG , #COLOR_BayerGB2BGR_VNG , #COLOR_BayerRG2BGR_VNG , #COLOR_BayerGR2BGR_VNG + +- Edge-Aware Demosaicing. + + #COLOR_BayerBG2BGR_EA , #COLOR_BayerGB2BGR_EA , #COLOR_BayerRG2BGR_EA , #COLOR_BayerGR2BGR_EA + +- Demosaicing with alpha channel + + #COLOR_BayerBG2BGRA , #COLOR_BayerGB2BGRA , #COLOR_BayerRG2BGRA , #COLOR_BayerGR2BGRA + +@sa cvtColor +*/ +CV_EXPORTS_W void demosaicing(InputArray src, OutputArray dst, int code, int dstCn = 0); + +//! @} imgproc_color_conversions //! @addtogroup imgproc_shape //! @{ @@ -3282,6 +3746,9 @@ results are returned in the structure cv::Moments. used for images only. @returns moments. +@note Only applicable to contour moments calculations from Python bindings: Note that the numpy +type for the input array should be either np.int32 or np.float32. + @sa contourArea, arcLength */ CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage = false ); @@ -3327,6 +3794,10 @@ enum TemplateMatchModes { TM_CCOEFF_NORMED = 5 //!< \f[R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} }\f] }; +/** @example samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp +An example using Template Matching algorithm +*/ + /** @brief Compares a template against overlapped image regions. The function slides through image , compares the overlapped patches of size \f$w \times h\f$ against @@ -3335,8 +3806,8 @@ for the available comparison methods ( \f$I\f$ denotes image, \f$T\f$ template, is done over template and/or the image patch: \f$x' = 0...w-1, y' = 0...h-1\f$ After the function finishes the comparison, the best matches can be found as global minimums (when -TM_SQDIFF was used) or maximums (when TM_CCORR or TM_CCOEFF was used) using the -minMaxLoc function. In case of a color image, template summation in the numerator and each sum in +#TM_SQDIFF was used) or maximums (when #TM_CCORR or #TM_CCOEFF was used) using the +#minMaxLoc function. In case of a color image, template summation in the numerator and each sum in the denominator is done over all of the channels and separate mean values are used for each channel. That is, the function can take a color template and a color image. The result will still be a single-channel image, which is easier to analyze. @@ -3346,9 +3817,9 @@ single-channel image, which is easier to analyze. data type. @param result Map of comparison results. It must be single-channel 32-bit floating-point. If image is \f$W \times H\f$ and templ is \f$w \times h\f$ , then result is \f$(W-w+1) \times (H-h+1)\f$ . -@param method Parameter specifying the comparison method, see cv::TemplateMatchModes +@param method Parameter specifying the comparison method, see #TemplateMatchModes @param mask Mask of searched template. It must have the same datatype and size with templ. It is -not set by default. +not set by default. Currently, only the #TM_SQDIFF and #TM_CCORR_NORMED methods are supported. */ CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, OutputArray result, int method, InputArray mask = noArray() ); @@ -3358,28 +3829,76 @@ CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, //! @addtogroup imgproc_shape //! @{ +/** @example samples/cpp/connected_components.cpp +This program demonstrates connected components and use of the trackbar +*/ + /** @brief computes the connected components labeled image of boolean image image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0 represents the background label. ltype specifies the output label image type, an important consideration based on the total number of labels or alternatively the total number of pixels in -the source image. +the source image. ccltype specifies the connected components labeling algorithm to use, currently +Grana (BBDT) and Wu's (SAUF) algorithms are supported, see the #ConnectedComponentsAlgorithmsTypes +for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not. +This function uses parallel version of both Grana and Wu's algorithms if at least one allowed +parallel framework is enabled and if the rows of the image are at least twice the number returned by #getNumberOfCPUs. -@param image the image to be labeled +@param image the 8-bit single-channel image to be labeled @param labels destination labeled image @param connectivity 8 or 4 for 8-way or 4-way connectivity respectively @param ltype output image label type. Currently CV_32S and CV_16U are supported. - */ +@param ccltype connected components algorithm type (see the #ConnectedComponentsAlgorithmsTypes). +*/ +CV_EXPORTS_AS(connectedComponentsWithAlgorithm) int connectedComponents(InputArray image, OutputArray labels, + int connectivity, int ltype, int ccltype); + + +/** @overload + +@param image the 8-bit single-channel image to be labeled +@param labels destination labeled image +@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively +@param ltype output image label type. Currently CV_32S and CV_16U are supported. +*/ CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels, int connectivity = 8, int ltype = CV_32S); -/** @overload -@param image the image to be labeled + +/** @brief computes the connected components labeled image of boolean image and also produces a statistics output for each label + +image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0 +represents the background label. ltype specifies the output label image type, an important +consideration based on the total number of labels or alternatively the total number of pixels in +the source image. ccltype specifies the connected components labeling algorithm to use, currently +Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the #ConnectedComponentsAlgorithmsTypes +for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not. +This function uses parallel version of both Grana and Wu's algorithms (statistics included) if at least one allowed +parallel framework is enabled and if the rows of the image are at least twice the number returned by #getNumberOfCPUs. + +@param image the 8-bit single-channel image to be labeled @param labels destination labeled image @param stats statistics output for each label, including the background label, see below for available statistics. Statistics are accessed via stats(label, COLUMN) where COLUMN is one of -cv::ConnectedComponentsTypes -@param centroids floating point centroid (x,y) output for each label, including the background label +#ConnectedComponentsTypes. The data type is CV_32S. +@param centroids centroid output for each label, including the background label. Centroids are +accessed via centroids(label, 0) for x and centroids(label, 1) for y. The data type CV_64F. +@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively +@param ltype output image label type. Currently CV_32S and CV_16U are supported. +@param ccltype connected components algorithm type (see #ConnectedComponentsAlgorithmsTypes). +*/ +CV_EXPORTS_AS(connectedComponentsWithStatsWithAlgorithm) int connectedComponentsWithStats(InputArray image, OutputArray labels, + OutputArray stats, OutputArray centroids, + int connectivity, int ltype, int ccltype); + +/** @overload +@param image the 8-bit single-channel image to be labeled +@param labels destination labeled image +@param stats statistics output for each label, including the background label, see below for +available statistics. Statistics are accessed via stats(label, COLUMN) where COLUMN is one of +#ConnectedComponentsTypes. The data type is CV_32S. +@param centroids centroid output for each label, including the background label. Centroids are +accessed via centroids(label, 0) for x and centroids(label, 1) for y. The data type CV_64F. @param connectivity 8 or 4 for 8-way or 4-way connectivity respectively @param ltype output image label type. Currently CV_32S and CV_16U are supported. */ @@ -3391,27 +3910,24 @@ CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labe /** @brief Finds contours in a binary image. The function retrieves contours from the binary image using the algorithm @cite Suzuki85 . The contours -are a useful tool for shape analysis and object detection and recognition. See squares.c in the +are a useful tool for shape analysis and object detection and recognition. See squares.cpp in the OpenCV sample directory. - -@note Source image is modified by this function. Also, the function does not take into account -1-pixel border of the image (it's filled with 0's and used for neighbor analysis in the algorithm), -therefore the contours touching the image border will be clipped. +@note Since opencv 3.2 source image is not modified by this function. @param image Source, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero -pixels remain 0's, so the image is treated as binary . You can use compare , inRange , threshold , -adaptiveThreshold , Canny , and others to create a binary image out of a grayscale or color one. -The function modifies the image while extracting the contours. If mode equals to RETR_CCOMP -or RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1). -@param contours Detected contours. Each contour is stored as a vector of points. -@param hierarchy Optional output vector, containing information about the image topology. It has -as many elements as the number of contours. For each i-th contour contours[i] , the elements -hierarchy[i][0] , hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices +pixels remain 0's, so the image is treated as binary . You can use #compare, #inRange, #threshold , +#adaptiveThreshold, #Canny, and others to create a binary image out of a grayscale or color one. +If mode equals to #RETR_CCOMP or #RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1). +@param contours Detected contours. Each contour is stored as a vector of points (e.g. +std::vector >). +@param hierarchy Optional output vector (e.g. std::vector), containing information about the image topology. It has +as many elements as the number of contours. For each i-th contour contours[i], the elements +hierarchy[i][0] , hierarchy[i][1] , hierarchy[i][2] , and hierarchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. If for the contour i there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative. -@param mode Contour retrieval mode, see cv::RetrievalModes -@param method Contour approximation method, see cv::ContourApproximationModes +@param mode Contour retrieval mode, see #RetrievalModes +@param method Contour approximation method, see #ContourApproximationModes @param offset Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context. @@ -3424,9 +3940,19 @@ CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays cont CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset = Point()); +/** @example samples/cpp/squares.cpp +A program using pyramid scaling, Canny, contours and contour simplification to find +squares in a list of images (pic1-6.png). Returns sequence of squares detected on the image. +*/ + +/** @example samples/tapi/squares.cpp +A program using pyramid scaling, Canny, contours and contour simplification to find +squares in the input image. +*/ + /** @brief Approximates a polygonal curve(s) with the specified precision. -The functions approxPolyDP approximate a curve or a polygon with another curve/polygon with less +The function cv::approxPolyDP approximates a curve or a polygon with another curve/polygon with less vertices so that the distance between them is less or equal to the specified precision. It uses the Douglas-Peucker algorithm @@ -3450,19 +3976,20 @@ The function computes a curve length or a closed contour perimeter. */ CV_EXPORTS_W double arcLength( InputArray curve, bool closed ); -/** @brief Calculates the up-right bounding rectangle of a point set. +/** @brief Calculates the up-right bounding rectangle of a point set or non-zero pixels of gray-scale image. -The function calculates and returns the minimal up-right bounding rectangle for the specified point set. +The function calculates and returns the minimal up-right bounding rectangle for the specified point set or +non-zero pixels of gray-scale image. -@param points Input 2D point set, stored in std::vector or Mat. +@param array Input gray-scale image or 2D point set, stored in std::vector or Mat. */ -CV_EXPORTS_W Rect boundingRect( InputArray points ); +CV_EXPORTS_W Rect boundingRect( InputArray array ); /** @brief Calculates a contour area. The function computes a contour area. Similarly to moments , the area is computed using the Green formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using -drawContours or fillPoly , can be different. Also, the function will most certainly give a wrong +#drawContours or #fillPoly , can be different. Also, the function will most certainly give a wrong results for contours with self-intersections. Example: @@ -3493,9 +4020,8 @@ CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false ); /** @brief Finds a rotated rectangle of the minimum area enclosing the input 2D point set. The function calculates and returns the minimum-area bounding rectangle (possibly rotated) for a -specified point set. See the OpenCV sample minarea.cpp . Developer should keep in mind that the -returned rotatedRect can contain negative indices when data is close to the containing Mat element -boundary. +specified point set. Developer should keep in mind that the returned RotatedRect can contain negative +indices when data is close to the containing Mat element boundary. @param points Input vector of 2D points, stored in std::vector\<\> or Mat */ @@ -3504,10 +4030,8 @@ CV_EXPORTS_W RotatedRect minAreaRect( InputArray points ); /** @brief Finds the four vertices of a rotated rect. Useful to draw the rotated rectangle. The function finds the four vertices of a rotated rectangle. This function is useful to draw the -rectangle. In C++, instead of using this function, you can directly use box.points() method. Please -visit the [tutorial on bounding -rectangle](http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.html#bounding-rects-circles) -for more information. +rectangle. In C++, instead of using this function, you can directly use RotatedRect::points method. Please +visit the @ref tutorial_bounding_rotated_ellipses "tutorial on Creating Bounding rotated boxes and ellipses for contours" for more information. @param box The input rotated rectangle. It may be the output of @param points The output array of four vertices of rectangles. @@ -3516,8 +4040,7 @@ CV_EXPORTS_W void boxPoints(RotatedRect box, OutputArray points); /** @brief Finds a circle of the minimum area enclosing a 2D point set. -The function finds the minimal enclosing circle of a 2D point set using an iterative algorithm. See -the OpenCV sample minarea.cpp . +The function finds the minimal enclosing circle of a 2D point set using an iterative algorithm. @param points Input vector of 2D points, stored in std::vector\<\> or Mat @param center Output center of the circle. @@ -3526,8 +4049,8 @@ the OpenCV sample minarea.cpp . CV_EXPORTS_W void minEnclosingCircle( InputArray points, CV_OUT Point2f& center, CV_OUT float& radius ); -/** @example minarea.cpp - */ +/** @example samples/cpp/minarea.cpp +*/ /** @brief Finds a triangle of minimum area enclosing a 2D point set and returns its area. @@ -3539,9 +4062,9 @@ area. The output for a given 2D point set is shown in the image below. 2D points The implementation of the algorithm is based on O'Rourke's @cite ORourke86 and Klee and Laskowski's @cite KleeLaskowski85 papers. O'Rourke provides a \f$\theta(n)\f$ algorithm for finding the minimal -enclosing triangle of a 2D convex polygon with n vertices. Since the minEnclosingTriangle function +enclosing triangle of a 2D convex polygon with n vertices. Since the #minEnclosingTriangle function takes a 2D point set as input an additional preprocessing step of computing the convex hull of the -2D point set is required. The complexity of the convexHull function is \f$O(n log(n))\f$ which is higher +2D point set is required. The complexity of the #convexHull function is \f$O(n log(n))\f$ which is higher than \f$\theta(n)\f$. Thus the overall complexity of the function is \f$O(n log(n))\f$. @param points Input vector of 2D points with depth CV_32S or CV_32F, stored in std::vector\<\> or Mat @@ -3552,25 +4075,24 @@ CV_EXPORTS_W double minEnclosingTriangle( InputArray points, CV_OUT OutputArray /** @brief Compares two shapes. -The function compares two shapes. All three implemented methods use the Hu invariants (see cv::HuMoments) +The function compares two shapes. All three implemented methods use the Hu invariants (see #HuMoments) @param contour1 First contour or grayscale image. @param contour2 Second contour or grayscale image. -@param method Comparison method, see ::ShapeMatchModes +@param method Comparison method, see #ShapeMatchModes @param parameter Method-specific parameter (not supported now). */ CV_EXPORTS_W double matchShapes( InputArray contour1, InputArray contour2, int method, double parameter ); -/** @example convexhull.cpp +/** @example samples/cpp/convexhull.cpp An example using the convexHull functionality */ /** @brief Finds the convex hull of a point set. -The functions find the convex hull of a 2D point set using the Sklansky's algorithm @cite Sklansky82 -that has *O(N logN)* complexity in the current implementation. See the OpenCV sample convexhull.cpp -that demonstrates the usage of different function variants. +The function cv::convexHull finds the convex hull of a 2D point set using the Sklansky's algorithm @cite Sklansky82 +that has *O(N logN)* complexity in the current implementation. @param points Input 2D point set, stored in std::vector or Mat. @param hull Output convex hull. It is either an integer vector of indices or vector of points. In @@ -3583,8 +4105,16 @@ to the right, and its Y axis pointing upwards. @param returnPoints Operation flag. In case of a matrix, when the flag is true, the function returns convex hull points. Otherwise, it returns indices of the convex hull points. When the output array is std::vector, the flag is ignored, and the output depends on the type of the -vector: std::vector\ implies returnPoints=true, std::vector\ implies -returnPoints=false. +vector: std::vector\ implies returnPoints=false, std::vector\ implies +returnPoints=true. + +@note `points` and `hull` should be different arrays, inplace processing isn't supported. + +Check @ref tutorial_hull "the corresponding tutorial" for more details. + +useful links: + +https://www.learnopencv.com/convex-hull-using-opencv-in-python-and-c/ */ CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true ); @@ -3599,7 +4129,7 @@ The figure below displays convexity defects of a hand contour: @param convexhull Convex hull obtained using convexHull that should contain indices of the contour points that make the hull. @param convexityDefects The output vector of convexity defects. In C++ and the new Python/Java -interface each convexity defect is represented as 4-element integer vector (a.k.a. cv::Vec4i): +interface each convexity defect is represented as 4-element integer vector (a.k.a. #Vec4i): (start_index, end_index, farthest_pt_index, fixpt_depth), where indices are 0-based indices in the original contour of the convexity defect beginning, end and the farthest point, and fixpt_depth is fixed-point approximation (with 8 fractional bits) of the distance between the @@ -3621,8 +4151,8 @@ CV_EXPORTS_W bool isContourConvex( InputArray contour ); CV_EXPORTS_W float intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p12, bool handleNested = true ); -/** @example fitellipse.cpp - An example using the fitEllipse technique +/** @example samples/cpp/fitellipse.cpp +An example using the fitEllipse technique */ /** @brief Fits an ellipse around a set of 2D points. @@ -3637,6 +4167,88 @@ border of the containing Mat element. */ CV_EXPORTS_W RotatedRect fitEllipse( InputArray points ); +/** @brief Fits an ellipse around a set of 2D points. + + The function calculates the ellipse that fits a set of 2D points. + It returns the rotated rectangle in which the ellipse is inscribed. + The Approximate Mean Square (AMS) proposed by @cite Taubin1991 is used. + + For an ellipse, this basis set is \f$ \chi= \left(x^2, x y, y^2, x, y, 1\right) \f$, + which is a set of six free coefficients \f$ A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} \f$. + However, to specify an ellipse, all that is needed is five numbers; the major and minor axes lengths \f$ (a,b) \f$, + the position \f$ (x_0,y_0) \f$, and the orientation \f$ \theta \f$. This is because the basis set includes lines, + quadratics, parabolic and hyperbolic functions as well as elliptical functions as possible fits. + If the fit is found to be a parabolic or hyperbolic function then the standard #fitEllipse method is used. + The AMS method restricts the fit to parabolic, hyperbolic and elliptical curves + by imposing the condition that \f$ A^T ( D_x^T D_x + D_y^T D_y) A = 1 \f$ where + the matrices \f$ Dx \f$ and \f$ Dy \f$ are the partial derivatives of the design matrix \f$ D \f$ with + respect to x and y. The matrices are formed row by row applying the following to + each of the points in the set: + \f{align*}{ + D(i,:)&=\left\{x_i^2, x_i y_i, y_i^2, x_i, y_i, 1\right\} & + D_x(i,:)&=\left\{2 x_i,y_i,0,1,0,0\right\} & + D_y(i,:)&=\left\{0,x_i,2 y_i,0,1,0\right\} + \f} + The AMS method minimizes the cost function + \f{equation*}{ + \epsilon ^2=\frac{ A^T D^T D A }{ A^T (D_x^T D_x + D_y^T D_y) A^T } + \f} + + The minimum cost is found by solving the generalized eigenvalue problem. + + \f{equation*}{ + D^T D A = \lambda \left( D_x^T D_x + D_y^T D_y\right) A + \f} + + @param points Input 2D point set, stored in std::vector\<\> or Mat + */ +CV_EXPORTS_W RotatedRect fitEllipseAMS( InputArray points ); + + +/** @brief Fits an ellipse around a set of 2D points. + + The function calculates the ellipse that fits a set of 2D points. + It returns the rotated rectangle in which the ellipse is inscribed. + The Direct least square (Direct) method by @cite Fitzgibbon1999 is used. + + For an ellipse, this basis set is \f$ \chi= \left(x^2, x y, y^2, x, y, 1\right) \f$, + which is a set of six free coefficients \f$ A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} \f$. + However, to specify an ellipse, all that is needed is five numbers; the major and minor axes lengths \f$ (a,b) \f$, + the position \f$ (x_0,y_0) \f$, and the orientation \f$ \theta \f$. This is because the basis set includes lines, + quadratics, parabolic and hyperbolic functions as well as elliptical functions as possible fits. + The Direct method confines the fit to ellipses by ensuring that \f$ 4 A_{xx} A_{yy}- A_{xy}^2 > 0 \f$. + The condition imposed is that \f$ 4 A_{xx} A_{yy}- A_{xy}^2=1 \f$ which satisfies the inequality + and as the coefficients can be arbitrarily scaled is not overly restrictive. + + \f{equation*}{ + \epsilon ^2= A^T D^T D A \quad \text{with} \quad A^T C A =1 \quad \text{and} \quad C=\left(\begin{matrix} + 0 & 0 & 2 & 0 & 0 & 0 \\ + 0 & -1 & 0 & 0 & 0 & 0 \\ + 2 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 + \end{matrix} \right) + \f} + + The minimum cost is found by solving the generalized eigenvalue problem. + + \f{equation*}{ + D^T D A = \lambda \left( C\right) A + \f} + + The system produces only one positive eigenvalue \f$ \lambda\f$ which is chosen as the solution + with its eigenvector \f$\mathbf{u}\f$. These are used to find the coefficients + + \f{equation*}{ + A = \sqrt{\frac{1}{\mathbf{u}^T C \mathbf{u}}} \mathbf{u} + \f} + The scaling factor guarantees that \f$A^T C A =1\f$. + + @param points Input 2D point set, stored in std::vector\<\> or Mat + */ +CV_EXPORTS_W RotatedRect fitEllipseDirect( InputArray points ); + /** @brief Fits a line to a 2D or 3D point set. The function fitLine fits a line to a 2D or 3D point set by minimizing \f$\sum_i \rho(r_i)\f$ where @@ -3665,7 +4277,7 @@ weights \f$w_i\f$ are adjusted to be inversely proportional to \f$\rho(r_i)\f$ . (x0, y0) is a point on the line. In case of 3D fitting, it should be a vector of 6 elements (like Vec6f) - (vx, vy, vz, x0, y0, z0), where (vx, vy, vz) is a normalized vector collinear to the line and (x0, y0, z0) is a point on the line. -@param distType Distance used by the M-estimator, see cv::DistanceTypes +@param distType Distance used by the M-estimator, see #DistanceTypes @param param Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value is chosen. @param reps Sufficient accuracy for the radius (distance between the coordinate origin and the line). @@ -3694,7 +4306,7 @@ CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measu /** @brief Finds out if there is any intersection between two rotated rectangles. -If there is then the vertices of the interesecting region are returned as well. +If there is then the vertices of the intersecting region are returned as well. Below are some examples of intersection configurations. The hatched pattern indicates the intersecting region and the red vertices are returned by the function. @@ -3703,26 +4315,21 @@ intersecting region and the red vertices are returned by the function. @param rect1 First rectangle @param rect2 Second rectangle -@param intersectingRegion The output array of the verticies of the intersecting region. It returns +@param intersectingRegion The output array of the vertices of the intersecting region. It returns at most 8 vertices. Stored as std::vector\ or cv::Mat as Mx1 of type CV_32FC2. -@returns One of cv::RectanglesIntersectTypes +@returns One of #RectanglesIntersectTypes */ CV_EXPORTS_W int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& rect2, OutputArray intersectingRegion ); -//! @} imgproc_shape - -CV_EXPORTS_W Ptr createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8)); - -//! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122. -//! Detects position only without traslation and rotation +/** @brief Creates a smart pointer to a cv::GeneralizedHoughBallard class and initializes it. +*/ CV_EXPORTS Ptr createGeneralizedHoughBallard(); -//! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038. -//! Detects position, traslation and rotation +/** @brief Creates a smart pointer to a cv::GeneralizedHoughGuil class and initializes it. +*/ CV_EXPORTS Ptr createGeneralizedHoughGuil(); -//! Performs linear blending of two images -CV_EXPORTS void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst); +//! @} imgproc_shape //! @addtogroup imgproc_colormap //! @{ @@ -3742,22 +4349,38 @@ enum ColormapTypes COLORMAP_HSV = 9, //!< ![HSV](pics/colormaps/colorscale_hsv.jpg) COLORMAP_PINK = 10, //!< ![pink](pics/colormaps/colorscale_pink.jpg) COLORMAP_HOT = 11, //!< ![hot](pics/colormaps/colorscale_hot.jpg) - COLORMAP_PARULA = 12 //!< ![hot](pics/colormaps/colorscale_parula.jpg) + COLORMAP_PARULA = 12 //!< ![parula](pics/colormaps/colorscale_parula.jpg) }; +/** @example samples/cpp/falsecolor.cpp +An example using applyColorMap function +*/ + /** @brief Applies a GNU Octave/MATLAB equivalent colormap on a given image. -@param src The source image, grayscale or colored does not matter. +@param src The source image, grayscale or colored of type CV_8UC1 or CV_8UC3. @param dst The result is the colormapped source image. Note: Mat::create is called on dst. -@param colormap The colormap to apply, see cv::ColormapTypes - */ +@param colormap The colormap to apply, see #ColormapTypes +*/ CV_EXPORTS_W void applyColorMap(InputArray src, OutputArray dst, int colormap); +/** @brief Applies a user colormap on a given image. + +@param src The source image, grayscale or colored of type CV_8UC1 or CV_8UC3. +@param dst The result is the colormapped source image. Note: Mat::create is called on dst. +@param userColor The colormap to apply of type CV_8UC1 or CV_8UC3 and size 256 +*/ +CV_EXPORTS_W void applyColorMap(InputArray src, OutputArray dst, InputArray userColor); + //! @} imgproc_colormap //! @addtogroup imgproc_draw //! @{ + +/** OpenCV color channel order is BGR[A] */ +#define CV_RGB(r, g, b) cv::Scalar((b), (g), (r), 0) + /** @brief Draws a line segment connecting two points. The function line draws the line segment between pt1 and pt2 points in the image. The line is @@ -3770,7 +4393,7 @@ lines are drawn using Gaussian filtering. @param pt2 Second point of the line segment. @param color Line color. @param thickness Line thickness. -@param lineType Type of the line, see cv::LineTypes. +@param lineType Type of the line. See #LineTypes. @param shift Number of fractional bits in the point coordinates. */ CV_EXPORTS_W void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, @@ -3778,14 +4401,14 @@ CV_EXPORTS_W void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& /** @brief Draws a arrow segment pointing from the first point to the second one. -The function arrowedLine draws an arrow between pt1 and pt2 points in the image. See also cv::line. +The function cv::arrowedLine draws an arrow between pt1 and pt2 points in the image. See also #line. @param img Image. @param pt1 The point the arrow starts from. @param pt2 The point the arrow points to. @param color Line color. @param thickness Line thickness. -@param line_type Type of the line, see cv::LineTypes +@param line_type Type of the line. See #LineTypes @param shift Number of fractional bits in the point coordinates. @param tipLength The length of the arrow tip in relation to the arrow length */ @@ -3794,16 +4417,16 @@ CV_EXPORTS_W void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const /** @brief Draws a simple, thick, or filled up-right rectangle. -The function rectangle draws a rectangle outline or a filled rectangle whose two opposite corners +The function cv::rectangle draws a rectangle outline or a filled rectangle whose two opposite corners are pt1 and pt2. @param img Image. @param pt1 Vertex of the rectangle. @param pt2 Vertex of the rectangle opposite to pt1 . @param color Rectangle color or brightness (grayscale image). -@param thickness Thickness of lines that make up the rectangle. Negative values, like CV_FILLED , +@param thickness Thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle. -@param lineType Type of the line. See the line description. +@param lineType Type of the line. See #LineTypes @param shift Number of fractional bits in the point coordinates. */ CV_EXPORTS_W void rectangle(InputOutputArray img, Point pt1, Point pt2, @@ -3819,16 +4442,20 @@ CV_EXPORTS void rectangle(CV_IN_OUT Mat& img, Rect rec, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0); +/** @example samples/cpp/tutorial_code/ImgProc/basic_drawing/Drawing_2.cpp +An example using drawing functions +*/ + /** @brief Draws a circle. -The function circle draws a simple or filled circle with a given center and radius. +The function cv::circle draws a simple or filled circle with a given center and radius. @param img Image where the circle is drawn. @param center Center of the circle. @param radius Radius of the circle. @param color Circle color. -@param thickness Thickness of the circle outline, if positive. Negative thickness means that a -filled circle is to be drawn. -@param lineType Type of the circle boundary. See the line description. +@param thickness Thickness of the circle outline, if positive. Negative values, like #FILLED, +mean that a filled circle is to be drawn. +@param lineType Type of the circle boundary. See #LineTypes @param shift Number of fractional bits in the coordinates of the center and in the radius value. */ CV_EXPORTS_W void circle(InputOutputArray img, Point center, int radius, @@ -3837,14 +4464,16 @@ CV_EXPORTS_W void circle(InputOutputArray img, Point center, int radius, /** @brief Draws a simple or thick elliptic arc or fills an ellipse sector. -The functions ellipse with less parameters draw an ellipse outline, a filled ellipse, an elliptic -arc, or a filled ellipse sector. A piecewise-linear curve is used to approximate the elliptic arc +The function cv::ellipse with more parameters draws an ellipse outline, a filled ellipse, an elliptic +arc, or a filled ellipse sector. The drawing code uses general parametric form. +A piecewise-linear curve is used to approximate the elliptic arc boundary. If you need more control of the ellipse rendering, you can retrieve the curve using -ellipse2Poly and then render it with polylines or fill it with fillPoly . If you use the first -variant of the function and want to draw the whole ellipse, not an arc, pass startAngle=0 and -endAngle=360 . The figure below explains the meaning of the parameters. +#ellipse2Poly and then render it with #polylines or fill it with #fillPoly. If you use the first +variant of the function and want to draw the whole ellipse, not an arc, pass `startAngle=0` and +`endAngle=360`. If `startAngle` is greater than `endAngle`, they are swapped. The figure below explains +the meaning of the parameters to draw the blue arc. -![Parameters of Elliptic Arc](pics/ellipse.png) +![Parameters of Elliptic Arc](pics/ellipse.svg) @param img Image. @param center Center of the ellipse. @@ -3855,7 +4484,7 @@ endAngle=360 . The figure below explains the meaning of the parameters. @param color Ellipse color. @param thickness Thickness of the ellipse arc outline, if positive. Otherwise, this indicates that a filled ellipse sector is to be drawn. -@param lineType Type of the ellipse boundary. See the line description. +@param lineType Type of the ellipse boundary. See #LineTypes @param shift Number of fractional bits in the coordinates of the center and values of axes. */ CV_EXPORTS_W void ellipse(InputOutputArray img, Point center, Size axes, @@ -3870,11 +4499,48 @@ an ellipse inscribed in the rotated rectangle. @param color Ellipse color. @param thickness Thickness of the ellipse arc outline, if positive. Otherwise, this indicates that a filled ellipse sector is to be drawn. -@param lineType Type of the ellipse boundary. See the line description. +@param lineType Type of the ellipse boundary. See #LineTypes */ CV_EXPORTS_W void ellipse(InputOutputArray img, const RotatedRect& box, const Scalar& color, int thickness = 1, int lineType = LINE_8); +/* ----------------------------------------------------------------------------------------- */ +/* ADDING A SET OF PREDEFINED MARKERS WHICH COULD BE USED TO HIGHLIGHT POSITIONS IN AN IMAGE */ +/* ----------------------------------------------------------------------------------------- */ + +//! Possible set of marker types used for the cv::drawMarker function +enum MarkerTypes +{ + MARKER_CROSS = 0, //!< A crosshair marker shape + MARKER_TILTED_CROSS = 1, //!< A 45 degree tilted crosshair marker shape + MARKER_STAR = 2, //!< A star marker shape, combination of cross and tilted cross + MARKER_DIAMOND = 3, //!< A diamond marker shape + MARKER_SQUARE = 4, //!< A square marker shape + MARKER_TRIANGLE_UP = 5, //!< An upwards pointing triangle marker shape + MARKER_TRIANGLE_DOWN = 6 //!< A downwards pointing triangle marker shape +}; + +/** @brief Draws a marker on a predefined position in an image. + +The function cv::drawMarker draws a marker on a given position in the image. For the moment several +marker types are supported, see #MarkerTypes for more information. + +@param img Image. +@param position The point where the crosshair is positioned. +@param color Line color. +@param markerType The specific type of marker you want to use, see #MarkerTypes +@param thickness Line thickness. +@param line_type Type of the line, See #LineTypes +@param markerSize The length of the marker axis [default = 20 pixels] + */ +CV_EXPORTS_W void drawMarker(CV_IN_OUT Mat& img, Point position, const Scalar& color, + int markerType = MARKER_CROSS, int markerSize=20, int thickness=1, + int line_type=8); + +/* ----------------------------------------------------------------------------------------- */ +/* END OF MARKER SECTION */ +/* ----------------------------------------------------------------------------------------- */ + /** @overload */ CV_EXPORTS void fillConvexPoly(Mat& img, const Point* pts, int npts, const Scalar& color, int lineType = LINE_8, @@ -3882,15 +4548,15 @@ CV_EXPORTS void fillConvexPoly(Mat& img, const Point* pts, int npts, /** @brief Fills a convex polygon. -The function fillConvexPoly draws a filled convex polygon. This function is much faster than the -function cv::fillPoly . It can fill not only convex polygons but any monotonic polygon without +The function cv::fillConvexPoly draws a filled convex polygon. This function is much faster than the +function #fillPoly . It can fill not only convex polygons but any monotonic polygon without self-intersections, that is, a polygon whose contour intersects every horizontal line (scan line) twice at the most (though, its top-most and/or the bottom edge could be horizontal). @param img Image. @param points Polygon vertices. @param color Polygon color. -@param lineType Type of the polygon boundaries. See the line description. +@param lineType Type of the polygon boundaries. See #LineTypes @param shift Number of fractional bits in the vertex coordinates. */ CV_EXPORTS_W void fillConvexPoly(InputOutputArray img, InputArray points, @@ -3903,16 +4569,21 @@ CV_EXPORTS void fillPoly(Mat& img, const Point** pts, const Scalar& color, int lineType = LINE_8, int shift = 0, Point offset = Point() ); +/** @example samples/cpp/tutorial_code/ImgProc/basic_drawing/Drawing_1.cpp +An example using drawing functions +Check @ref tutorial_random_generator_and_text "the corresponding tutorial" for more details +*/ + /** @brief Fills the area bounded by one or more polygons. -The function fillPoly fills an area bounded by several polygonal contours. The function can fill +The function cv::fillPoly fills an area bounded by several polygonal contours. The function can fill complex areas, for example, areas with holes, contours with self-intersections (some of their parts), and so forth. @param img Image. @param pts Array of polygons where each polygon is represented as an array of points. @param color Polygon color. -@param lineType Type of the polygon boundaries. See the line description. +@param lineType Type of the polygon boundaries. See #LineTypes @param shift Number of fractional bits in the vertex coordinates. @param offset Optional offset of all points of the contours. */ @@ -3933,77 +4604,38 @@ CV_EXPORTS void polylines(Mat& img, const Point* const* pts, const int* npts, the function draws a line from the last vertex of each curve to its first vertex. @param color Polyline color. @param thickness Thickness of the polyline edges. -@param lineType Type of the line segments. See the line description. +@param lineType Type of the line segments. See #LineTypes @param shift Number of fractional bits in the vertex coordinates. -The function polylines draws one or more polygonal curves. +The function cv::polylines draws one or more polygonal curves. */ CV_EXPORTS_W void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0 ); -/** @example contours2.cpp - An example using the drawContour functionality +/** @example samples/cpp/contours2.cpp +An example program illustrates the use of cv::findContours and cv::drawContours +\image html WindowsQtContoursOutput.png "Screenshot of the program" */ -/** @example segment_objects.cpp +/** @example samples/cpp/segment_objects.cpp An example using drawContours to clean up a background segmentation result - */ +*/ /** @brief Draws contours outlines or filled contours. The function draws contour outlines in the image if \f$\texttt{thickness} \ge 0\f$ or fills the area bounded by the contours if \f$\texttt{thickness}<0\f$ . The example below shows how to retrieve connected components from the binary image and label them: : -@code - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - - using namespace cv; - using namespace std; - - int main( int argc, char** argv ) - { - Mat src; - // the first command-line parameter must be a filename of the binary - // (black-n-white) image - if( argc != 2 || !(src=imread(argv[1], 0)).data) - return -1; - - Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3); - - src = src > 1; - namedWindow( "Source", 1 ); - imshow( "Source", src ); - - vector > contours; - vector hierarchy; - - findContours( src, contours, hierarchy, - RETR_CCOMP, CHAIN_APPROX_SIMPLE ); - - // iterate through all the top-level contours, - // draw each connected component with its own random color - int idx = 0; - for( ; idx >= 0; idx = hierarchy[idx][0] ) - { - Scalar color( rand()&255, rand()&255, rand()&255 ); - drawContours( dst, contours, idx, color, FILLED, 8, hierarchy ); - } - - namedWindow( "Components", 1 ); - imshow( "Components", dst ); - waitKey(0); - } -@endcode +@include snippets/imgproc_drawContours.cpp @param image Destination image. @param contours All the input contours. Each contour is stored as a point vector. @param contourIdx Parameter indicating a contour to draw. If it is negative, all the contours are drawn. @param color Color of the contours. @param thickness Thickness of lines the contours are drawn with. If it is negative (for example, -thickness=CV_FILLED ), the contour interiors are drawn. -@param lineType Line connectivity. See cv::LineTypes. +thickness=#FILLED ), the contour interiors are drawn. +@param lineType Line connectivity. See #LineTypes @param hierarchy Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see maxLevel ). @param maxLevel Maximal level for drawn contours. If it is 0, only the specified contour is drawn. @@ -4012,6 +4644,11 @@ draws the contours, all the nested contours, all the nested-to-nested contours, parameter is only taken into account when there is hierarchy available. @param offset Optional contour shift parameter. Shift all the drawn contours by the specified \f$\texttt{offset}=(dx,dy)\f$ . +@note When thickness=#FILLED, the function is designed to handle connected components with holes correctly +even when no hierarchy date is provided. This is done by analyzing all the outlines together +using even-odd rule. This may give incorrect results if you have a joint collection of separately retrieved +contours. In order to solve this problem, you need to call #drawContours separately for each sub-group +of contours, or iterate over the collection using contourIdx parameter. */ CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, @@ -4021,15 +4658,22 @@ CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays conto /** @brief Clips the line against the image rectangle. -The functions clipLine calculate a part of the line segment that is entirely within the specified -rectangle. They return false if the line segment is completely outside the rectangle. Otherwise, -they return true . +The function cv::clipLine calculates a part of the line segment that is entirely within the specified +rectangle. it returns false if the line segment is completely outside the rectangle. Otherwise, +it returns true . @param imgSize Image size. The image rectangle is Rect(0, 0, imgSize.width, imgSize.height) . @param pt1 First line point. @param pt2 Second line point. */ CV_EXPORTS bool clipLine(Size imgSize, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2); +/** @overload +@param imgSize Image size. The image rectangle is Rect(0, 0, imgSize.width, imgSize.height) . +@param pt1 First line point. +@param pt2 Second line point. +*/ +CV_EXPORTS bool clipLine(Size2l imgSize, CV_IN_OUT Point2l& pt1, CV_IN_OUT Point2l& pt2); + /** @overload @param imgRect Image rectangle. @param pt1 First line point. @@ -4040,11 +4684,11 @@ CV_EXPORTS_W bool clipLine(Rect imgRect, CV_OUT CV_IN_OUT Point& pt1, CV_OUT CV_ /** @brief Approximates an elliptic arc with a polyline. The function ellipse2Poly computes the vertices of a polyline that approximates the specified -elliptic arc. It is used by cv::ellipse. +elliptic arc. It is used by #ellipse. If `arcStart` is greater than `arcEnd`, they are swapped. @param center Center of the arc. -@param axes Half of the size of the ellipse main axes. See the ellipse for details. -@param angle Rotation angle of the ellipse in degrees. See the ellipse for details. +@param axes Half of the size of the ellipse main axes. See #ellipse for details. +@param angle Rotation angle of the ellipse in degrees. See #ellipse for details. @param arcStart Starting angle of the elliptic arc in degrees. @param arcEnd Ending angle of the elliptic arc in degrees. @param delta Angle between the subsequent polyline vertices. It defines the approximation @@ -4055,20 +4699,33 @@ CV_EXPORTS_W void ellipse2Poly( Point center, Size axes, int angle, int arcStart, int arcEnd, int delta, CV_OUT std::vector& pts ); +/** @overload +@param center Center of the arc. +@param axes Half of the size of the ellipse main axes. See #ellipse for details. +@param angle Rotation angle of the ellipse in degrees. See #ellipse for details. +@param arcStart Starting angle of the elliptic arc in degrees. +@param arcEnd Ending angle of the elliptic arc in degrees. +@param delta Angle between the subsequent polyline vertices. It defines the approximation accuracy. +@param pts Output vector of polyline vertices. +*/ +CV_EXPORTS void ellipse2Poly(Point2d center, Size2d axes, int angle, + int arcStart, int arcEnd, int delta, + CV_OUT std::vector& pts); + /** @brief Draws a text string. -The function putText renders the specified text string in the image. Symbols that cannot be rendered -using the specified font are replaced by question marks. See getTextSize for a text rendering code +The function cv::putText renders the specified text string in the image. Symbols that cannot be rendered +using the specified font are replaced by question marks. See #getTextSize for a text rendering code example. @param img Image. @param text Text string to be drawn. @param org Bottom-left corner of the text string in the image. -@param fontFace Font type, see cv::HersheyFonts. +@param fontFace Font type, see #HersheyFonts. @param fontScale Font scale factor that is multiplied by the font-specific base size. @param color Text color. @param thickness Thickness of the lines used to draw a text. -@param lineType Line type. See the line for details. +@param lineType Line type. See #LineTypes @param bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner. */ @@ -4079,7 +4736,7 @@ CV_EXPORTS_W void putText( InputOutputArray img, const String& text, Point org, /** @brief Calculates the width and height of a text string. -The function getTextSize calculates and returns the size of a box that contains the specified text. +The function cv::getTextSize calculates and returns the size of a box that contains the specified text. That is, the following code renders some text, the tight box surrounding it, and the baseline: : @code String text = "Funny text inside the box"; @@ -4113,19 +4770,33 @@ That is, the following code renders some text, the tight box surrounding it, and @endcode @param text Input text string. -@param fontFace Font to use, see cv::HersheyFonts. +@param fontFace Font to use, see #HersheyFonts. @param fontScale Font scale factor that is multiplied by the font-specific base size. -@param thickness Thickness of lines used to render the text. See putText for details. +@param thickness Thickness of lines used to render the text. See #putText for details. @param[out] baseLine y-coordinate of the baseline relative to the bottom-most text point. @return The size of a box that contains the specified text. -@see cv::putText +@see putText */ CV_EXPORTS_W Size getTextSize(const String& text, int fontFace, double fontScale, int thickness, CV_OUT int* baseLine); + +/** @brief Calculates the font-specific size to use to achieve a given height in pixels. + +@param fontFace Font to use, see cv::HersheyFonts. +@param pixelHeight Pixel height to compute the fontScale for +@param thickness Thickness of lines used to render the text.See putText for details. +@return The fontSize to use for cv::putText + +@see cv::putText +*/ +CV_EXPORTS_W double getFontScaleFromHeight(const int fontFace, + const int pixelHeight, + const int thickness = 1); + /** @brief Line iterator The class is used to iterate over all the pixels on the raster line @@ -4148,7 +4819,7 @@ LineIterator it2 = it; vector buf(it.count); for(int i = 0; i < it.count; i++, ++it) - buf[i] = *(const Vec3b)*it; + buf[i] = *(const Vec3b*)*it; // alternative way of iterating through the line for(int i = 0; i < it2.count; i++, ++it2) @@ -4161,7 +4832,7 @@ for(int i = 0; i < it2.count; i++, ++it2) class CV_EXPORTS LineIterator { public: - /** @brief intializes the iterator + /** @brief initializes the iterator creates iterators for the line connecting pt1 and pt2 the line will be clipped on the image boundaries diff --git a/include/opencv2/imgproc/detail/distortion_model.hpp b/include/opencv2/imgproc/detail/distortion_model.hpp new file mode 100644 index 0000000..a9c3dde --- /dev/null +++ b/include/opencv2/imgproc/detail/distortion_model.hpp @@ -0,0 +1,123 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP +#define OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP + +//! @cond IGNORED + +namespace cv { namespace detail { +/** +Computes the matrix for the projection onto a tilted image sensor +\param tauX angular parameter rotation around x-axis +\param tauY angular parameter rotation around y-axis +\param matTilt if not NULL returns the matrix +\f[ +\vecthreethree{R_{33}(\tau_x, \tau_y)}{0}{-R_{13}((\tau_x, \tau_y)} +{0}{R_{33}(\tau_x, \tau_y)}{-R_{23}(\tau_x, \tau_y)} +{0}{0}{1} R(\tau_x, \tau_y) +\f] +where +\f[ +R(\tau_x, \tau_y) = +\vecthreethree{\cos(\tau_y)}{0}{-\sin(\tau_y)}{0}{1}{0}{\sin(\tau_y)}{0}{\cos(\tau_y)} +\vecthreethree{1}{0}{0}{0}{\cos(\tau_x)}{\sin(\tau_x)}{0}{-\sin(\tau_x)}{\cos(\tau_x)} = +\vecthreethree{\cos(\tau_y)}{\sin(\tau_y)\sin(\tau_x)}{-\sin(\tau_y)\cos(\tau_x)} +{0}{\cos(\tau_x)}{\sin(\tau_x)} +{\sin(\tau_y)}{-\cos(\tau_y)\sin(\tau_x)}{\cos(\tau_y)\cos(\tau_x)}. +\f] +\param dMatTiltdTauX if not NULL it returns the derivative of matTilt with +respect to \f$\tau_x\f$. +\param dMatTiltdTauY if not NULL it returns the derivative of matTilt with +respect to \f$\tau_y\f$. +\param invMatTilt if not NULL it returns the inverse of matTilt +**/ +template +void computeTiltProjectionMatrix(FLOAT tauX, + FLOAT tauY, + Matx* matTilt = 0, + Matx* dMatTiltdTauX = 0, + Matx* dMatTiltdTauY = 0, + Matx* invMatTilt = 0) +{ + FLOAT cTauX = cos(tauX); + FLOAT sTauX = sin(tauX); + FLOAT cTauY = cos(tauY); + FLOAT sTauY = sin(tauY); + Matx matRotX = Matx(1,0,0,0,cTauX,sTauX,0,-sTauX,cTauX); + Matx matRotY = Matx(cTauY,0,-sTauY,0,1,0,sTauY,0,cTauY); + Matx matRotXY = matRotY * matRotX; + Matx matProjZ = Matx(matRotXY(2,2),0,-matRotXY(0,2),0,matRotXY(2,2),-matRotXY(1,2),0,0,1); + if (matTilt) + { + // Matrix for trapezoidal distortion of tilted image sensor + *matTilt = matProjZ * matRotXY; + } + if (dMatTiltdTauX) + { + // Derivative with respect to tauX + Matx dMatRotXYdTauX = matRotY * Matx(0,0,0,0,-sTauX,cTauX,0,-cTauX,-sTauX); + Matx dMatProjZdTauX = Matx(dMatRotXYdTauX(2,2),0,-dMatRotXYdTauX(0,2), + 0,dMatRotXYdTauX(2,2),-dMatRotXYdTauX(1,2),0,0,0); + *dMatTiltdTauX = (matProjZ * dMatRotXYdTauX) + (dMatProjZdTauX * matRotXY); + } + if (dMatTiltdTauY) + { + // Derivative with respect to tauY + Matx dMatRotXYdTauY = Matx(-sTauY,0,-cTauY,0,0,0,cTauY,0,-sTauY) * matRotX; + Matx dMatProjZdTauY = Matx(dMatRotXYdTauY(2,2),0,-dMatRotXYdTauY(0,2), + 0,dMatRotXYdTauY(2,2),-dMatRotXYdTauY(1,2),0,0,0); + *dMatTiltdTauY = (matProjZ * dMatRotXYdTauY) + (dMatProjZdTauY * matRotXY); + } + if (invMatTilt) + { + FLOAT inv = 1./matRotXY(2,2); + Matx invMatProjZ = Matx(inv,0,inv*matRotXY(0,2),0,inv,inv*matRotXY(1,2),0,0,1); + *invMatTilt = matRotXY.t()*invMatProjZ; + } +} +}} // namespace detail, cv + + +//! @endcond + +#endif // OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP diff --git a/include/opencv2/imgproc/hal/hal.hpp b/include/opencv2/imgproc/hal/hal.hpp new file mode 100644 index 0000000..a435fd6 --- /dev/null +++ b/include/opencv2/imgproc/hal/hal.hpp @@ -0,0 +1,241 @@ +#ifndef CV_IMGPROC_HAL_HPP +#define CV_IMGPROC_HAL_HPP + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" +#include "opencv2/core/hal/interface.h" + +namespace cv { namespace hal { + +//! @addtogroup imgproc_hal_functions +//! @{ + +//--------------------------- +//! @cond IGNORED + +struct CV_EXPORTS Filter2D +{ + CV_DEPRECATED static Ptr create(uchar * , size_t , int , + int , int , + int , int , + int , int , + int , double , + int , int , + bool , bool ); + virtual void apply(uchar * , size_t , + uchar * , size_t , + int , int , + int , int , + int , int ) = 0; + virtual ~Filter2D() {} +}; + +struct CV_EXPORTS SepFilter2D +{ + CV_DEPRECATED static Ptr create(int , int , int , + uchar * , int , + uchar * , int , + int , int , + double , int ); + virtual void apply(uchar * , size_t , + uchar * , size_t , + int , int , + int , int , + int , int ) = 0; + virtual ~SepFilter2D() {} +}; + + +struct CV_EXPORTS Morph +{ + CV_DEPRECATED static Ptr create(int , int , int , int , int , + int , uchar * , size_t , + int , int , + int , int , + int , const double *, + int , bool , bool ); + virtual void apply(uchar * , size_t , uchar * , size_t , int , int , + int , int , int , int , + int , int , int , int ) = 0; + virtual ~Morph() {} +}; + +//! @endcond +//--------------------------- + +CV_EXPORTS void filter2D(int stype, int dtype, int kernel_type, + uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int full_width, int full_height, + int offset_x, int offset_y, + uchar * kernel_data, size_t kernel_step, + int kernel_width, int kernel_height, + int anchor_x, int anchor_y, + double delta, int borderType, + bool isSubmatrix); + +CV_EXPORTS void sepFilter2D(int stype, int dtype, int ktype, + uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int full_width, int full_height, + int offset_x, int offset_y, + uchar * kernelx_data, int kernelx_len, + uchar * kernely_data, int kernely_len, + int anchor_x, int anchor_y, + double delta, int borderType); + +CV_EXPORTS void morph(int op, int src_type, int dst_type, + uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int roi_width, int roi_height, int roi_x, int roi_y, + int roi_width2, int roi_height2, int roi_x2, int roi_y2, + int kernel_type, uchar * kernel_data, size_t kernel_step, + int kernel_width, int kernel_height, int anchor_x, int anchor_y, + int borderType, const double borderValue[4], + int iterations, bool isSubmatrix); + + +CV_EXPORTS void resize(int src_type, + const uchar * src_data, size_t src_step, int src_width, int src_height, + uchar * dst_data, size_t dst_step, int dst_width, int dst_height, + double inv_scale_x, double inv_scale_y, int interpolation); + +CV_EXPORTS void warpAffine(int src_type, + const uchar * src_data, size_t src_step, int src_width, int src_height, + uchar * dst_data, size_t dst_step, int dst_width, int dst_height, + const double M[6], int interpolation, int borderType, const double borderValue[4]); + +CV_EXPORTS void warpPerspectve(int src_type, + const uchar * src_data, size_t src_step, int src_width, int src_height, + uchar * dst_data, size_t dst_step, int dst_width, int dst_height, + const double M[9], int interpolation, int borderType, const double borderValue[4]); + +CV_EXPORTS void cvtBGRtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, int dcn, bool swapBlue); + +CV_EXPORTS void cvtBGRtoBGR5x5(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int greenBits); + +CV_EXPORTS void cvtBGR5x5toBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int dcn, bool swapBlue, int greenBits); + +CV_EXPORTS void cvtBGRtoGray(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue); + +CV_EXPORTS void cvtGraytoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn); + +CV_EXPORTS void cvtBGR5x5toGray(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int greenBits); + +CV_EXPORTS void cvtGraytoBGR5x5(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int greenBits); +CV_EXPORTS void cvtBGRtoYUV(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue, bool isCbCr); + +CV_EXPORTS void cvtYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue, bool isCbCr); + +CV_EXPORTS void cvtBGRtoXYZ(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue); + +CV_EXPORTS void cvtXYZtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue); + +CV_EXPORTS void cvtBGRtoHSV(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue, bool isFullRange, bool isHSV); + +CV_EXPORTS void cvtHSVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue, bool isFullRange, bool isHSV); + +CV_EXPORTS void cvtBGRtoLab(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue, bool isLab, bool srgb); + +CV_EXPORTS void cvtLabtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue, bool isLab, bool srgb); + +CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + +//! Separate Y and UV planes +CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + +CV_EXPORTS void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + +CV_EXPORTS void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int uIdx); + +//! Separate Y and UV planes +CV_EXPORTS void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step, + uchar * y_data, uchar * uv_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int uIdx); + +CV_EXPORTS void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int dcn, bool swapBlue, int uIdx, int ycn); + +CV_EXPORTS void cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height); + +CV_EXPORTS void cvtMultipliedRGBAtoRGBA(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height); + +CV_EXPORTS void integral(int depth, int sdepth, int sqdepth, + const uchar* src, size_t srcstep, + uchar* sum, size_t sumstep, + uchar* sqsum, size_t sqsumstep, + uchar* tilted, size_t tstep, + int width, int height, int cn); + +//! @} + +}} + +#endif // CV_IMGPROC_HAL_HPP diff --git a/include/opencv2/imgproc/hal/interface.h b/include/opencv2/imgproc/hal/interface.h new file mode 100644 index 0000000..f8dbcfe --- /dev/null +++ b/include/opencv2/imgproc/hal/interface.h @@ -0,0 +1,46 @@ +#ifndef OPENCV_IMGPROC_HAL_INTERFACE_H +#define OPENCV_IMGPROC_HAL_INTERFACE_H + +//! @addtogroup imgproc_hal_interface +//! @{ + +//! @name Interpolation modes +//! @sa cv::InterpolationFlags +//! @{ +#define CV_HAL_INTER_NEAREST 0 +#define CV_HAL_INTER_LINEAR 1 +#define CV_HAL_INTER_CUBIC 2 +#define CV_HAL_INTER_AREA 3 +#define CV_HAL_INTER_LANCZOS4 4 +//! @} + +//! @name Morphology operations +//! @sa cv::MorphTypes +//! @{ +#define CV_HAL_MORPH_ERODE 0 +#define CV_HAL_MORPH_DILATE 1 +//! @} + +//! @name Threshold types +//! @sa cv::ThresholdTypes +//! @{ +#define CV_HAL_THRESH_BINARY 0 +#define CV_HAL_THRESH_BINARY_INV 1 +#define CV_HAL_THRESH_TRUNC 2 +#define CV_HAL_THRESH_TOZERO 3 +#define CV_HAL_THRESH_TOZERO_INV 4 +#define CV_HAL_THRESH_MASK 7 +#define CV_HAL_THRESH_OTSU 8 +#define CV_HAL_THRESH_TRIANGLE 16 +//! @} + +//! @name Adaptive threshold algorithm +//! @sa cv::AdaptiveThresholdTypes +//! @{ +#define CV_HAL_ADAPTIVE_THRESH_MEAN_C 0 +#define CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C 1 +//! @} + +//! @} + +#endif diff --git a/include/opencv2/imgproc/imgproc_c.h b/include/opencv2/imgproc/imgproc_c.h index 87518d7..cec0f36 100644 --- a/include/opencv2/imgproc/imgproc_c.h +++ b/include/opencv2/imgproc/imgproc_c.h @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_IMGPROC_IMGPROC_C_H__ -#define __OPENCV_IMGPROC_IMGPROC_C_H__ +#ifndef OPENCV_IMGPROC_IMGPROC_C_H +#define OPENCV_IMGPROC_IMGPROC_C_H #include "opencv2/imgproc/types_c.h" @@ -260,14 +260,14 @@ CVAPI(void) cvConvertMaps( const CvArr* mapx, const CvArr* mapy, CvArr* mapxy, CvArr* mapalpha ); /** @brief Performs forward or inverse log-polar image transform -@see cv::logPolar +@see cv::warpPolar */ CVAPI(void) cvLogPolar( const CvArr* src, CvArr* dst, CvPoint2D32f center, double M, int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS)); /** Performs forward or inverse linear-polar image transform -@see cv::linearPolar +@see cv::warpPolar */ CVAPI(void) cvLinearPolar( const CvArr* src, CvArr* dst, CvPoint2D32f center, double maxRadius, @@ -982,7 +982,6 @@ CVAPI(void) cvFitLine( const CvArr* points, int dist_type, double param, * If a drawn figure is partially or completely outside of the image, it is clipped.* \****************************************************************************************/ -#define CV_RGB( r, g, b ) cvScalar( (b), (g), (r), 0 ) #define CV_FILLED -1 #define CV_AA 16 @@ -1037,9 +1036,10 @@ CV_INLINE void cvEllipseBox( CvArr* img, CvBox2D box, CvScalar color, int thickness CV_DEFAULT(1), int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ) { - CvSize axes; - axes.width = cvRound(box.size.width*0.5); - axes.height = cvRound(box.size.height*0.5); + CvSize axes = cvSize( + cvRound(box.size.width*0.5), + cvRound(box.size.height*0.5) + ); cvEllipse( img, cvPointFrom32f( box.center ), axes, box.angle, 0, 360, color, thickness, line_type, shift ); diff --git a/include/opencv2/imgproc/types_c.h b/include/opencv2/imgproc/types_c.h index 5ecb460..d3e55f5 100644 --- a/include/opencv2/imgproc/types_c.h +++ b/include/opencv2/imgproc/types_c.h @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_IMGPROC_TYPES_C_H__ -#define __OPENCV_IMGPROC_TYPES_C_H__ +#ifndef OPENCV_IMGPROC_TYPES_C_H +#define OPENCV_IMGPROC_TYPES_C_H #include "opencv2/core/core_c.h" @@ -349,7 +349,17 @@ enum CV_BayerRG2RGB_EA = CV_BayerBG2BGR_EA, CV_BayerGR2RGB_EA = CV_BayerGB2BGR_EA, - CV_COLORCVT_MAX = 139 + CV_BayerBG2BGRA =139, + CV_BayerGB2BGRA =140, + CV_BayerRG2BGRA =141, + CV_BayerGR2BGRA =142, + + CV_BayerBG2RGBA =CV_BayerRG2BGRA, + CV_BayerGB2RGBA =CV_BayerGR2BGRA, + CV_BayerRG2RGBA =CV_BayerBG2BGRA, + CV_BayerGR2RGBA =CV_BayerGB2BGRA, + + CV_COLORCVT_MAX = 143 }; @@ -400,7 +410,7 @@ typedef struct CvMoments double mu20, mu11, mu02, mu30, mu21, mu12, mu03; /**< central moments */ double inv_sqrt_m00; /**< m00 != 0 ? 1/sqrt(m00) : 0 */ -#ifdef __cplusplus +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) CvMoments(){} CvMoments(const cv::Moments& m) { @@ -420,6 +430,36 @@ typedef struct CvMoments } CvMoments; +#ifdef __cplusplus +} // extern "C" + +CV_INLINE CvMoments cvMoments() +{ +#if !defined(CV__ENABLE_C_API_CTORS) + CvMoments self = CV_STRUCT_INITIALIZER; return self; +#else + return CvMoments(); +#endif +} + +CV_INLINE CvMoments cvMoments(const cv::Moments& m) +{ +#if !defined(CV__ENABLE_C_API_CTORS) + double am00 = std::abs(m.m00); + CvMoments self = { + m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03, + m.mu20, m.mu11, m.mu02, m.mu30, m.mu21, m.mu12, m.mu03, + am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0 + }; + return self; +#else + return CvMoments(m); +#endif +} + +extern "C" { +#endif // __cplusplus + /** Hu invariants */ typedef struct CvHuMoments { @@ -491,15 +531,8 @@ enum CV_POLY_APPROX_DP = 0 }; -/** @brief Shape matching methods - -\f$A\f$ denotes object1,\f$B\f$ denotes object2 - -\f$\begin{array}{l} m^A_i = \mathrm{sign} (h^A_i) \cdot \log{h^A_i} \\ m^B_i = \mathrm{sign} (h^B_i) \cdot \log{h^B_i} \end{array}\f$ - -and \f$h^A_i, h^B_i\f$ are the Hu moments of \f$A\f$ and \f$B\f$ , respectively. -*/ -enum ShapeMatchModes +/** Shape matching methods */ +enum { CV_CONTOURS_MATCH_I1 =1, //!< \f[I_1(A,B) = \sum _{i=1...7} \left | \frac{1}{m^A_i} - \frac{1}{m^B_i} \right |\f] CV_CONTOURS_MATCH_I2 =2, //!< \f[I_2(A,B) = \sum _{i=1...7} \left | m^A_i - m^B_i \right |\f] diff --git a/include/opencv2/ml.hpp b/include/opencv2/ml.hpp index d0d2c33..f2ca78f 100644 --- a/include/opencv2/ml.hpp +++ b/include/opencv2/ml.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_ML_HPP__ -#define __OPENCV_ML_HPP__ +#ifndef OPENCV_ML_HPP +#define OPENCV_ML_HPP #ifdef __cplusplus # include "opencv2/core.hpp" @@ -104,7 +104,7 @@ enum SampleTypes It is used for optimizing statmodel accuracy by varying model parameters, the accuracy estimate being computed by cross-validation. */ -class CV_EXPORTS ParamGrid +class CV_EXPORTS_W ParamGrid { public: /** @brief Default constructor */ @@ -112,8 +112,8 @@ public: /** @brief Constructor with parameters */ ParamGrid(double _minVal, double _maxVal, double _logStep); - double minVal; //!< Minimum value of the statmodel parameter. Default value is 0. - double maxVal; //!< Maximum value of the statmodel parameter. Default value is 0. + CV_PROP_RW double minVal; //!< Minimum value of the statmodel parameter. Default value is 0. + CV_PROP_RW double maxVal; //!< Maximum value of the statmodel parameter. Default value is 0. /** @brief Logarithmic step for iterating the statmodel parameter. The grid determines the following iteration sequence of the statmodel parameter values: @@ -122,7 +122,15 @@ public: \f[\texttt{minVal} * \texttt{logStep} ^n < \texttt{maxVal}\f] The grid is logarithmic, so logStep must always be greater then 1. Default value is 1. */ - double logStep; + CV_PROP_RW double logStep; + + /** @brief Creates a ParamGrid Ptr that can be given to the %SVM::trainAuto method + + @param minVal minimum value of the parameter grid + @param maxVal maximum value of the parameter grid + @param logstep Logarithmic step for iterating the statmodel parameter + */ + CV_WRAP static Ptr create(double minVal=0., double maxVal=0., double logstep=1.); }; /** @brief Class encapsulating training data. @@ -190,6 +198,7 @@ public: CV_WRAP virtual Mat getTestSampleWeights() const = 0; CV_WRAP virtual Mat getVarIdx() const = 0; CV_WRAP virtual Mat getVarType() const = 0; + CV_WRAP Mat getVarSymbolFlags() const; CV_WRAP virtual int getResponseType() const = 0; CV_WRAP virtual Mat getTrainSampleIdx() const = 0; CV_WRAP virtual Mat getTestSampleIdx() const = 0; @@ -224,7 +233,24 @@ public: CV_WRAP virtual void setTrainTestSplitRatio(double ratio, bool shuffle=true) = 0; CV_WRAP virtual void shuffleTrainTest() = 0; - CV_WRAP static Mat getSubVector(const Mat& vec, const Mat& idx); + /** @brief Returns matrix of test samples */ + CV_WRAP Mat getTestSamples() const; + + /** @brief Returns vector of symbolic names captured in loadFromCSV() */ + CV_WRAP void getNames(std::vector& names) const; + + /** @brief Extract from 1D vector elements specified by passed indexes. + @param vec input vector (supported types: CV_32S, CV_32F, CV_64F) + @param idx 1D index vector + */ + static CV_WRAP Mat getSubVector(const Mat& vec, const Mat& idx); + + /** @brief Extract from matrix rows/cols specified by passed indexes. + @param matrix input matrix (supported types: CV_32S, CV_32F, CV_64F) + @param idx 1D index vector + @param layout specifies to extract rows (cv::ml::ROW_SAMPLES) or to extract columns (cv::ml::COL_SAMPLES) + */ + static CV_WRAP Mat getSubMatrix(const Mat& matrix, const Mat& idx, int layout); /** @brief Reads the dataset from a .csv file and returns the ready-to-use training data. @@ -252,6 +278,8 @@ public: @param missch The character used to specify missing measurements. It should not be a digit. Although it's a non-numerical value, it surely does not affect the decision of whether the variable ordered or categorical. + @note If the dataset only contains input variables and no responses, use responseStartIdx = -2 + and responseEndIdx = 0. The output variables vector will just contain zeros. */ static Ptr loadFromCSV(const String& filename, int headerLineCount, @@ -301,7 +329,7 @@ public: /** @brief Returns the number of variables in training samples */ CV_WRAP virtual int getVarCount() const = 0; - CV_WRAP virtual bool empty() const; + CV_WRAP virtual bool empty() const CV_OVERRIDE; /** @brief Returns true if the model is trained */ CV_WRAP virtual bool isTrained() const = 0; @@ -384,6 +412,17 @@ public: /** Creates empty model Use StatModel::train to train the model after creation. */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized NormalBayesClassifier from a file + * + * Use NormalBayesClassifier::save to serialize and store an NormalBayesClassifier to disk. + * Load the NormalBayesClassifier from this file again, by calling this function with the path to the file. + * Optionally specify the node for the file containing the classifier + * + * @param filepath path to serialized NormalBayesClassifier + * @param nodeName name of node containing the classifier + */ + CV_WRAP static Ptr load(const String& filepath , const String& nodeName = String()); }; /****************************************************************************************\ @@ -663,21 +702,69 @@ public: the usual %SVM with parameters specified in params is executed. */ virtual bool trainAuto( const Ptr& data, int kFold = 10, - ParamGrid Cgrid = SVM::getDefaultGrid(SVM::C), - ParamGrid gammaGrid = SVM::getDefaultGrid(SVM::GAMMA), - ParamGrid pGrid = SVM::getDefaultGrid(SVM::P), - ParamGrid nuGrid = SVM::getDefaultGrid(SVM::NU), - ParamGrid coeffGrid = SVM::getDefaultGrid(SVM::COEF), - ParamGrid degreeGrid = SVM::getDefaultGrid(SVM::DEGREE), + ParamGrid Cgrid = getDefaultGrid(C), + ParamGrid gammaGrid = getDefaultGrid(GAMMA), + ParamGrid pGrid = getDefaultGrid(P), + ParamGrid nuGrid = getDefaultGrid(NU), + ParamGrid coeffGrid = getDefaultGrid(COEF), + ParamGrid degreeGrid = getDefaultGrid(DEGREE), bool balanced=false) = 0; + /** @brief Trains an %SVM with optimal parameters + + @param samples training samples + @param layout See ml::SampleTypes. + @param responses vector of responses associated with the training samples. + @param kFold Cross-validation parameter. The training set is divided into kFold subsets. One + subset is used to test the model, the others form the train set. So, the %SVM algorithm is + @param Cgrid grid for C + @param gammaGrid grid for gamma + @param pGrid grid for p + @param nuGrid grid for nu + @param coeffGrid grid for coeff + @param degreeGrid grid for degree + @param balanced If true and the problem is 2-class classification then the method creates more + balanced cross-validation subsets that is proportions between classes in subsets are close + to such proportion in the whole train dataset. + + The method trains the %SVM model automatically by choosing the optimal parameters C, gamma, p, + nu, coef0, degree. Parameters are considered optimal when the cross-validation + estimate of the test set error is minimal. + + This function only makes use of SVM::getDefaultGrid for parameter optimization and thus only + offers rudimentary parameter options. + + This function works for the classification (SVM::C_SVC or SVM::NU_SVC) as well as for the + regression (SVM::EPS_SVR or SVM::NU_SVR). If it is SVM::ONE_CLASS, no optimization is made and + the usual %SVM with parameters specified in params is executed. + */ + CV_WRAP bool trainAuto(InputArray samples, + int layout, + InputArray responses, + int kFold = 10, + Ptr Cgrid = SVM::getDefaultGridPtr(SVM::C), + Ptr gammaGrid = SVM::getDefaultGridPtr(SVM::GAMMA), + Ptr pGrid = SVM::getDefaultGridPtr(SVM::P), + Ptr nuGrid = SVM::getDefaultGridPtr(SVM::NU), + Ptr coeffGrid = SVM::getDefaultGridPtr(SVM::COEF), + Ptr degreeGrid = SVM::getDefaultGridPtr(SVM::DEGREE), + bool balanced=false); + /** @brief Retrieves all the support vectors - The method returns all the support vector as floating-point matrix, where support vectors are + The method returns all the support vectors as a floating-point matrix, where support vectors are stored as matrix rows. */ CV_WRAP virtual Mat getSupportVectors() const = 0; + /** @brief Retrieves all the uncompressed support vectors of a linear %SVM + + The method returns all the uncompressed support vectors of a linear %SVM that the compressed + support vector, used for prediction, was derived from. They are returned in a floating-point + matrix, where the support vectors are stored as matrix rows. + */ + CV_WRAP Mat getUncompressedSupportVectors() const; + /** @brief Retrieves the decision function @param i the index of the decision function. If the problem solved is regression, 1-class or @@ -705,10 +792,29 @@ public: */ static ParamGrid getDefaultGrid( int param_id ); + /** @brief Generates a grid for %SVM parameters. + + @param param_id %SVM parameters IDs that must be one of the SVM::ParamTypes. The grid is + generated for the parameter with this ID. + + The function generates a grid pointer for the specified parameter of the %SVM algorithm. + The grid may be passed to the function SVM::trainAuto. + */ + CV_WRAP static Ptr getDefaultGridPtr( int param_id ); + /** Creates empty model. Use StatModel::train to train the model. Since %SVM has several parameters, you may want to find the best parameters for your problem, it can be done with SVM::trainAuto. */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized svm from a file + * + * Use SVM::save to serialize and store an SVM to disk. + * Load the SVM from this file again, by calling this function with the path to the file. + * + * @param filepath path to serialized svm + */ + CV_WRAP static Ptr load(const String& filepath); }; /****************************************************************************************\ @@ -790,7 +896,16 @@ public: Returns vector of covariation matrices. Number of matrices is the number of gaussian mixtures, each matrix is a square floating-point matrix NxN, where N is the space dimensionality. */ - virtual void getCovs(std::vector& covs) const = 0; + CV_WRAP virtual void getCovs(CV_OUT std::vector& covs) const = 0; + + /** @brief Returns posterior probabilities for the provided samples + + @param samples The input samples, floating-point matrix + @param results The optional output \f$ nSamples \times nClusters\f$ matrix of results. It contains + posterior probabilities for each sample from the input + @param flags This parameter will be ignored + */ + CV_WRAP virtual float predict( InputArray samples, OutputArray results=noArray(), int flags=0 ) const CV_OVERRIDE = 0; /** @brief Returns a likelihood logarithm value and an index of the most probable mixture component for the given sample. @@ -804,7 +919,7 @@ public: the sample. First element is an index of the most probable mixture component for the given sample. */ - CV_WRAP CV_WRAP virtual Vec2d predict2(InputArray sample, OutputArray probs) const = 0; + CV_WRAP virtual Vec2d predict2(InputArray sample, OutputArray probs) const = 0; /** @brief Estimate the Gaussian mixture parameters from a samples set. @@ -901,6 +1016,17 @@ public: can use one of the EM::train\* methods or load it from file using Algorithm::load\(filename). */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized EM from a file + * + * Use EM::save to serialize and store an EM to disk. + * Load the EM from this file again, by calling this function with the path to the file. + * Optionally specify the node for the file containing the classifier + * + * @param filepath path to serialized EM + * @param nodeName name of node containing the classifier + */ + CV_WRAP static Ptr load(const String& filepath , const String& nodeName = String()); }; /****************************************************************************************\ @@ -1089,6 +1215,17 @@ public: file using Algorithm::load\(filename). */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized DTrees from a file + * + * Use DTree::save to serialize and store an DTree to disk. + * Load the DTree from this file again, by calling this function with the path to the file. + * Optionally specify the node for the file containing the classifier + * + * @param filepath path to serialized DTree + * @param nodeName name of node containing the classifier + */ + CV_WRAP static Ptr load(const String& filepath , const String& nodeName = String()); }; /****************************************************************************************\ @@ -1138,11 +1275,33 @@ public: */ CV_WRAP virtual Mat getVarImportance() const = 0; + /** Returns the result of each individual tree in the forest. + In case the model is a regression problem, the method will return each of the trees' + results for each of the sample cases. If the model is a classifier, it will return + a Mat with samples + 1 rows, where the first row gives the class number and the + following rows return the votes each class had for each sample. + @param samples Array containing the samples for which votes will be calculated. + @param results Array where the result of the calculation will be written. + @param flags Flags for defining the type of RTrees. + */ + CV_WRAP void getVotes(InputArray samples, OutputArray results, int flags) const; + /** Creates the empty model. Use StatModel::train to train the model, StatModel::train to create and train the model, Algorithm::load to load the pre-trained model. */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized RTree from a file + * + * Use RTree::save to serialize and store an RTree to disk. + * Load the RTree from this file again, by calling this function with the path to the file. + * Optionally specify the node for the file containing the classifier + * + * @param filepath path to serialized RTree + * @param nodeName name of node containing the classifier + */ + CV_WRAP static Ptr load(const String& filepath , const String& nodeName = String()); }; /****************************************************************************************\ @@ -1192,6 +1351,17 @@ public: /** Creates the empty model. Use StatModel::train to train the model, Algorithm::load\(filename) to load the pre-trained model. */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized Boost from a file + * + * Use Boost::save to serialize and store an RTree to disk. + * Load the Boost from this file again, by calling this function with the path to the file. + * Optionally specify the node for the file containing the classifier + * + * @param filepath path to serialized Boost + * @param nodeName name of node containing the classifier + */ + CV_WRAP static Ptr load(const String& filepath , const String& nodeName = String()); }; /****************************************************************************************\ @@ -1247,13 +1417,14 @@ public: /** Available training methods */ enum TrainingMethods { BACKPROP=0, //!< The back-propagation algorithm. - RPROP=1 //!< The RPROP algorithm. See @cite RPROP93 for details. + RPROP = 1, //!< The RPROP algorithm. See @cite RPROP93 for details. + ANNEAL = 2 //!< The simulated annealing algorithm. See @cite Kirkpatrick83 for details. }; /** Sets training method and common parameters. @param method Default value is ANN_MLP::RPROP. See ANN_MLP::TrainingMethods. - @param param1 passed to setRpropDW0 for ANN_MLP::RPROP and to setBackpropWeightScale for ANN_MLP::BACKPROP - @param param2 passed to setRpropDWMin for ANN_MLP::RPROP and to setBackpropMomentumScale for ANN_MLP::BACKPROP. + @param param1 passed to setRpropDW0 for ANN_MLP::RPROP and to setBackpropWeightScale for ANN_MLP::BACKPROP and to initialT for ANN_MLP::ANNEAL. + @param param2 passed to setRpropDWMin for ANN_MLP::RPROP and to setBackpropMomentumScale for ANN_MLP::BACKPROP and to finalT for ANN_MLP::ANNEAL. */ CV_WRAP virtual void setTrainMethod(int method, double param1 = 0, double param2 = 0) = 0; @@ -1340,18 +1511,53 @@ public: /** @copybrief getRpropDWMax @see getRpropDWMax */ CV_WRAP virtual void setRpropDWMax(double val) = 0; + /** ANNEAL: Update initial temperature. + It must be \>=0. Default value is 10.*/ + /** @see setAnnealInitialT */ + CV_WRAP double getAnnealInitialT() const; + /** @copybrief getAnnealInitialT @see getAnnealInitialT */ + CV_WRAP void setAnnealInitialT(double val); + + /** ANNEAL: Update final temperature. + It must be \>=0 and less than initialT. Default value is 0.1.*/ + /** @see setAnnealFinalT */ + CV_WRAP double getAnnealFinalT() const; + /** @copybrief getAnnealFinalT @see getAnnealFinalT */ + CV_WRAP void setAnnealFinalT(double val); + + /** ANNEAL: Update cooling ratio. + It must be \>0 and less than 1. Default value is 0.95.*/ + /** @see setAnnealCoolingRatio */ + CV_WRAP double getAnnealCoolingRatio() const; + /** @copybrief getAnnealCoolingRatio @see getAnnealCoolingRatio */ + CV_WRAP void setAnnealCoolingRatio(double val); + + /** ANNEAL: Update iteration per step. + It must be \>0 . Default value is 10.*/ + /** @see setAnnealItePerStep */ + CV_WRAP int getAnnealItePerStep() const; + /** @copybrief getAnnealItePerStep @see getAnnealItePerStep */ + CV_WRAP void setAnnealItePerStep(int val); + + /** @brief Set/initialize anneal RNG */ + void setAnnealEnergyRNG(const RNG& rng); + /** possible activation functions */ enum ActivationFunctions { /** Identity function: \f$f(x)=x\f$ */ IDENTITY = 0, - /** Symmetrical sigmoid: \f$f(x)=\beta*(1-e^{-\alpha x})/(1+e^{-\alpha x}\f$ + /** Symmetrical sigmoid: \f$f(x)=\beta*(1-e^{-\alpha x})/(1+e^{-\alpha x})\f$ @note If you are using the default sigmoid activation function with the default parameter values fparam1=0 and fparam2=0 then the function used is y = 1.7159\*tanh(2/3 \* x), so the output will range from [-1.7159, 1.7159], instead of [0,1].*/ SIGMOID_SYM = 1, /** Gaussian function: \f$f(x)=\beta e^{-\alpha x*x}\f$ */ - GAUSSIAN = 2 + GAUSSIAN = 2, + /** ReLU function: \f$f(x)=max(0,x)\f$ */ + RELU = 3, + /** Leaky ReLU function: for x>0 \f$f(x)=x \f$ and x<=0 \f$f(x)=\alpha x \f$*/ + LEAKYRELU= 4 }; /** Train options */ @@ -1379,6 +1585,16 @@ public: Note that the train method has optional flags: ANN_MLP::TrainFlags. */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized ANN from a file + * + * Use ANN::save to serialize and store an ANN to disk. + * Load the ANN from this file again, by calling this function with the path to the file. + * + * @param filepath path to serialized ANN + */ + CV_WRAP static Ptr load(const String& filepath); + }; /****************************************************************************************\ @@ -1451,11 +1667,11 @@ public: @param results Predicted labels as a column matrix of type CV_32S. @param flags Not used. */ - CV_WRAP virtual float predict( InputArray samples, OutputArray results=noArray(), int flags=0 ) const = 0; + CV_WRAP virtual float predict( InputArray samples, OutputArray results=noArray(), int flags=0 ) const CV_OVERRIDE = 0; - /** @brief This function returns the trained paramters arranged across rows. + /** @brief This function returns the trained parameters arranged across rows. - For a two class classifcation problem, it returns a row matrix. It returns learnt paramters of + For a two class classifcation problem, it returns a row matrix. It returns learnt parameters of the Logistic Regression as a matrix of type CV_32F. */ CV_WRAP virtual Mat get_learnt_thetas() const = 0; @@ -1465,10 +1681,191 @@ public: Creates Logistic Regression model with parameters given. */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized LogisticRegression from a file + * + * Use LogisticRegression::save to serialize and store an LogisticRegression to disk. + * Load the LogisticRegression from this file again, by calling this function with the path to the file. + * Optionally specify the node for the file containing the classifier + * + * @param filepath path to serialized LogisticRegression + * @param nodeName name of node containing the classifier + */ + CV_WRAP static Ptr load(const String& filepath , const String& nodeName = String()); }; + /****************************************************************************************\ -* Auxilary functions declarations * +* Stochastic Gradient Descent SVM Classifier * +\****************************************************************************************/ + +/*! +@brief Stochastic Gradient Descent SVM classifier + +SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, +as presented in @cite bottou2010large. + +The classifier has following parameters: +- model type, +- margin type, +- margin regularization (\f$\lambda\f$), +- initial step size (\f$\gamma_0\f$), +- step decreasing power (\f$c\f$), +- and termination criteria. + +The model type may have one of the following values: \ref SGD and \ref ASGD. + +- \ref SGD is the classic version of SVMSGD classifier: every next step is calculated by the formula + \f[w_{t+1} = w_t - \gamma(t) \frac{dQ_i}{dw} |_{w = w_t}\f] + where + - \f$w_t\f$ is the weights vector for decision function at step \f$t\f$, + - \f$\gamma(t)\f$ is the step size of model parameters at the iteration \f$t\f$, it is decreased on each step by the formula + \f$\gamma(t) = \gamma_0 (1 + \lambda \gamma_0 t) ^ {-c}\f$ + - \f$Q_i\f$ is the target functional from SVM task for sample with number \f$i\f$, this sample is chosen stochastically on each step of the algorithm. + +- \ref ASGD is Average Stochastic Gradient Descent SVM Classifier. ASGD classifier averages weights vector on each step of algorithm by the formula +\f$\widehat{w}_{t+1} = \frac{t}{1+t}\widehat{w}_{t} + \frac{1}{1+t}w_{t+1}\f$ + +The recommended model type is ASGD (following @cite bottou2010large). + +The margin type may have one of the following values: \ref SOFT_MARGIN or \ref HARD_MARGIN. + +- You should use \ref HARD_MARGIN type, if you have linearly separable sets. +- You should use \ref SOFT_MARGIN type, if you have non-linearly separable sets or sets with outliers. +- In the general case (if you know nothing about linear separability of your sets), use SOFT_MARGIN. + +The other parameters may be described as follows: +- Margin regularization parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers + (the less the parameter, the less probability that an outlier will be ignored). + Recommended value for SGD model is 0.0001, for ASGD model is 0.00001. + +- Initial step size parameter is the initial value for the step size \f$\gamma(t)\f$. + You will have to find the best initial step for your problem. + +- Step decreasing power is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. + Recommended value for SGD model is 1, for ASGD model is 0.75. + +- Termination criteria can be TermCriteria::COUNT, TermCriteria::EPS or TermCriteria::COUNT + TermCriteria::EPS. + You will have to find the best termination criteria for your problem. + +Note that the parameters margin regularization, initial step size, and step decreasing power should be positive. + +To use SVMSGD algorithm do as follows: + +- first, create the SVMSGD object. The algoorithm will set optimal parameters by default, but you can set your own parameters via functions setSvmsgdType(), + setMarginType(), setMarginRegularization(), setInitialStepSize(), and setStepDecreasingPower(). + +- then the SVM model can be trained using the train features and the correspondent labels by the method train(). + +- after that, the label of a new feature vector can be predicted using the method predict(). + +@code +// Create empty object +cv::Ptr svmsgd = SVMSGD::create(); + +// Train the Stochastic Gradient Descent SVM +svmsgd->train(trainData); + +// Predict labels for the new samples +svmsgd->predict(samples, responses); +@endcode + +*/ + +class CV_EXPORTS_W SVMSGD : public cv::ml::StatModel +{ +public: + + /** SVMSGD type. + ASGD is often the preferable choice. */ + enum SvmsgdType + { + SGD, //!< Stochastic Gradient Descent + ASGD //!< Average Stochastic Gradient Descent + }; + + /** Margin type.*/ + enum MarginType + { + SOFT_MARGIN, //!< General case, suits to the case of non-linearly separable sets, allows outliers. + HARD_MARGIN //!< More accurate for the case of linearly separable sets. + }; + + /** + * @return the weights of the trained model (decision function f(x) = weights * x + shift). + */ + CV_WRAP virtual Mat getWeights() = 0; + + /** + * @return the shift of the trained model (decision function f(x) = weights * x + shift). + */ + CV_WRAP virtual float getShift() = 0; + + /** @brief Creates empty model. + * Use StatModel::train to train the model. Since %SVMSGD has several parameters, you may want to + * find the best parameters for your problem or use setOptimalParameters() to set some default parameters. + */ + CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized SVMSGD from a file + * + * Use SVMSGD::save to serialize and store an SVMSGD to disk. + * Load the SVMSGD from this file again, by calling this function with the path to the file. + * Optionally specify the node for the file containing the classifier + * + * @param filepath path to serialized SVMSGD + * @param nodeName name of node containing the classifier + */ + CV_WRAP static Ptr load(const String& filepath , const String& nodeName = String()); + + /** @brief Function sets optimal parameters values for chosen SVM SGD model. + * @param svmsgdType is the type of SVMSGD classifier. + * @param marginType is the type of margin constraint. + */ + CV_WRAP virtual void setOptimalParameters(int svmsgdType = SVMSGD::ASGD, int marginType = SVMSGD::SOFT_MARGIN) = 0; + + /** @brief %Algorithm type, one of SVMSGD::SvmsgdType. */ + /** @see setSvmsgdType */ + CV_WRAP virtual int getSvmsgdType() const = 0; + /** @copybrief getSvmsgdType @see getSvmsgdType */ + CV_WRAP virtual void setSvmsgdType(int svmsgdType) = 0; + + /** @brief %Margin type, one of SVMSGD::MarginType. */ + /** @see setMarginType */ + CV_WRAP virtual int getMarginType() const = 0; + /** @copybrief getMarginType @see getMarginType */ + CV_WRAP virtual void setMarginType(int marginType) = 0; + + /** @brief Parameter marginRegularization of a %SVMSGD optimization problem. */ + /** @see setMarginRegularization */ + CV_WRAP virtual float getMarginRegularization() const = 0; + /** @copybrief getMarginRegularization @see getMarginRegularization */ + CV_WRAP virtual void setMarginRegularization(float marginRegularization) = 0; + + /** @brief Parameter initialStepSize of a %SVMSGD optimization problem. */ + /** @see setInitialStepSize */ + CV_WRAP virtual float getInitialStepSize() const = 0; + /** @copybrief getInitialStepSize @see getInitialStepSize */ + CV_WRAP virtual void setInitialStepSize(float InitialStepSize) = 0; + + /** @brief Parameter stepDecreasingPower of a %SVMSGD optimization problem. */ + /** @see setStepDecreasingPower */ + CV_WRAP virtual float getStepDecreasingPower() const = 0; + /** @copybrief getStepDecreasingPower @see getStepDecreasingPower */ + CV_WRAP virtual void setStepDecreasingPower(float stepDecreasingPower) = 0; + + /** @brief Termination criteria of the training algorithm. + You can specify the maximum number of iterations (maxCount) and/or how much the error could + change between the iterations to make the algorithm continue (epsilon).*/ + /** @see setTermCriteria */ + CV_WRAP virtual TermCriteria getTermCriteria() const = 0; + /** @copybrief getTermCriteria @see getTermCriteria */ + CV_WRAP virtual void setTermCriteria(const cv::TermCriteria &val) = 0; +}; + + +/****************************************************************************************\ +* Auxiliary functions declarations * \****************************************************************************************/ /** @brief Generates _sample_ from multivariate normal distribution @@ -1480,20 +1877,96 @@ public: */ CV_EXPORTS void randMVNormal( InputArray mean, InputArray cov, int nsamples, OutputArray samples); -/** @brief Generates sample from gaussian mixture distribution */ -CV_EXPORTS void randGaussMixture( InputArray means, InputArray covs, InputArray weights, - int nsamples, OutputArray samples, OutputArray sampClasses ); - /** @brief Creates test set */ CV_EXPORTS void createConcentricSpheresTestSet( int nsamples, int nfeatures, int nclasses, OutputArray samples, OutputArray responses); +/** @brief Artificial Neural Networks - Multi-Layer Perceptrons. + +@sa @ref ml_intro_ann +*/ +class CV_EXPORTS_W ANN_MLP_ANNEAL : public ANN_MLP +{ +public: + /** @see setAnnealInitialT */ + CV_WRAP virtual double getAnnealInitialT() const = 0; + /** @copybrief getAnnealInitialT @see getAnnealInitialT */ + CV_WRAP virtual void setAnnealInitialT(double val) = 0; + + /** ANNEAL: Update final temperature. + It must be \>=0 and less than initialT. Default value is 0.1.*/ + /** @see setAnnealFinalT */ + CV_WRAP virtual double getAnnealFinalT() const = 0; + /** @copybrief getAnnealFinalT @see getAnnealFinalT */ + CV_WRAP virtual void setAnnealFinalT(double val) = 0; + + /** ANNEAL: Update cooling ratio. + It must be \>0 and less than 1. Default value is 0.95.*/ + /** @see setAnnealCoolingRatio */ + CV_WRAP virtual double getAnnealCoolingRatio() const = 0; + /** @copybrief getAnnealCoolingRatio @see getAnnealCoolingRatio */ + CV_WRAP virtual void setAnnealCoolingRatio(double val) = 0; + + /** ANNEAL: Update iteration per step. + It must be \>0 . Default value is 10.*/ + /** @see setAnnealItePerStep */ + CV_WRAP virtual int getAnnealItePerStep() const = 0; + /** @copybrief getAnnealItePerStep @see getAnnealItePerStep */ + CV_WRAP virtual void setAnnealItePerStep(int val) = 0; + + /** @brief Set/initialize anneal RNG */ + virtual void setAnnealEnergyRNG(const RNG& rng) = 0; +}; + + +/****************************************************************************************\ +* Simulated annealing solver * +\****************************************************************************************/ + +#ifdef CV_DOXYGEN +/** @brief This class declares example interface for system state used in simulated annealing optimization algorithm. + +@note This class is not defined in C++ code and can't be use directly - you need your own implementation with the same methods. +*/ +struct SimulatedAnnealingSolverSystem +{ + /** Give energy value for a state of system.*/ + double energy() const; + /** Function which change the state of system (random perturbation).*/ + void changeState(); + /** Function to reverse to the previous state. Can be called once only after changeState(). */ + void reverseState(); +}; +#endif // CV_DOXYGEN + +/** @brief The class implements simulated annealing for optimization. + +@cite Kirkpatrick83 for details + +@param solverSystem optimization system (see SimulatedAnnealingSolverSystem) +@param initialTemperature initial temperature +@param finalTemperature final temperature +@param coolingRatio temperature step multiplies +@param iterationsPerStep number of iterations per temperature changing step +@param lastTemperature optional output for last used temperature +@param rngEnergy specify custom random numbers generator (cv::theRNG() by default) +*/ +template +int simulatedAnnealingSolver(SimulatedAnnealingSolverSystem& solverSystem, + double initialTemperature, double finalTemperature, double coolingRatio, + size_t iterationsPerStep, + CV_OUT double* lastTemperature = NULL, + cv::RNG& rngEnergy = cv::theRNG() +); + //! @} ml } } +#include + #endif // __cplusplus -#endif // __OPENCV_ML_HPP__ +#endif // OPENCV_ML_HPP /* End of file. */ diff --git a/include/opencv2/ml/ml.inl.hpp b/include/opencv2/ml/ml.inl.hpp new file mode 100644 index 0000000..dc9c783 --- /dev/null +++ b/include/opencv2/ml/ml.inl.hpp @@ -0,0 +1,60 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_ML_INL_HPP +#define OPENCV_ML_INL_HPP + +namespace cv { namespace ml { + +// declared in ml.hpp +template +int simulatedAnnealingSolver(SimulatedAnnealingSolverSystem& solverSystem, + double initialTemperature, double finalTemperature, double coolingRatio, + size_t iterationsPerStep, + CV_OUT double* lastTemperature, + cv::RNG& rngEnergy +) +{ + CV_Assert(finalTemperature > 0); + CV_Assert(initialTemperature > finalTemperature); + CV_Assert(iterationsPerStep > 0); + CV_Assert(coolingRatio < 1.0f); + double Ti = initialTemperature; + double previousEnergy = solverSystem.energy(); + int exchange = 0; + while (Ti > finalTemperature) + { + for (size_t i = 0; i < iterationsPerStep; i++) + { + solverSystem.changeState(); + double newEnergy = solverSystem.energy(); + if (newEnergy < previousEnergy) + { + previousEnergy = newEnergy; + exchange++; + } + else + { + double r = rngEnergy.uniform(0.0, 1.0); + if (r < std::exp(-(newEnergy - previousEnergy) / Ti)) + { + previousEnergy = newEnergy; + exchange++; + } + else + { + solverSystem.reverseState(); + } + } + } + Ti *= coolingRatio; + } + if (lastTemperature) + *lastTemperature = Ti; + return exchange; +} + +}} //namespace + +#endif // OPENCV_ML_INL_HPP diff --git a/include/opencv2/objdetect.hpp b/include/opencv2/objdetect.hpp index bd932e6..cc9c4e1 100644 --- a/include/opencv2/objdetect.hpp +++ b/include/opencv2/objdetect.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_OBJDETECT_HPP__ -#define __OPENCV_OBJDETECT_HPP__ +#ifndef OPENCV_OBJDETECT_HPP +#define OPENCV_OBJDETECT_HPP #include "opencv2/core.hpp" @@ -91,7 +91,7 @@ compensate for the differences in the size of areas. The sums of pixel values ov regions are calculated rapidly using integral images (see below and the integral description). To see the object detector at work, have a look at the facedetect demo: - + The following reference is for the detection part only. There is a separate application called opencv_traincascade that can train a cascade of boosted classifiers from a set of samples. @@ -124,7 +124,7 @@ public: SimilarRects(double _eps) : eps(_eps) {} inline bool operator()(const Rect& r1, const Rect& r2) const { - double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5; + double delta = eps * ((std::min)(r1.width, r2.width) + (std::min)(r1.height, r2.height)) * 0.5; return std::abs(r1.x - r2.x) <= delta && std::abs(r1.y - r2.y) <= delta && std::abs(r1.x + r1.width - r2.x - r2.width) <= delta && @@ -175,7 +175,7 @@ class CV_EXPORTS_W BaseCascadeClassifier : public Algorithm { public: virtual ~BaseCascadeClassifier(); - virtual bool empty() const = 0; + virtual bool empty() const CV_OVERRIDE = 0; virtual bool load( const String& filename ) = 0; virtual void detectMultiScale( InputArray image, CV_OUT std::vector& objects, @@ -215,6 +215,10 @@ public: virtual Ptr getMaskGenerator() = 0; }; +/** @example samples/cpp/facedetect.cpp +This program demonstrates usage of the Cascade classifier class +\image html Cascade_Classifier_Tutorial_Result_Haar.jpg "Sample screenshot" width=321 height=254 +*/ /** @brief Cascade classifier class for object detection. */ class CV_EXPORTS_W CascadeClassifier @@ -255,13 +259,13 @@ public: @param flags Parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade. @param minSize Minimum possible object size. Objects smaller than that are ignored. - @param maxSize Maximum possible object size. Objects larger than that are ignored. + @param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale. The function is parallelized with the TBB library. @note - (Python) A face detection example using cascade classifiers can be found at - opencv_source_code/samples/python2/facedetect.py + opencv_source_code/samples/python/facedetect.py */ CV_WRAP void detectMultiScale( InputArray image, CV_OUT std::vector& objects, @@ -283,7 +287,7 @@ public: @param flags Parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade. @param minSize Minimum possible object size. Objects smaller than that are ignored. - @param maxSize Maximum possible object size. Objects larger than that are ignored. + @param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale. */ CV_WRAP_AS(detectMultiScale2) void detectMultiScale( InputArray image, CV_OUT std::vector& objects, @@ -294,7 +298,21 @@ public: Size maxSize=Size() ); /** @overload - if `outputRejectLevels` is `true` returns `rejectLevels` and `levelWeights` + This function allows you to retrieve the final stage decision certainty of classification. + For this, one needs to set `outputRejectLevels` on true and provide the `rejectLevels` and `levelWeights` parameter. + For each resulting detection, `levelWeights` will then contain the certainty of classification at the final stage. + This value can then be used to separate strong from weaker classifications. + + A code sample on how to use it efficiently can be found below: + @code + Mat img; + vector weights; + vector levels; + vector detections; + CascadeClassifier model("/path/to/your/model.xml"); + model.detectMultiScale(img, detections, levels, weights, 1.1, 3, 0, Size(), Size(), true); + cerr << "Detection " << detections[0] << " with weight " << weights[0] << endl; + @endcode */ CV_WRAP_AS(detectMultiScale3) void detectMultiScale( InputArray image, CV_OUT std::vector& objects, @@ -328,26 +346,60 @@ struct DetectionROI { //! scale(size) of the bounding box double scale; - //! set of requrested locations to be evaluated + //! set of requested locations to be evaluated std::vector locations; //! vector that will contain confidence values for each location std::vector confidences; }; +/**@brief Implementation of HOG (Histogram of Oriented Gradients) descriptor and object detector. + +the HOG descriptor algorithm introduced by Navneet Dalal and Bill Triggs @cite Dalal2005 . + +useful links: + +https://hal.inria.fr/inria-00548512/document/ + +https://en.wikipedia.org/wiki/Histogram_of_oriented_gradients + +https://software.intel.com/en-us/ipp-dev-reference-histogram-of-oriented-gradients-hog-descriptor + +http://www.learnopencv.com/histogram-of-oriented-gradients + +http://www.learnopencv.com/handwritten-digits-classification-an-opencv-c-python-tutorial + + */ struct CV_EXPORTS_W HOGDescriptor { public: - enum { L2Hys = 0 + enum { L2Hys = 0 //!< Default histogramNormType }; - enum { DEFAULT_NLEVELS = 64 + enum { DEFAULT_NLEVELS = 64 //!< Default nlevels value. }; + /**@brief Creates the HOG descriptor and detector with default params. + aqual to HOGDescriptor(Size(64,128), Size(16,16), Size(8,8), Size(8,8), 9, 1 ) + */ CV_WRAP HOGDescriptor() : winSize(64,128), blockSize(16,16), blockStride(8,8), cellSize(8,8), nbins(9), derivAperture(1), winSigma(-1), histogramNormType(HOGDescriptor::L2Hys), L2HysThreshold(0.2), gammaCorrection(true), free_coef(-1.f), nlevels(HOGDescriptor::DEFAULT_NLEVELS), signedGradient(false) {} + /** @overload + @param _winSize sets winSize with given value. + @param _blockSize sets blockSize with given value. + @param _blockStride sets blockStride with given value. + @param _cellSize sets cellSize with given value. + @param _nbins sets nbins with given value. + @param _derivAperture sets derivAperture with given value. + @param _winSigma sets winSigma with given value. + @param _histogramNormType sets histogramNormType with given value. + @param _L2HysThreshold sets L2HysThreshold with given value. + @param _gammaCorrection sets gammaCorrection with given value. + @param _nlevels sets nlevels with given value. + @param _signedGradient sets signedGradient with given value. + */ CV_WRAP HOGDescriptor(Size _winSize, Size _blockSize, Size _blockStride, Size _cellSize, int _nbins, int _derivAperture=1, double _winSigma=-1, int _histogramNormType=HOGDescriptor::L2Hys, @@ -359,102 +411,327 @@ public: gammaCorrection(_gammaCorrection), free_coef(-1.f), nlevels(_nlevels), signedGradient(_signedGradient) {} + /** @overload + @param filename the file name containing HOGDescriptor properties and coefficients of the trained classifier + */ CV_WRAP HOGDescriptor(const String& filename) { load(filename); } + /** @overload + @param d the HOGDescriptor which cloned to create a new one. + */ HOGDescriptor(const HOGDescriptor& d) { d.copyTo(*this); } + /**@brief Default destructor. + */ virtual ~HOGDescriptor() {} + /**@brief Returns the number of coefficients required for the classification. + */ CV_WRAP size_t getDescriptorSize() const; + + /** @brief Checks if detector size equal to descriptor size. + */ CV_WRAP bool checkDetectorSize() const; + + /** @brief Returns winSigma value + */ CV_WRAP double getWinSigma() const; + /**@example samples/cpp/peopledetect.cpp + */ + /**@brief Sets coefficients for the linear SVM classifier. + @param _svmdetector coefficients for the linear SVM classifier. + */ CV_WRAP virtual void setSVMDetector(InputArray _svmdetector); + /** @brief Reads HOGDescriptor parameters from a file node. + @param fn File node + */ virtual bool read(FileNode& fn); + + /** @brief Stores HOGDescriptor parameters in a file storage. + @param fs File storage + @param objname Object name + */ virtual void write(FileStorage& fs, const String& objname) const; + /** @brief loads coefficients for the linear SVM classifier from a file + @param filename Name of the file to read. + @param objname The optional name of the node to read (if empty, the first top-level node will be used). + */ CV_WRAP virtual bool load(const String& filename, const String& objname = String()); + + /** @brief saves coefficients for the linear SVM classifier to a file + @param filename File name + @param objname Object name + */ CV_WRAP virtual void save(const String& filename, const String& objname = String()) const; + + /** @brief clones the HOGDescriptor + @param c cloned HOGDescriptor + */ virtual void copyTo(HOGDescriptor& c) const; + /**@example samples/cpp/train_HOG.cpp + */ + /** @brief Computes HOG descriptors of given image. + @param img Matrix of the type CV_8U containing an image where HOG features will be calculated. + @param descriptors Matrix of the type CV_32F + @param winStride Window stride. It must be a multiple of block stride. + @param padding Padding + @param locations Vector of Point + */ CV_WRAP virtual void compute(InputArray img, CV_OUT std::vector& descriptors, Size winStride = Size(), Size padding = Size(), const std::vector& locations = std::vector()) const; - //! with found weights output + /** @brief Performs object detection without a multi-scale window. + @param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected. + @param foundLocations Vector of point where each point contains left-top corner point of detected object boundaries. + @param weights Vector that will contain confidence values for each detected object. + @param hitThreshold Threshold for the distance between features and SVM classifying plane. + Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient). + But if the free coefficient is omitted (which is allowed), you can specify it manually here. + @param winStride Window stride. It must be a multiple of block stride. + @param padding Padding + @param searchLocations Vector of Point includes set of requested locations to be evaluated. + */ CV_WRAP virtual void detect(const Mat& img, CV_OUT std::vector& foundLocations, CV_OUT std::vector& weights, double hitThreshold = 0, Size winStride = Size(), Size padding = Size(), const std::vector& searchLocations = std::vector()) const; - //! without found weights output + + /** @brief Performs object detection without a multi-scale window. + @param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected. + @param foundLocations Vector of point where each point contains left-top corner point of detected object boundaries. + @param hitThreshold Threshold for the distance between features and SVM classifying plane. + Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient). + But if the free coefficient is omitted (which is allowed), you can specify it manually here. + @param winStride Window stride. It must be a multiple of block stride. + @param padding Padding + @param searchLocations Vector of Point includes locations to search. + */ virtual void detect(const Mat& img, CV_OUT std::vector& foundLocations, double hitThreshold = 0, Size winStride = Size(), Size padding = Size(), const std::vector& searchLocations=std::vector()) const; - //! with result weights output + /** @brief Detects objects of different sizes in the input image. The detected objects are returned as a list + of rectangles. + @param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected. + @param foundLocations Vector of rectangles where each rectangle contains the detected object. + @param foundWeights Vector that will contain confidence values for each detected object. + @param hitThreshold Threshold for the distance between features and SVM classifying plane. + Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient). + But if the free coefficient is omitted (which is allowed), you can specify it manually here. + @param winStride Window stride. It must be a multiple of block stride. + @param padding Padding + @param scale Coefficient of the detection window increase. + @param finalThreshold Final threshold + @param useMeanshiftGrouping indicates grouping algorithm + */ CV_WRAP virtual void detectMultiScale(InputArray img, CV_OUT std::vector& foundLocations, CV_OUT std::vector& foundWeights, double hitThreshold = 0, Size winStride = Size(), Size padding = Size(), double scale = 1.05, double finalThreshold = 2.0,bool useMeanshiftGrouping = false) const; - //! without found weights output + + /** @brief Detects objects of different sizes in the input image. The detected objects are returned as a list + of rectangles. + @param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected. + @param foundLocations Vector of rectangles where each rectangle contains the detected object. + @param hitThreshold Threshold for the distance between features and SVM classifying plane. + Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient). + But if the free coefficient is omitted (which is allowed), you can specify it manually here. + @param winStride Window stride. It must be a multiple of block stride. + @param padding Padding + @param scale Coefficient of the detection window increase. + @param finalThreshold Final threshold + @param useMeanshiftGrouping indicates grouping algorithm + */ virtual void detectMultiScale(InputArray img, CV_OUT std::vector& foundLocations, double hitThreshold = 0, Size winStride = Size(), Size padding = Size(), double scale = 1.05, double finalThreshold = 2.0, bool useMeanshiftGrouping = false) const; + /** @brief Computes gradients and quantized gradient orientations. + @param img Matrix contains the image to be computed + @param grad Matrix of type CV_32FC2 contains computed gradients + @param angleOfs Matrix of type CV_8UC2 contains quantized gradient orientations + @param paddingTL Padding from top-left + @param paddingBR Padding from bottom-right + */ CV_WRAP virtual void computeGradient(const Mat& img, CV_OUT Mat& grad, CV_OUT Mat& angleOfs, Size paddingTL = Size(), Size paddingBR = Size()) const; + /** @brief Returns coefficients of the classifier trained for people detection (for 64x128 windows). + */ CV_WRAP static std::vector getDefaultPeopleDetector(); + + /**@example samples/tapi/hog.cpp + */ + /** @brief Returns coefficients of the classifier trained for people detection (for 48x96 windows). + */ CV_WRAP static std::vector getDaimlerPeopleDetector(); + //! Detection window size. Align to block size and block stride. Default value is Size(64,128). CV_PROP Size winSize; + + //! Block size in pixels. Align to cell size. Default value is Size(16,16). CV_PROP Size blockSize; + + //! Block stride. It must be a multiple of cell size. Default value is Size(8,8). CV_PROP Size blockStride; + + //! Cell size. Default value is Size(8,8). CV_PROP Size cellSize; + + //! Number of bins used in the calculation of histogram of gradients. Default value is 9. CV_PROP int nbins; + + //! not documented CV_PROP int derivAperture; + + //! Gaussian smoothing window parameter. CV_PROP double winSigma; + + //! histogramNormType CV_PROP int histogramNormType; + + //! L2-Hys normalization method shrinkage. CV_PROP double L2HysThreshold; + + //! Flag to specify whether the gamma correction preprocessing is required or not. CV_PROP bool gammaCorrection; + + //! coefficients for the linear SVM classifier. CV_PROP std::vector svmDetector; + + //! coefficients for the linear SVM classifier used when OpenCL is enabled UMat oclSvmDetector; + + //! not documented float free_coef; + + //! Maximum number of detection window increases. Default value is 64 CV_PROP int nlevels; + + //! Indicates signed gradient will be used or not CV_PROP bool signedGradient; - - //! evaluate specified ROI and return confidence value for each location + /** @brief evaluate specified ROI and return confidence value for each location + @param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected. + @param locations Vector of Point + @param foundLocations Vector of Point where each Point is detected object's top-left point. + @param confidences confidences + @param hitThreshold Threshold for the distance between features and SVM classifying plane. Usually + it is 0 and should be specified in the detector coefficients (as the last free coefficient). But if + the free coefficient is omitted (which is allowed), you can specify it manually here + @param winStride winStride + @param padding padding + */ virtual void detectROI(const cv::Mat& img, const std::vector &locations, CV_OUT std::vector& foundLocations, CV_OUT std::vector& confidences, double hitThreshold = 0, cv::Size winStride = Size(), cv::Size padding = Size()) const; - //! evaluate specified ROI and return confidence value for each location in multiple scales + /** @brief evaluate specified ROI and return confidence value for each location in multiple scales + @param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected. + @param foundLocations Vector of rectangles where each rectangle contains the detected object. + @param locations Vector of DetectionROI + @param hitThreshold Threshold for the distance between features and SVM classifying plane. Usually it is 0 and should be specified + in the detector coefficients (as the last free coefficient). But if the free coefficient is omitted (which is allowed), you can specify it manually here. + @param groupThreshold Minimum possible number of rectangles minus 1. The threshold is used in a group of rectangles to retain it. + */ virtual void detectMultiScaleROI(const cv::Mat& img, - CV_OUT std::vector& foundLocations, - std::vector& locations, - double hitThreshold = 0, - int groupThreshold = 0) const; + CV_OUT std::vector& foundLocations, + std::vector& locations, + double hitThreshold = 0, + int groupThreshold = 0) const; - //! read/parse Dalal's alt model file + /** @brief read/parse Dalal's alt model file + @param modelfile Path of Dalal's alt model file. + */ void readALTModel(String modelfile); + + /** @brief Groups the object candidate rectangles. + @param rectList Input/output vector of rectangles. Output vector includes retained and grouped rectangles. (The Python list is not modified in place.) + @param weights Input/output vector of weights of rectangles. Output vector includes weights of retained and grouped rectangles. (The Python list is not modified in place.) + @param groupThreshold Minimum possible number of rectangles minus 1. The threshold is used in a group of rectangles to retain it. + @param eps Relative difference between sides of the rectangles to merge them into a group. + */ void groupRectangles(std::vector& rectList, std::vector& weights, int groupThreshold, double eps) const; }; -//! @} objdetect +class CV_EXPORTS_W QRCodeDetector +{ +public: + CV_WRAP QRCodeDetector(); + ~QRCodeDetector(); + /** @brief sets the epsilon used during the horizontal scan of QR code stop marker detection. + @param epsX Epsilon neighborhood, which allows you to determine the horizontal pattern + of the scheme 1:1:3:1:1 according to QR code standard. + */ + CV_WRAP void setEpsX(double epsX); + /** @brief sets the epsilon used during the vertical scan of QR code stop marker detection. + @param epsY Epsilon neighborhood, which allows you to determine the vertical pattern + of the scheme 1:1:3:1:1 according to QR code standard. + */ + CV_WRAP void setEpsY(double epsY); + + /** @brief Detects QR code in image and returns the quadrangle containing the code. + @param img grayscale or color (BGR) image containing (or not) QR code. + @param points Output vector of vertices of the minimum-area quadrangle containing the code. + */ + CV_WRAP bool detect(InputArray img, OutputArray points) const; + + /** @brief Decodes QR code in image once it's found by the detect() method. + Returns UTF8-encoded output string or empty string if the code cannot be decoded. + + @param img grayscale or color (BGR) image containing QR code. + @param points Quadrangle vertices found by detect() method (or some other algorithm). + @param straight_qrcode The optional output image containing rectified and binarized QR code + */ + CV_WRAP cv::String decode(InputArray img, InputArray points, OutputArray straight_qrcode = noArray()); + + /** @brief Both detects and decodes QR code + + @param img grayscale or color (BGR) image containing QR code. + @param points opiotnal output array of vertices of the found QR code quadrangle. Will be empty if not found. + @param straight_qrcode The optional output image containing rectified and binarized QR code + */ + CV_WRAP cv::String detectAndDecode(InputArray img, OutputArray points=noArray(), + OutputArray straight_qrcode = noArray()); +protected: + struct Impl; + Ptr p; +}; + +/** @brief Detect QR code in image and return minimum area of quadrangle that describes QR code. + @param in Matrix of the type CV_8UC1 containing an image where QR code are detected. + @param points Output vector of vertices of a quadrangle of minimal area that describes QR code. + @param eps_x Epsilon neighborhood, which allows you to determine the horizontal pattern of the scheme 1:1:3:1:1 according to QR code standard. + @param eps_y Epsilon neighborhood, which allows you to determine the vertical pattern of the scheme 1:1:3:1:1 according to QR code standard. + */ +CV_EXPORTS bool detectQRCode(InputArray in, std::vector &points, double eps_x = 0.2, double eps_y = 0.1); + +/** @brief Decode QR code in image and return text that is encrypted in QR code. + @param in Matrix of the type CV_8UC1 containing an image where QR code are detected. + @param points Input vector of vertices of a quadrangle of minimal area that describes QR code. + @param decoded_info String information that is encrypted in QR code. + @param straight_qrcode Matrix of the type CV_8UC1 containing an binary straight QR code. + */ +CV_EXPORTS bool decodeQRCode(InputArray in, InputArray points, std::string &decoded_info, OutputArray straight_qrcode = noArray()); + +//! @} objdetect } #include "opencv2/objdetect/detection_based_tracker.hpp" diff --git a/include/opencv2/objdetect/detection_based_tracker.hpp b/include/opencv2/objdetect/detection_based_tracker.hpp index 54117fd..07dd587 100644 --- a/include/opencv2/objdetect/detection_based_tracker.hpp +++ b/include/opencv2/objdetect/detection_based_tracker.hpp @@ -41,11 +41,14 @@ // //M*/ -#ifndef __OPENCV_OBJDETECT_DBT_HPP__ -#define __OPENCV_OBJDETECT_DBT_HPP__ +#ifndef OPENCV_OBJDETECT_DBT_HPP +#define OPENCV_OBJDETECT_DBT_HPP +#include + +// After this condition removal update blacklist for bindings: modules/python/common.cmake #if defined(__linux__) || defined(LINUX) || defined(__APPLE__) || defined(__ANDROID__) || \ - (defined(__cplusplus) && __cplusplus > 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1700) + defined(CV_CXX11) #include @@ -58,7 +61,7 @@ namespace cv class CV_EXPORTS DetectionBasedTracker { public: - struct Parameters + struct CV_EXPORTS Parameters { int maxTrackLifetime; int minDetectionPeriod; //the minimal time between run of the big object detector (on the whole frame) in ms (1000 mean 1 sec), default=0 diff --git a/include/opencv2/objdetect/objdetect_c.h b/include/opencv2/objdetect/objdetect_c.h index 632a438..67dc2f4 100644 --- a/include/opencv2/objdetect/objdetect_c.h +++ b/include/opencv2/objdetect/objdetect_c.h @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_OBJDETECT_C_H__ -#define __OPENCV_OBJDETECT_C_H__ +#ifndef OPENCV_OBJDETECT_C_H +#define OPENCV_OBJDETECT_C_H #include "opencv2/core/core_c.h" @@ -69,6 +69,7 @@ extern "C" { (((const CvHaarClassifierCascade*)(haar))->flags & CV_MAGIC_MASK)==CV_HAAR_MAGIC_VAL) #define CV_HAAR_FEATURE_MAX 3 +#define CV_HAAR_STAGE_MAX 1000 typedef struct CvHaarFeature { @@ -162,4 +163,4 @@ CV_EXPORTS CvSeq* cvHaarDetectObjectsForROC( const CvArr* image, #endif -#endif /* __OPENCV_OBJDETECT_C_H__ */ +#endif /* OPENCV_OBJDETECT_C_H */ diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp index fd9ca58..4048158 100644 --- a/include/opencv2/opencv.hpp +++ b/include/opencv2/opencv.hpp @@ -40,19 +40,100 @@ // //M*/ -#ifndef __OPENCV_ALL_HPP__ -#define __OPENCV_ALL_HPP__ +#ifndef OPENCV_ALL_HPP +#define OPENCV_ALL_HPP +// File that defines what modules where included during the build of OpenCV +// These are purely the defines of the correct HAVE_OPENCV_modulename values +#include "opencv2/opencv_modules.hpp" + +// Then the list of defines is checked to include the correct headers +// Core library is always included --> without no OpenCV functionality available #include "opencv2/core.hpp" -#include "opencv2/imgproc.hpp" -#include "opencv2/photo.hpp" -#include "opencv2/video.hpp" -#include "opencv2/features2d.hpp" -#include "opencv2/objdetect.hpp" + +// Then the optional modules are checked +#ifdef HAVE_OPENCV_CALIB3D #include "opencv2/calib3d.hpp" -#include "opencv2/imgcodecs.hpp" -#include "opencv2/videoio.hpp" +#endif +#ifdef HAVE_OPENCV_FEATURES2D +#include "opencv2/features2d.hpp" +#endif +#ifdef HAVE_OPENCV_DNN +#include "opencv2/dnn.hpp" +#endif +#ifdef HAVE_OPENCV_FLANN +#include "opencv2/flann.hpp" +#endif +#ifdef HAVE_OPENCV_HIGHGUI #include "opencv2/highgui.hpp" +#endif +#ifdef HAVE_OPENCV_IMGCODECS +#include "opencv2/imgcodecs.hpp" +#endif +#ifdef HAVE_OPENCV_IMGPROC +#include "opencv2/imgproc.hpp" +#endif +#ifdef HAVE_OPENCV_ML #include "opencv2/ml.hpp" +#endif +#ifdef HAVE_OPENCV_OBJDETECT +#include "opencv2/objdetect.hpp" +#endif +#ifdef HAVE_OPENCV_PHOTO +#include "opencv2/photo.hpp" +#endif +#ifdef HAVE_OPENCV_SHAPE +#include "opencv2/shape.hpp" +#endif +#ifdef HAVE_OPENCV_STITCHING +#include "opencv2/stitching.hpp" +#endif +#ifdef HAVE_OPENCV_SUPERRES +#include "opencv2/superres.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEO +#include "opencv2/video.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEOIO +#include "opencv2/videoio.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEOSTAB +#include "opencv2/videostab.hpp" +#endif +#ifdef HAVE_OPENCV_VIZ +#include "opencv2/viz.hpp" +#endif + +// Finally CUDA specific entries are checked and added +#ifdef HAVE_OPENCV_CUDAARITHM +#include "opencv2/cudaarithm.hpp" +#endif +#ifdef HAVE_OPENCV_CUDABGSEGM +#include "opencv2/cudabgsegm.hpp" +#endif +#ifdef HAVE_OPENCV_CUDACODEC +#include "opencv2/cudacodec.hpp" +#endif +#ifdef HAVE_OPENCV_CUDAFEATURES2D +#include "opencv2/cudafeatures2d.hpp" +#endif +#ifdef HAVE_OPENCV_CUDAFILTERS +#include "opencv2/cudafilters.hpp" +#endif +#ifdef HAVE_OPENCV_CUDAIMGPROC +#include "opencv2/cudaimgproc.hpp" +#endif +#ifdef HAVE_OPENCV_CUDAOBJDETECT +#include "opencv2/cudaobjdetect.hpp" +#endif +#ifdef HAVE_OPENCV_CUDAOPTFLOW +#include "opencv2/cudaoptflow.hpp" +#endif +#ifdef HAVE_OPENCV_CUDASTEREO +#include "opencv2/cudastereo.hpp" +#endif +#ifdef HAVE_OPENCV_CUDAWARPING +#include "opencv2/cudawarping.hpp" +#endif #endif diff --git a/include/opencv2/opencv_modules.hpp b/include/opencv2/opencv_modules.hpp index ebca30a..d0f2dc5 100644 --- a/include/opencv2/opencv_modules.hpp +++ b/include/opencv2/opencv_modules.hpp @@ -6,11 +6,15 @@ * */ +// This definition means that OpenCV is built with enabled non-free code. +// For example, patented algorithms for non-profit/non-commercial use only. +/* #undef OPENCV_ENABLE_NONFREE */ + #define HAVE_OPENCV_CALIB3D #define HAVE_OPENCV_CORE +#define HAVE_OPENCV_DNN #define HAVE_OPENCV_FEATURES2D #define HAVE_OPENCV_FLANN -#define HAVE_OPENCV_HAL #define HAVE_OPENCV_HIGHGUI #define HAVE_OPENCV_IMGCODECS #define HAVE_OPENCV_IMGPROC @@ -23,5 +27,6 @@ #define HAVE_OPENCV_VIDEO #define HAVE_OPENCV_VIDEOIO #define HAVE_OPENCV_VIDEOSTAB +#define HAVE_OPENCV_WORLD diff --git a/include/opencv2/photo.hpp b/include/opencv2/photo.hpp index 3d96912..7ceb97e 100644 --- a/include/opencv2/photo.hpp +++ b/include/opencv2/photo.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_PHOTO_HPP__ -#define __OPENCV_PHOTO_HPP__ +#ifndef OPENCV_PHOTO_HPP +#define OPENCV_PHOTO_HPP #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" @@ -89,7 +89,7 @@ enum /** @brief Restores the selected region in an image using the region neighborhood. -@param src Input 8-bit 1-channel or 3-channel image. +@param src Input 8-bit, 16-bit unsigned or 32-bit float 1-channel or 8-bit 3-channel image. @param inpaintMask Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted. @param dst Output image with the same size and type as src . @@ -107,7 +107,7 @@ objects from still images or video. See @@ -216,7 +216,7 @@ CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputA int imgToDenoiseIndex, int temporalWindowSize, float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); -/** @brief Modification of fastNlMeansDenoising function for images sequence where consequtive images have been +/** @brief Modification of fastNlMeansDenoising function for images sequence where consecutive images have been captured in small period of time. For example video. This version of the function is for grayscale images or for manual manipulation with colorspaces. For more details see @@ -376,43 +376,6 @@ results, default value is 0.85. */ CV_EXPORTS_W Ptr createTonemapDrago(float gamma = 1.0f, float saturation = 1.0f, float bias = 0.85f); -/** @brief This algorithm decomposes image into two layers: base layer and detail layer using bilateral filter -and compresses contrast of the base layer thus preserving all the details. - -This implementation uses regular bilateral filter from opencv. - -Saturation enhancement is possible as in ocvTonemapDrago. - -For more information see @cite DD02 . - */ -class CV_EXPORTS_W TonemapDurand : public Tonemap -{ -public: - - CV_WRAP virtual float getSaturation() const = 0; - CV_WRAP virtual void setSaturation(float saturation) = 0; - - CV_WRAP virtual float getContrast() const = 0; - CV_WRAP virtual void setContrast(float contrast) = 0; - - CV_WRAP virtual float getSigmaSpace() const = 0; - CV_WRAP virtual void setSigmaSpace(float sigma_space) = 0; - - CV_WRAP virtual float getSigmaColor() const = 0; - CV_WRAP virtual void setSigmaColor(float sigma_color) = 0; -}; - -/** @brief Creates TonemapDurand object - -@param gamma gamma value for gamma correction. See createTonemap -@param contrast resulting contrast on logarithmic scale, i. e. log(max / min), where max and min -are maximum and minimum luminance values of the resulting image. -@param saturation saturation enhancement value. See createTonemapDrago -@param sigma_space bilateral filter sigma in color space -@param sigma_color bilateral filter sigma in coordinate space - */ -CV_EXPORTS_W Ptr -createTonemapDurand(float gamma = 1.0f, float contrast = 4.0f, float saturation = 1.0f, float sigma_space = 2.0f, float sigma_color = 2.0f); /** @brief This is a global tonemapping operator that models human visual system. @@ -502,7 +465,7 @@ class CV_EXPORTS_W AlignMTB : public AlignExposures { public: CV_WRAP virtual void process(InputArrayOfArrays src, std::vector& dst, - InputArray times, InputArray response) = 0; + InputArray times, InputArray response) CV_OVERRIDE = 0; /** @brief Short version of process, that doesn't take extra arguments. @@ -591,7 +554,7 @@ public: @param samples number of pixel locations to use @param lambda smoothness term weight. Greater values produce smoother results, but can alter the response. -@param random if true sample pixel locations are chosen at random, otherwise the form a +@param random if true sample pixel locations are chosen at random, otherwise they form a rectangular grid. */ CV_EXPORTS_W Ptr createCalibrateDebevec(int samples = 70, float lambda = 10.0f, bool random = false); @@ -646,7 +609,7 @@ class CV_EXPORTS_W MergeDebevec : public MergeExposures { public: CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, - InputArray times, InputArray response) = 0; + InputArray times, InputArray response) CV_OVERRIDE = 0; CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, InputArray times) = 0; }; @@ -669,7 +632,7 @@ class CV_EXPORTS_W MergeMertens : public MergeExposures { public: CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, - InputArray times, InputArray response) = 0; + InputArray times, InputArray response) CV_OVERRIDE = 0; /** @brief Short version of process, that doesn't take extra arguments. @param src vector of input images @@ -705,7 +668,7 @@ class CV_EXPORTS_W MergeRobertson : public MergeExposures { public: CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, - InputArray times, InputArray response) = 0; + InputArray times, InputArray response) CV_OVERRIDE = 0; CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, InputArray times) = 0; }; @@ -730,6 +693,9 @@ CV_EXPORTS_W void decolor( InputArray src, OutputArray grayscale, OutputArray co //! @addtogroup photo_clone //! @{ +/** @example samples/cpp/tutorial_code/photo/seamless_cloning/cloning_demo.cpp +An example using seamlessClone function +*/ /** @brief Image editing tasks concern either global changes (color/intensity corrections, filters, deformations) or local changes concerned to a selection. Here we are interested in achieving local changes, ones that are restricted to a region manually selected (ROI), in a seamless and effortless @@ -748,7 +714,7 @@ complex outlines into a new background consuming and often leaves an undesirable halo. Seamless cloning, even averaged with the original image, is not effective. Mixed seamless cloning based on a loose selection proves effective. -- **FEATURE_EXCHANGE** Feature exchange allows the user to easily replace certain features of +- **MONOCHROME_TRANSFER** Monochrome transfer allows the user to easily replace certain features of one object by alternative features. */ CV_EXPORTS_W void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, @@ -833,6 +799,9 @@ CV_EXPORTS_W void edgePreservingFilter(InputArray src, OutputArray dst, int flag CV_EXPORTS_W void detailEnhance(InputArray src, OutputArray dst, float sigma_s = 10, float sigma_r = 0.15f); +/** @example samples/cpp/tutorial_code/photo/non_photorealistic_rendering/npr_demo.cpp +An example using non-photorealistic line drawing functions +*/ /** @brief Pencil-like non-photorealistic line drawing @param src Input 8-bit 3-channel image. diff --git a/include/opencv2/photo/cuda.hpp b/include/opencv2/photo/cuda.hpp index aeac1fa..a2f3816 100644 --- a/include/opencv2/photo/cuda.hpp +++ b/include/opencv2/photo/cuda.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_PHOTO_CUDA_HPP__ -#define __OPENCV_PHOTO_CUDA_HPP__ +#ifndef OPENCV_PHOTO_CUDA_HPP +#define OPENCV_PHOTO_CUDA_HPP #include "opencv2/core/cuda.hpp" @@ -129,4 +129,4 @@ CV_EXPORTS void fastNlMeansDenoisingColored(InputArray src, OutputArray dst, }} // namespace cv { namespace cuda { -#endif /* __OPENCV_PHOTO_CUDA_HPP__ */ +#endif /* OPENCV_PHOTO_CUDA_HPP */ diff --git a/include/opencv2/photo/photo_c.h b/include/opencv2/photo/photo_c.h index 07ca9b3..cd623c1 100644 --- a/include/opencv2/photo/photo_c.h +++ b/include/opencv2/photo/photo_c.h @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_PHOTO_C_H__ -#define __OPENCV_PHOTO_C_H__ +#ifndef OPENCV_PHOTO_C_H +#define OPENCV_PHOTO_C_H #include "opencv2/core/core_c.h" @@ -71,4 +71,4 @@ CVAPI(void) cvInpaint( const CvArr* src, const CvArr* inpaint_mask, } //extern "C" #endif -#endif //__OPENCV_PHOTO_C_H__ +#endif //OPENCV_PHOTO_C_H diff --git a/include/opencv2/shape.hpp b/include/opencv2/shape.hpp index 6999476..f302b6b 100644 --- a/include/opencv2/shape.hpp +++ b/include/opencv2/shape.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_SHAPE_HPP__ -#define __OPENCV_SHAPE_HPP__ +#ifndef OPENCV_SHAPE_HPP +#define OPENCV_SHAPE_HPP #include "opencv2/shape/emdL1.hpp" #include "opencv2/shape/shape_transformer.hpp" diff --git a/include/opencv2/shape/emdL1.hpp b/include/opencv2/shape/emdL1.hpp index 1dfa758..a15d68c 100644 --- a/include/opencv2/shape/emdL1.hpp +++ b/include/opencv2/shape/emdL1.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_EMD_L1_HPP__ -#define __OPENCV_EMD_L1_HPP__ +#ifndef OPENCV_EMD_L1_HPP +#define OPENCV_EMD_L1_HPP #include "opencv2/core.hpp" diff --git a/include/opencv2/shape/hist_cost.hpp b/include/opencv2/shape/hist_cost.hpp index 15c0a87..21d0d68 100644 --- a/include/opencv2/shape/hist_cost.hpp +++ b/include/opencv2/shape/hist_cost.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_HIST_COST_HPP__ -#define __OPENCV_HIST_COST_HPP__ +#ifndef OPENCV_HIST_COST_HPP +#define OPENCV_HIST_COST_HPP #include "opencv2/imgproc.hpp" diff --git a/include/opencv2/shape/shape_distance.hpp b/include/opencv2/shape/shape_distance.hpp index 4b0c3b5..725b56a 100644 --- a/include/opencv2/shape/shape_distance.hpp +++ b/include/opencv2/shape/shape_distance.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_SHAPE_SHAPE_DISTANCE_HPP__ -#define __OPENCV_SHAPE_SHAPE_DISTANCE_HPP__ +#ifndef OPENCV_SHAPE_SHAPE_DISTANCE_HPP +#define OPENCV_SHAPE_SHAPE_DISTANCE_HPP #include "opencv2/core.hpp" #include "opencv2/shape/hist_cost.hpp" #include "opencv2/shape/shape_transformer.hpp" @@ -53,6 +53,9 @@ namespace cv //! @addtogroup shape //! @{ +/** @example samples/cpp/shape_example.cpp +An example using shape distance algorithm +*/ /** @brief Abstract base class for shape distance algorithms. */ class CV_EXPORTS_W ShapeDistanceExtractor : public Algorithm diff --git a/include/opencv2/shape/shape_transformer.hpp b/include/opencv2/shape/shape_transformer.hpp index 2180613..3c3ce20 100644 --- a/include/opencv2/shape/shape_transformer.hpp +++ b/include/opencv2/shape/shape_transformer.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_SHAPE_SHAPE_TRANSFORM_HPP__ -#define __OPENCV_SHAPE_SHAPE_TRANSFORM_HPP__ +#ifndef OPENCV_SHAPE_SHAPE_TRANSFORM_HPP +#define OPENCV_SHAPE_SHAPE_TRANSFORM_HPP #include #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" @@ -92,7 +92,7 @@ public: /** @brief Definition of the transformation -ocupied in the paper "Principal Warps: Thin-Plate Splines and Decomposition of Deformations", by +occupied in the paper "Principal Warps: Thin-Plate Splines and Decomposition of Deformations", by F.L. Bookstein (PAMI 1989). : */ class CV_EXPORTS_W ThinPlateSplineShapeTransformer : public ShapeTransformer diff --git a/include/opencv2/stitching.hpp b/include/opencv2/stitching.hpp index 96cde14..07e1b5f 100644 --- a/include/opencv2/stitching.hpp +++ b/include/opencv2/stitching.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_STITCHER_HPP__ -#define __OPENCV_STITCHING_STITCHER_HPP__ +#ifndef OPENCV_STITCHING_STITCHER_HPP +#define OPENCV_STITCHING_STITCHER_HPP #include "opencv2/core.hpp" #include "opencv2/features2d.hpp" @@ -53,6 +53,12 @@ #include "opencv2/stitching/detail/blenders.hpp" #include "opencv2/stitching/detail/camera.hpp" + +#if defined(Status) +# warning Detected X11 'Status' macro definition, it can cause build conflicts. Please, include this header before any X11 headers. +#endif + + /** @defgroup stitching Images stitching @@ -63,7 +69,29 @@ one can combine and use them separately. The implemented stitching pipeline is very similar to the one proposed in @cite BL07 . -![image](StitchingPipeline.jpg) +![stitching pipeline](StitchingPipeline.jpg) + +Camera models +------------- + +There are currently 2 camera models implemented in stitching pipeline. + +- _Homography model_ expecting perspective transformations between images + implemented in @ref cv::detail::BestOf2NearestMatcher cv::detail::HomographyBasedEstimator + cv::detail::BundleAdjusterReproj cv::detail::BundleAdjusterRay +- _Affine model_ expecting affine transformation with 6 DOF or 4 DOF implemented in + @ref cv::detail::AffineBestOf2NearestMatcher cv::detail::AffineBasedEstimator + cv::detail::BundleAdjusterAffine cv::detail::BundleAdjusterAffinePartial cv::AffineWarper + +Homography model is useful for creating photo panoramas captured by camera, +while affine-based model can be used to stitch scans and object captured by +specialized devices. Use @ref cv::Stitcher::create to get preconfigured pipeline for one +of those models. + +@note +Certain detailed settings of @ref cv::Stitcher might not make sense. Especially +you should not mix classes implementing affine model and classes implementing +Homography model, as they work with different transformations. @{ @defgroup stitching_match Features Finding and Images Matching @@ -81,6 +109,14 @@ namespace cv { //! @addtogroup stitching //! @{ +/** @example samples/cpp/stitching.cpp +A basic example on image stitching +*/ + +/** @example samples/cpp/stitching_detailed.cpp +A detailed example on image stitching +*/ + /** @brief High level image stitcher. It's possible to use this class without being aware of the entire stitching pipeline. However, to @@ -104,6 +140,22 @@ public: ERR_HOMOGRAPHY_EST_FAIL = 2, ERR_CAMERA_PARAMS_ADJUST_FAIL = 3 }; + enum Mode + { + /** Mode for creating photo panoramas. Expects images under perspective + transformation and projects resulting pano to sphere. + + @sa detail::BestOf2NearestMatcher SphericalWarper + */ + PANORAMA = 0, + /** Mode for composing scans. Expects images under affine transformation does + not compensate exposure by default. + + @sa detail::AffineBestOf2NearestMatcher AffineWarper + */ + SCANS = 1, + + }; // Stitcher() {} /** @brief Creates a stitcher with the default parameters. @@ -112,6 +164,15 @@ public: @return Stitcher class instance. */ static Stitcher createDefault(bool try_use_gpu = false); + /** @brief Creates a Stitcher configured in one of the stitching modes. + + @param mode Scenario for stitcher operation. This is usually determined by source of images + to stitch and their transformation. Default parameters will be chosen for operation in given + scenario. + @param try_use_gpu Flag indicating whether GPU should be used whenever it's possible. + @return Stitcher class instance. + */ + static Ptr create(Mode mode = PANORAMA, bool try_use_gpu = false); CV_WRAP double registrationResol() const { return registr_resol_; } CV_WRAP void setRegistrationResol(double resol_mpx) { registr_resol_ = resol_mpx; } @@ -153,6 +214,13 @@ public: void setBundleAdjuster(Ptr bundle_adjuster) { bundle_adjuster_ = bundle_adjuster; } + /* TODO OpenCV ABI 4.x + Ptr estimator() { return estimator_; } + const Ptr estimator() const { return estimator_; } + void setEstimator(Ptr estimator) + { estimator_ = estimator; } + */ + Ptr warper() { return warper_; } const Ptr warper() const { return warper_; } void setWarper(Ptr creator) { warper_ = creator; } @@ -227,6 +295,9 @@ private: Ptr features_matcher_; cv::UMat matching_mask_; Ptr bundle_adjuster_; + /* TODO OpenCV ABI 4.x + Ptr estimator_; + */ bool do_wave_correct_; detail::WaveCorrectKind wave_correct_kind_; Ptr warper_; @@ -249,9 +320,10 @@ private: }; CV_EXPORTS_W Ptr createStitcher(bool try_use_gpu = false); +CV_EXPORTS_W Ptr createStitcherScans(bool try_use_gpu = false); //! @} stitching } // namespace cv -#endif // __OPENCV_STITCHING_STITCHER_HPP__ +#endif // OPENCV_STITCHING_STITCHER_HPP diff --git a/include/opencv2/stitching/detail/autocalib.hpp b/include/opencv2/stitching/detail/autocalib.hpp index ccc0aa1..19705e2 100644 --- a/include/opencv2/stitching/detail/autocalib.hpp +++ b/include/opencv2/stitching/detail/autocalib.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_AUTOCALIB_HPP__ -#define __OPENCV_STITCHING_AUTOCALIB_HPP__ +#ifndef OPENCV_STITCHING_AUTOCALIB_HPP +#define OPENCV_STITCHING_AUTOCALIB_HPP #include "opencv2/core.hpp" #include "matchers.hpp" @@ -83,4 +83,4 @@ bool CV_EXPORTS calibrateRotatingCamera(const std::vector &Hs, Mat &K); } // namespace detail } // namespace cv -#endif // __OPENCV_STITCHING_AUTOCALIB_HPP__ +#endif // OPENCV_STITCHING_AUTOCALIB_HPP diff --git a/include/opencv2/stitching/detail/blenders.hpp b/include/opencv2/stitching/detail/blenders.hpp index 0e60725..542f1e4 100644 --- a/include/opencv2/stitching/detail/blenders.hpp +++ b/include/opencv2/stitching/detail/blenders.hpp @@ -40,10 +40,15 @@ // //M*/ -#ifndef __OPENCV_STITCHING_BLENDERS_HPP__ -#define __OPENCV_STITCHING_BLENDERS_HPP__ +#ifndef OPENCV_STITCHING_BLENDERS_HPP +#define OPENCV_STITCHING_BLENDERS_HPP + +#if defined(NO) +# warning Detected Apple 'NO' macro definition, it can cause build conflicts. Please, include this header before any Apple headers. +#endif #include "opencv2/core.hpp" +#include "opencv2/core/cuda.hpp" namespace cv { namespace detail { @@ -100,9 +105,9 @@ public: float sharpness() const { return sharpness_; } void setSharpness(float val) { sharpness_ = val; } - void prepare(Rect dst_roi); - void feed(InputArray img, InputArray mask, Point tl); - void blend(InputOutputArray dst, InputOutputArray dst_mask); + void prepare(Rect dst_roi) CV_OVERRIDE; + void feed(InputArray img, InputArray mask, Point tl) CV_OVERRIDE; + void blend(InputOutputArray dst, InputOutputArray dst_mask) CV_OVERRIDE; //! Creates weight maps for fixed set of source images by their masks and top-left corners. //! Final image can be obtained by simple weighting of the source images. @@ -127,9 +132,9 @@ public: int numBands() const { return actual_num_bands_; } void setNumBands(int val) { actual_num_bands_ = val; } - void prepare(Rect dst_roi); - void feed(InputArray img, InputArray mask, Point tl); - void blend(InputOutputArray dst, InputOutputArray dst_mask); + void prepare(Rect dst_roi) CV_OVERRIDE; + void feed(InputArray img, InputArray mask, Point tl) CV_OVERRIDE; + void blend(InputOutputArray dst, InputOutputArray dst_mask) CV_OVERRIDE; private: int actual_num_bands_, num_bands_; @@ -138,6 +143,22 @@ private: Rect dst_roi_final_; bool can_use_gpu_; int weight_type_; //CV_32F or CV_16S +#if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) + std::vector gpu_dst_pyr_laplace_; + std::vector gpu_dst_band_weights_; + std::vector gpu_tl_points_; + std::vector gpu_imgs_with_border_; + std::vector > gpu_weight_pyr_gauss_vec_; + std::vector > gpu_src_pyr_laplace_vec_; + std::vector > gpu_ups_; + cuda::GpuMat gpu_dst_mask_; + cuda::GpuMat gpu_mask_; + cuda::GpuMat gpu_img_; + cuda::GpuMat gpu_weight_map_; + cuda::GpuMat gpu_add_mask_; + int gpu_feed_idx_; + bool gpu_initialized_; +#endif }; @@ -160,4 +181,4 @@ void CV_EXPORTS restoreImageFromLaplacePyrGpu(std::vector& pyr); } // namespace detail } // namespace cv -#endif // __OPENCV_STITCHING_BLENDERS_HPP__ +#endif // OPENCV_STITCHING_BLENDERS_HPP diff --git a/include/opencv2/stitching/detail/camera.hpp b/include/opencv2/stitching/detail/camera.hpp index c231ba5..07c6b5b 100644 --- a/include/opencv2/stitching/detail/camera.hpp +++ b/include/opencv2/stitching/detail/camera.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_CAMERA_HPP__ -#define __OPENCV_STITCHING_CAMERA_HPP__ +#ifndef OPENCV_STITCHING_CAMERA_HPP +#define OPENCV_STITCHING_CAMERA_HPP #include "opencv2/core.hpp" @@ -59,7 +59,7 @@ struct CV_EXPORTS CameraParams { CameraParams(); CameraParams(const CameraParams& other); - const CameraParams& operator =(const CameraParams& other); + CameraParams& operator =(const CameraParams& other); Mat K() const; double focal; // Focal length @@ -75,4 +75,4 @@ struct CV_EXPORTS CameraParams } // namespace detail } // namespace cv -#endif // #ifndef __OPENCV_STITCHING_CAMERA_HPP__ +#endif // #ifndef OPENCV_STITCHING_CAMERA_HPP diff --git a/include/opencv2/stitching/detail/exposure_compensate.hpp b/include/opencv2/stitching/detail/exposure_compensate.hpp index ef64e12..6c99407 100644 --- a/include/opencv2/stitching/detail/exposure_compensate.hpp +++ b/include/opencv2/stitching/detail/exposure_compensate.hpp @@ -40,8 +40,12 @@ // //M*/ -#ifndef __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__ -#define __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__ +#ifndef OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP +#define OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP + +#if defined(NO) +# warning Detected Apple 'NO' macro definition, it can cause build conflicts. Please, include this header before any Apple headers. +#endif #include "opencv2/core.hpp" @@ -88,8 +92,8 @@ class CV_EXPORTS NoExposureCompensator : public ExposureCompensator { public: void feed(const std::vector &/*corners*/, const std::vector &/*images*/, - const std::vector > &/*masks*/) { } - void apply(int /*index*/, Point /*corner*/, InputOutputArray /*image*/, InputArray /*mask*/) { } + const std::vector > &/*masks*/) CV_OVERRIDE { } + void apply(int /*index*/, Point /*corner*/, InputOutputArray /*image*/, InputArray /*mask*/) CV_OVERRIDE { } }; /** @brief Exposure compensator which tries to remove exposure related artifacts by adjusting image @@ -99,8 +103,8 @@ class CV_EXPORTS GainCompensator : public ExposureCompensator { public: void feed(const std::vector &corners, const std::vector &images, - const std::vector > &masks); - void apply(int index, Point corner, InputOutputArray image, InputArray mask); + const std::vector > &masks) CV_OVERRIDE; + void apply(int index, Point corner, InputOutputArray image, InputArray mask) CV_OVERRIDE; std::vector gains() const; private: @@ -116,8 +120,8 @@ public: BlocksGainCompensator(int bl_width = 32, int bl_height = 32) : bl_width_(bl_width), bl_height_(bl_height) {} void feed(const std::vector &corners, const std::vector &images, - const std::vector > &masks); - void apply(int index, Point corner, InputOutputArray image, InputArray mask); + const std::vector > &masks) CV_OVERRIDE; + void apply(int index, Point corner, InputOutputArray image, InputArray mask) CV_OVERRIDE; private: int bl_width_, bl_height_; @@ -129,4 +133,4 @@ private: } // namespace detail } // namespace cv -#endif // __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__ +#endif // OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP diff --git a/include/opencv2/stitching/detail/matchers.hpp b/include/opencv2/stitching/detail/matchers.hpp index 8f34bd2..25c0f2a 100644 --- a/include/opencv2/stitching/detail/matchers.hpp +++ b/include/opencv2/stitching/detail/matchers.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_MATCHERS_HPP__ -#define __OPENCV_STITCHING_MATCHERS_HPP__ +#ifndef OPENCV_STITCHING_MATCHERS_HPP +#define OPENCV_STITCHING_MATCHERS_HPP #include "opencv2/core.hpp" #include "opencv2/features2d.hpp" @@ -83,9 +83,27 @@ public: @sa detail::ImageFeatures, Rect_ */ void operator ()(InputArray image, ImageFeatures &features, const std::vector &rois); + /** @brief Finds features in the given images in parallel. + + @param images Source images + @param features Found features for each image + @param rois Regions of interest for each image + + @sa detail::ImageFeatures, Rect_ + */ + void operator ()(InputArrayOfArrays images, std::vector &features, + const std::vector > &rois); + /** @overload */ + void operator ()(InputArrayOfArrays images, std::vector &features); /** @brief Frees unused memory allocated before if there is any. */ virtual void collectGarbage() {} + /* TODO OpenCV ABI 4.x + reimplement this as public method similar to FeaturesMatcher and remove private function hack + @return True, if it's possible to use the same finder instance in parallel, false otherwise + bool isThreadSafe() const { return is_thread_safe_; } + */ + protected: /** @brief This method must implement features finding logic in order to make the wrappers detail::FeaturesFinder::operator()_ work. @@ -95,6 +113,10 @@ protected: @sa detail::ImageFeatures */ virtual void find(InputArray image, ImageFeatures &features) = 0; + /** @brief uses dynamic_cast to determine thread-safety + @return True, if it's possible to use the same finder instance in parallel, false otherwise + */ + bool isThreadSafe() const; }; /** @brief SURF features finder. @@ -108,13 +130,28 @@ public: int num_octaves_descr = /*4*/3, int num_layers_descr = /*2*/4); private: - void find(InputArray image, ImageFeatures &features); + void find(InputArray image, ImageFeatures &features) CV_OVERRIDE; Ptr detector_; Ptr extractor_; Ptr surf; }; + +/** @brief SIFT features finder. + +@sa detail::FeaturesFinder, SIFT +*/ +class CV_EXPORTS SiftFeaturesFinder : public FeaturesFinder +{ +public: + SiftFeaturesFinder(); + +private: + void find(InputArray image, ImageFeatures &features) CV_OVERRIDE; + Ptr sift; +}; + /** @brief ORB features finder. : @sa detail::FeaturesFinder, ORB @@ -125,12 +162,32 @@ public: OrbFeaturesFinder(Size _grid_size = Size(3,1), int nfeatures=1500, float scaleFactor=1.3f, int nlevels=5); private: - void find(InputArray image, ImageFeatures &features); + void find(InputArray image, ImageFeatures &features) CV_OVERRIDE; Ptr orb; Size grid_size; }; +/** @brief AKAZE features finder. : + +@sa detail::FeaturesFinder, AKAZE +*/ +class CV_EXPORTS AKAZEFeaturesFinder : public detail::FeaturesFinder +{ +public: + AKAZEFeaturesFinder(int descriptor_type = AKAZE::DESCRIPTOR_MLDB, + int descriptor_size = 0, + int descriptor_channels = 3, + float threshold = 0.001f, + int nOctaves = 4, + int nOctaveLayers = 4, + int diffusivity = KAZE::DIFF_PM_G2); + +private: + void find(InputArray image, ImageFeatures &features) CV_OVERRIDE; + + Ptr akaze; +}; #ifdef HAVE_OPENCV_XFEATURES2D class CV_EXPORTS SurfFeaturesFinderGpu : public FeaturesFinder @@ -139,10 +196,10 @@ public: SurfFeaturesFinderGpu(double hess_thresh = 300., int num_octaves = 3, int num_layers = 4, int num_octaves_descr = 4, int num_layers_descr = 2); - void collectGarbage(); + void collectGarbage() CV_OVERRIDE; private: - void find(InputArray image, ImageFeatures &features); + void find(InputArray image, ImageFeatures &features) CV_OVERRIDE; cuda::GpuMat image_; cuda::GpuMat gray_image_; @@ -156,19 +213,22 @@ private: /** @brief Structure containing information about matches between two images. -It's assumed that there is a homography between those images. +It's assumed that there is a transformation between those images. Transformation may be +homography or affine transformation based on selected matcher. + +@sa detail::FeaturesMatcher */ struct CV_EXPORTS MatchesInfo { MatchesInfo(); MatchesInfo(const MatchesInfo &other); - const MatchesInfo& operator =(const MatchesInfo &other); + MatchesInfo& operator =(const MatchesInfo &other); int src_img_idx, dst_img_idx; //!< Images indices (optional) std::vector matches; std::vector inliers_mask; //!< Geometrically consistent matches mask int num_inliers; //!< Number of geometrically consistent matches - Mat H; //!< Estimated homography + Mat H; //!< Estimated transformation double confidence; //!< Confidence two images are from the same panorama }; @@ -243,10 +303,10 @@ public: BestOf2NearestMatcher(bool try_use_gpu = false, float match_conf = 0.3f, int num_matches_thresh1 = 6, int num_matches_thresh2 = 6); - void collectGarbage(); + void collectGarbage() CV_OVERRIDE; protected: - void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo &matches_info); + void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo &matches_info) CV_OVERRIDE; int num_matches_thresh1_; int num_matches_thresh2_; @@ -267,9 +327,44 @@ protected: int range_width_; }; +/** @brief Features matcher similar to cv::detail::BestOf2NearestMatcher which +finds two best matches for each feature and leaves the best one only if the +ratio between descriptor distances is greater than the threshold match_conf. + +Unlike cv::detail::BestOf2NearestMatcher this matcher uses affine +transformation (affine trasformation estimate will be placed in matches_info). + +@sa cv::detail::FeaturesMatcher cv::detail::BestOf2NearestMatcher + */ +class CV_EXPORTS AffineBestOf2NearestMatcher : public BestOf2NearestMatcher +{ +public: + /** @brief Constructs a "best of 2 nearest" matcher that expects affine trasformation + between images + + @param full_affine whether to use full affine transformation with 6 degress of freedom or reduced + transformation with 4 degrees of freedom using only rotation, translation and uniform scaling + @param try_use_gpu Should try to use GPU or not + @param match_conf Match distances ration threshold + @param num_matches_thresh1 Minimum number of matches required for the 2D affine transform + estimation used in the inliers classification step + + @sa cv::estimateAffine2D cv::estimateAffinePartial2D + */ + AffineBestOf2NearestMatcher(bool full_affine = false, bool try_use_gpu = false, + float match_conf = 0.3f, int num_matches_thresh1 = 6) : + BestOf2NearestMatcher(try_use_gpu, match_conf, num_matches_thresh1, num_matches_thresh1), + full_affine_(full_affine) {} + +protected: + void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo &matches_info) CV_OVERRIDE; + + bool full_affine_; +}; + //! @} stitching_match } // namespace detail } // namespace cv -#endif // __OPENCV_STITCHING_MATCHERS_HPP__ +#endif // OPENCV_STITCHING_MATCHERS_HPP diff --git a/include/opencv2/stitching/detail/motion_estimators.hpp b/include/opencv2/stitching/detail/motion_estimators.hpp index 2c86e63..40f12c3 100644 --- a/include/opencv2/stitching/detail/motion_estimators.hpp +++ b/include/opencv2/stitching/detail/motion_estimators.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_MOTION_ESTIMATORS_HPP__ -#define __OPENCV_STITCHING_MOTION_ESTIMATORS_HPP__ +#ifndef OPENCV_STITCHING_MOTION_ESTIMATORS_HPP +#define OPENCV_STITCHING_MOTION_ESTIMATORS_HPP #include "opencv2/core.hpp" #include "matchers.hpp" @@ -104,11 +104,26 @@ public: private: virtual bool estimate(const std::vector &features, const std::vector &pairwise_matches, - std::vector &cameras); + std::vector &cameras) CV_OVERRIDE; bool is_focals_estimated_; }; +/** @brief Affine transformation based estimator. + +This estimator uses pairwise transformations estimated by matcher to estimate +final transformation for each camera. + +@sa cv::detail::HomographyBasedEstimator + */ +class CV_EXPORTS AffineBasedEstimator : public Estimator +{ +private: + virtual bool estimate(const std::vector &features, + const std::vector &pairwise_matches, + std::vector &cameras) CV_OVERRIDE; +}; + /** @brief Base class for all camera parameters refinement methods. */ class CV_EXPORTS BundleAdjusterBase : public Estimator @@ -134,8 +149,10 @@ protected: @param num_errs_per_measurement Number of error terms (components) per match */ BundleAdjusterBase(int num_params_per_cam, int num_errs_per_measurement) - : num_params_per_cam_(num_params_per_cam), - num_errs_per_measurement_(num_errs_per_measurement) + : num_images_(0), total_num_matches_(0), + num_params_per_cam_(num_params_per_cam), + num_errs_per_measurement_(num_errs_per_measurement), + features_(0), pairwise_matches_(0), conf_thresh_(0) { setRefinementMask(Mat::ones(3, 3, CV_8U)); setConfThresh(1.); @@ -145,7 +162,7 @@ protected: // Runs bundle adjustment virtual bool estimate(const std::vector &features, const std::vector &pairwise_matches, - std::vector &cameras); + std::vector &cameras) CV_OVERRIDE; /** @brief Sets initial camera parameter to refine. @@ -184,7 +201,7 @@ protected: // Threshold to filter out poorly matched image pairs double conf_thresh_; - //Levenberg–Marquardt algorithm termination criteria + //Levenberg-Marquardt algorithm termination criteria TermCriteria term_criteria_; // Camera parameters matrix (CV_64F) @@ -195,6 +212,26 @@ protected: }; +/** @brief Stub bundle adjuster that does nothing. + */ +class CV_EXPORTS NoBundleAdjuster : public BundleAdjusterBase +{ +public: + NoBundleAdjuster() : BundleAdjusterBase(0, 0) {} + +private: + bool estimate(const std::vector &, const std::vector &, + std::vector &) CV_OVERRIDE + { + return true; + } + void setUpInitialCameraParams(const std::vector &) CV_OVERRIDE {} + void obtainRefinedCameraParams(std::vector &) const CV_OVERRIDE {} + void calcError(Mat &) CV_OVERRIDE {} + void calcJacobian(Mat &) CV_OVERRIDE {} +}; + + /** @brief Implementation of the camera parameters refinement algorithm which minimizes sum of the reprojection error squares @@ -207,10 +244,10 @@ public: BundleAdjusterReproj() : BundleAdjusterBase(7, 2) {} private: - void setUpInitialCameraParams(const std::vector &cameras); - void obtainRefinedCameraParams(std::vector &cameras) const; - void calcError(Mat &err); - void calcJacobian(Mat &jac); + void setUpInitialCameraParams(const std::vector &cameras) CV_OVERRIDE; + void obtainRefinedCameraParams(std::vector &cameras) const CV_OVERRIDE; + void calcError(Mat &err) CV_OVERRIDE; + void calcJacobian(Mat &jac) CV_OVERRIDE; Mat err1_, err2_; }; @@ -227,10 +264,58 @@ public: BundleAdjusterRay() : BundleAdjusterBase(4, 3) {} private: - void setUpInitialCameraParams(const std::vector &cameras); - void obtainRefinedCameraParams(std::vector &cameras) const; - void calcError(Mat &err); - void calcJacobian(Mat &jac); + void setUpInitialCameraParams(const std::vector &cameras) CV_OVERRIDE; + void obtainRefinedCameraParams(std::vector &cameras) const CV_OVERRIDE; + void calcError(Mat &err) CV_OVERRIDE; + void calcJacobian(Mat &jac) CV_OVERRIDE; + + Mat err1_, err2_; +}; + + +/** @brief Bundle adjuster that expects affine transformation +represented in homogeneous coordinates in R for each camera param. Implements +camera parameters refinement algorithm which minimizes sum of the reprojection +error squares + +It estimates all transformation parameters. Refinement mask is ignored. + +@sa AffineBasedEstimator AffineBestOf2NearestMatcher BundleAdjusterAffinePartial + */ +class CV_EXPORTS BundleAdjusterAffine : public BundleAdjusterBase +{ +public: + BundleAdjusterAffine() : BundleAdjusterBase(6, 2) {} + +private: + void setUpInitialCameraParams(const std::vector &cameras) CV_OVERRIDE; + void obtainRefinedCameraParams(std::vector &cameras) const CV_OVERRIDE; + void calcError(Mat &err) CV_OVERRIDE; + void calcJacobian(Mat &jac) CV_OVERRIDE; + + Mat err1_, err2_; +}; + + +/** @brief Bundle adjuster that expects affine transformation with 4 DOF +represented in homogeneous coordinates in R for each camera param. Implements +camera parameters refinement algorithm which minimizes sum of the reprojection +error squares + +It estimates all transformation parameters. Refinement mask is ignored. + +@sa AffineBasedEstimator AffineBestOf2NearestMatcher BundleAdjusterAffine + */ +class CV_EXPORTS BundleAdjusterAffinePartial : public BundleAdjusterBase +{ +public: + BundleAdjusterAffinePartial() : BundleAdjusterBase(4, 2) {} + +private: + void setUpInitialCameraParams(const std::vector &cameras) CV_OVERRIDE; + void obtainRefinedCameraParams(std::vector &cameras) const CV_OVERRIDE; + void calcError(Mat &err) CV_OVERRIDE; + void calcJacobian(Mat &jac) CV_OVERRIDE; Mat err1_, err2_; }; @@ -271,4 +356,4 @@ void CV_EXPORTS findMaxSpanningTree( } // namespace detail } // namespace cv -#endif // __OPENCV_STITCHING_MOTION_ESTIMATORS_HPP__ +#endif // OPENCV_STITCHING_MOTION_ESTIMATORS_HPP diff --git a/include/opencv2/stitching/detail/seam_finders.hpp b/include/opencv2/stitching/detail/seam_finders.hpp index 4ff22c4..904f0ec 100644 --- a/include/opencv2/stitching/detail/seam_finders.hpp +++ b/include/opencv2/stitching/detail/seam_finders.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_SEAM_FINDERS_HPP__ -#define __OPENCV_STITCHING_SEAM_FINDERS_HPP__ +#ifndef OPENCV_STITCHING_SEAM_FINDERS_HPP +#define OPENCV_STITCHING_SEAM_FINDERS_HPP #include #include "opencv2/core.hpp" @@ -74,7 +74,7 @@ public: class CV_EXPORTS NoSeamFinder : public SeamFinder { public: - void find(const std::vector&, const std::vector&, std::vector&) {} + void find(const std::vector&, const std::vector&, std::vector&) CV_OVERRIDE {} }; /** @brief Base class for all pairwise seam estimators. @@ -83,7 +83,7 @@ class CV_EXPORTS PairwiseSeamFinder : public SeamFinder { public: virtual void find(const std::vector &src, const std::vector &corners, - std::vector &masks); + std::vector &masks) CV_OVERRIDE; protected: void run(); @@ -107,11 +107,11 @@ class CV_EXPORTS VoronoiSeamFinder : public PairwiseSeamFinder { public: virtual void find(const std::vector &src, const std::vector &corners, - std::vector &masks); + std::vector &masks) CV_OVERRIDE; virtual void find(const std::vector &size, const std::vector &corners, std::vector &masks); private: - void findInPair(size_t first, size_t second, Rect roi); + void findInPair(size_t first, size_t second, Rect roi) CV_OVERRIDE; }; @@ -126,7 +126,7 @@ public: void setCostFunction(CostFunction val) { costFunc_ = val; } virtual void find(const std::vector &src, const std::vector &corners, - std::vector &masks); + std::vector &masks) CV_OVERRIDE; private: enum ComponentState @@ -242,7 +242,7 @@ public: ~GraphCutSeamFinder(); void find(const std::vector &src, const std::vector &corners, - std::vector &masks); + std::vector &masks) CV_OVERRIDE; private: // To avoid GCGraph dependency @@ -261,8 +261,8 @@ public: bad_region_penalty_(bad_region_penalty) {} void find(const std::vector &src, const std::vector &corners, - std::vector &masks); - void findInPair(size_t first, size_t second, Rect roi); + std::vector &masks) CV_OVERRIDE; + void findInPair(size_t first, size_t second, Rect roi) CV_OVERRIDE; private: void setGraphWeightsColor(const cv::Mat &img1, const cv::Mat &img2, const cv::Mat &mask1, const cv::Mat &mask2, @@ -282,4 +282,4 @@ private: } // namespace detail } // namespace cv -#endif // __OPENCV_STITCHING_SEAM_FINDERS_HPP__ +#endif // OPENCV_STITCHING_SEAM_FINDERS_HPP diff --git a/include/opencv2/stitching/detail/timelapsers.hpp b/include/opencv2/stitching/detail/timelapsers.hpp index d64c03c..74d797e 100644 --- a/include/opencv2/stitching/detail/timelapsers.hpp +++ b/include/opencv2/stitching/detail/timelapsers.hpp @@ -41,8 +41,8 @@ //M*/ -#ifndef __OPENCV_STITCHING_TIMELAPSERS_HPP__ -#define __OPENCV_STITCHING_TIMELAPSERS_HPP__ +#ifndef OPENCV_STITCHING_TIMELAPSERS_HPP +#define OPENCV_STITCHING_TIMELAPSERS_HPP #include "opencv2/core.hpp" @@ -80,7 +80,7 @@ protected: class CV_EXPORTS TimelapserCrop : public Timelapser { public: - virtual void initialize(const std::vector &corners, const std::vector &sizes); + virtual void initialize(const std::vector &corners, const std::vector &sizes) CV_OVERRIDE; }; //! @} @@ -88,4 +88,4 @@ public: } // namespace detail } // namespace cv -#endif // __OPENCV_STITCHING_TIMELAPSERS_HPP__ +#endif // OPENCV_STITCHING_TIMELAPSERS_HPP diff --git a/include/opencv2/stitching/detail/util.hpp b/include/opencv2/stitching/detail/util.hpp index 3845ba5..78301b8 100644 --- a/include/opencv2/stitching/detail/util.hpp +++ b/include/opencv2/stitching/detail/util.hpp @@ -40,62 +40,12 @@ // //M*/ -#ifndef __OPENCV_STITCHING_UTIL_HPP__ -#define __OPENCV_STITCHING_UTIL_HPP__ +#ifndef OPENCV_STITCHING_UTIL_HPP +#define OPENCV_STITCHING_UTIL_HPP #include #include "opencv2/core.hpp" -#ifndef ENABLE_LOG -#define ENABLE_LOG 0 -#endif - -// TODO remove LOG macros, add logging class -#if ENABLE_LOG -#ifdef ANDROID - #include - #include - #include - #define LOG_STITCHING_MSG(msg) \ - do { \ - Stringstream _os; \ - _os << msg; \ - __android_log_print(ANDROID_LOG_DEBUG, "STITCHING", "%s", _os.str().c_str()); \ - } while(0); -#else - #include - #define LOG_STITCHING_MSG(msg) for(;;) { std::cout << msg; std::cout.flush(); break; } -#endif -#else - #define LOG_STITCHING_MSG(msg) -#endif - -#define LOG_(_level, _msg) \ - for(;;) \ - { \ - using namespace std; \ - if ((_level) >= ::cv::detail::stitchingLogLevel()) \ - { \ - LOG_STITCHING_MSG(_msg); \ - } \ - break; \ - } - - -#define LOG(msg) LOG_(1, msg) -#define LOG_CHAT(msg) LOG_(0, msg) - -#define LOGLN(msg) LOG(msg << std::endl) -#define LOGLN_CHAT(msg) LOG_CHAT(msg << std::endl) - -//#if DEBUG_LOG_CHAT -// #define LOG_CHAT(msg) LOG(msg) -// #define LOGLN_CHAT(msg) LOGLN(msg) -//#else -// #define LOG_CHAT(msg) do{}while(0) -// #define LOGLN_CHAT(msg) do{}while(0) -//#endif - namespace cv { namespace detail { @@ -168,4 +118,4 @@ CV_EXPORTS int& stitchingLogLevel(); #include "util_inl.hpp" -#endif // __OPENCV_STITCHING_UTIL_HPP__ +#endif // OPENCV_STITCHING_UTIL_HPP diff --git a/include/opencv2/stitching/detail/util_inl.hpp b/include/opencv2/stitching/detail/util_inl.hpp index 6ac6f8e..dafab8b 100644 --- a/include/opencv2/stitching/detail/util_inl.hpp +++ b/include/opencv2/stitching/detail/util_inl.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_UTIL_INL_HPP__ -#define __OPENCV_STITCHING_UTIL_INL_HPP__ +#ifndef OPENCV_STITCHING_UTIL_INL_HPP +#define OPENCV_STITCHING_UTIL_INL_HPP #include #include "opencv2/core.hpp" @@ -128,4 +128,4 @@ static inline double sqr(double x) { return x * x; } //! @endcond -#endif // __OPENCV_STITCHING_UTIL_INL_HPP__ +#endif // OPENCV_STITCHING_UTIL_INL_HPP diff --git a/include/opencv2/stitching/detail/warpers.hpp b/include/opencv2/stitching/detail/warpers.hpp index ee8e824..1b05651 100644 --- a/include/opencv2/stitching/detail/warpers.hpp +++ b/include/opencv2/stitching/detail/warpers.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_WARPERS_HPP__ -#define __OPENCV_STITCHING_WARPERS_HPP__ +#ifndef OPENCV_STITCHING_WARPERS_HPP +#define OPENCV_STITCHING_WARPERS_HPP #include "opencv2/core.hpp" #include "opencv2/core/cuda.hpp" @@ -138,23 +138,23 @@ struct CV_EXPORTS ProjectorBase /** @brief Base class for rotation-based warper using a detail::ProjectorBase_ derived class. */ template -class CV_EXPORTS RotationWarperBase : public RotationWarper +class CV_EXPORTS_TEMPLATE RotationWarperBase : public RotationWarper { public: - Point2f warpPoint(const Point2f &pt, InputArray K, InputArray R); + Point2f warpPoint(const Point2f &pt, InputArray K, InputArray R) CV_OVERRIDE; - Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap); + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE; Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, - OutputArray dst); + OutputArray dst) CV_OVERRIDE; void warpBackward(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, - Size dst_size, OutputArray dst); + Size dst_size, OutputArray dst) CV_OVERRIDE; - Rect warpRoi(Size src_size, InputArray K, InputArray R); + Rect warpRoi(Size src_size, InputArray K, InputArray R) CV_OVERRIDE; - float getScale() const { return projector_.scale; } - void setScale(float val) { projector_.scale = val; } + float getScale() const CV_OVERRIDE{ return projector_.scale; } + void setScale(float val) CV_OVERRIDE { projector_.scale = val; } protected: @@ -186,22 +186,50 @@ public: */ PlaneWarper(float scale = 1.f) { projector_.scale = scale; } - Point2f warpPoint(const Point2f &pt, InputArray K, InputArray R); + Point2f warpPoint(const Point2f &pt, InputArray K, InputArray R) CV_OVERRIDE; Point2f warpPoint(const Point2f &pt, InputArray K, InputArray R, InputArray T); virtual Rect buildMaps(Size src_size, InputArray K, InputArray R, InputArray T, OutputArray xmap, OutputArray ymap); - Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap); + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE; Point warp(InputArray src, InputArray K, InputArray R, - int interp_mode, int border_mode, OutputArray dst); + int interp_mode, int border_mode, OutputArray dst) CV_OVERRIDE; virtual Point warp(InputArray src, InputArray K, InputArray R, InputArray T, int interp_mode, int border_mode, OutputArray dst); - Rect warpRoi(Size src_size, InputArray K, InputArray R); + Rect warpRoi(Size src_size, InputArray K, InputArray R) CV_OVERRIDE; Rect warpRoi(Size src_size, InputArray K, InputArray R, InputArray T); protected: - void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br); + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) CV_OVERRIDE; +}; + + +/** @brief Affine warper that uses rotations and translations + + Uses affine transformation in homogeneous coordinates to represent both rotation and + translation in camera rotation matrix. + */ +class CV_EXPORTS AffineWarper : public PlaneWarper +{ +public: + /** @brief Construct an instance of the affine warper class. + + @param scale Projected image scale multiplier + */ + AffineWarper(float scale = 1.f) : PlaneWarper(scale) {} + + Point2f warpPoint(const Point2f &pt, InputArray K, InputArray R) CV_OVERRIDE; + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE; + Point warp(InputArray src, InputArray K, InputArray R, + int interp_mode, int border_mode, OutputArray dst) CV_OVERRIDE; + Rect warpRoi(Size src_size, InputArray K, InputArray R) CV_OVERRIDE; + +protected: + /** @brief Extracts rotation and translation matrices from matrix H representing + affine transformation in homogeneous coordinates + */ + void getRTfromHomogeneous(InputArray H, Mat &R, Mat &T); }; @@ -214,7 +242,8 @@ struct CV_EXPORTS SphericalProjector : ProjectorBase /** @brief Warper that maps an image onto the unit sphere located at the origin. - Projects image onto unit sphere with origin at (0, 0, 0). + Projects image onto unit sphere with origin at (0, 0, 0) and radius scale, measured in pixels. + A 360 panorama would therefore have a resulting width of 2 * scale * PI pixels. Poles are located at (0, -1, 0) and (0, 1, 0) points. */ class CV_EXPORTS SphericalWarper : public RotationWarperBase @@ -222,14 +251,15 @@ class CV_EXPORTS SphericalWarper : public RotationWarperBase public: /** @brief Construct an instance of the spherical warper class. - @param scale Projected image scale multiplier + @param scale Radius of the projected sphere, in pixels. An image spanning the + whole sphere will have a width of 2 * scale * PI pixels. */ SphericalWarper(float scale) { projector_.scale = scale; } - Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap); - Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, OutputArray dst); + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE; + Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, OutputArray dst) CV_OVERRIDE; protected: - void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br); + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) CV_OVERRIDE; }; @@ -251,10 +281,10 @@ public: */ CylindricalWarper(float scale) { projector_.scale = scale; } - Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap); - Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, OutputArray dst); + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE; + Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, OutputArray dst) CV_OVERRIDE; protected: - void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) CV_OVERRIDE { RotationWarperBase::detectResultRoiByBorder(src_size, dst_tl, dst_br); } @@ -407,7 +437,7 @@ class CV_EXPORTS PlaneWarperGpu : public PlaneWarper public: PlaneWarperGpu(float scale = 1.f) : PlaneWarper(scale) {} - Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE { Rect result = buildMaps(src_size, K, R, d_xmap_, d_ymap_); d_xmap_.download(xmap); @@ -415,7 +445,7 @@ public: return result; } - Rect buildMaps(Size src_size, InputArray K, InputArray R, InputArray T, OutputArray xmap, OutputArray ymap) + Rect buildMaps(Size src_size, InputArray K, InputArray R, InputArray T, OutputArray xmap, OutputArray ymap) CV_OVERRIDE { Rect result = buildMaps(src_size, K, R, T, d_xmap_, d_ymap_); d_xmap_.download(xmap); @@ -424,7 +454,7 @@ public: } Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, - OutputArray dst) + OutputArray dst) CV_OVERRIDE { d_src_.upload(src); Point result = warp(d_src_, K, R, interp_mode, border_mode, d_dst_); @@ -433,7 +463,7 @@ public: } Point warp(InputArray src, InputArray K, InputArray R, InputArray T, int interp_mode, int border_mode, - OutputArray dst) + OutputArray dst) CV_OVERRIDE { d_src_.upload(src); Point result = warp(d_src_, K, R, T, interp_mode, border_mode, d_dst_); @@ -461,7 +491,7 @@ class CV_EXPORTS SphericalWarperGpu : public SphericalWarper public: SphericalWarperGpu(float scale) : SphericalWarper(scale) {} - Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE { Rect result = buildMaps(src_size, K, R, d_xmap_, d_ymap_); d_xmap_.download(xmap); @@ -470,7 +500,7 @@ public: } Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, - OutputArray dst) + OutputArray dst) CV_OVERRIDE { d_src_.upload(src); Point result = warp(d_src_, K, R, interp_mode, border_mode, d_dst_); @@ -493,7 +523,7 @@ class CV_EXPORTS CylindricalWarperGpu : public CylindricalWarper public: CylindricalWarperGpu(float scale) : CylindricalWarper(scale) {} - Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) + Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) CV_OVERRIDE { Rect result = buildMaps(src_size, K, R, d_xmap_, d_ymap_); d_xmap_.download(xmap); @@ -502,7 +532,7 @@ public: } Point warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, - OutputArray dst) + OutputArray dst) CV_OVERRIDE { d_src_.upload(src); Point result = warp(d_src_, K, R, interp_mode, border_mode, d_dst_); @@ -520,7 +550,7 @@ private: }; -struct SphericalPortraitProjector : ProjectorBase +struct CV_EXPORTS SphericalPortraitProjector : ProjectorBase { void mapForward(float x, float y, float &u, float &v); void mapBackward(float u, float v, float &x, float &y); @@ -535,10 +565,10 @@ public: SphericalPortraitWarper(float scale) { projector_.scale = scale; } protected: - void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br); + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) CV_OVERRIDE; }; -struct CylindricalPortraitProjector : ProjectorBase +struct CV_EXPORTS CylindricalPortraitProjector : ProjectorBase { void mapForward(float x, float y, float &u, float &v); void mapBackward(float u, float v, float &x, float &y); @@ -551,13 +581,13 @@ public: CylindricalPortraitWarper(float scale) { projector_.scale = scale; } protected: - void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) CV_OVERRIDE { RotationWarperBase::detectResultRoiByBorder(src_size, dst_tl, dst_br); } }; -struct PlanePortraitProjector : ProjectorBase +struct CV_EXPORTS PlanePortraitProjector : ProjectorBase { void mapForward(float x, float y, float &u, float &v); void mapBackward(float u, float v, float &x, float &y); @@ -570,7 +600,7 @@ public: PlanePortraitWarper(float scale) { projector_.scale = scale; } protected: - void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) CV_OVERRIDE { RotationWarperBase::detectResultRoiByBorder(src_size, dst_tl, dst_br); } @@ -583,4 +613,4 @@ protected: #include "warpers_inl.hpp" -#endif // __OPENCV_STITCHING_WARPERS_HPP__ +#endif // OPENCV_STITCHING_WARPERS_HPP diff --git a/include/opencv2/stitching/detail/warpers_inl.hpp b/include/opencv2/stitching/detail/warpers_inl.hpp index 0416ecb..f4a19d9 100644 --- a/include/opencv2/stitching/detail/warpers_inl.hpp +++ b/include/opencv2/stitching/detail/warpers_inl.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_WARPERS_INL_HPP__ -#define __OPENCV_STITCHING_WARPERS_INL_HPP__ +#ifndef OPENCV_STITCHING_WARPERS_INL_HPP +#define OPENCV_STITCHING_WARPERS_INL_HPP #include "opencv2/core.hpp" #include "warpers.hpp" // Make your IDE see declarations @@ -150,10 +150,10 @@ Rect RotationWarperBase

::warpRoi(Size src_size, InputArray K, InputArray R) template void RotationWarperBase

::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) { - float tl_uf = std::numeric_limits::max(); - float tl_vf = std::numeric_limits::max(); - float br_uf = -std::numeric_limits::max(); - float br_vf = -std::numeric_limits::max(); + float tl_uf = (std::numeric_limits::max)(); + float tl_vf = (std::numeric_limits::max)(); + float br_uf = -(std::numeric_limits::max)(); + float br_vf = -(std::numeric_limits::max)(); float u, v; for (int y = 0; y < src_size.height; ++y) @@ -161,8 +161,8 @@ void RotationWarperBase

::detectResultRoi(Size src_size, Point &dst_tl, Point for (int x = 0; x < src_size.width; ++x) { projector_.mapForward(static_cast(x), static_cast(y), u, v); - tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); - br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); + tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v); + br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v); } } @@ -176,31 +176,31 @@ void RotationWarperBase

::detectResultRoi(Size src_size, Point &dst_tl, Point template void RotationWarperBase

::detectResultRoiByBorder(Size src_size, Point &dst_tl, Point &dst_br) { - float tl_uf = std::numeric_limits::max(); - float tl_vf = std::numeric_limits::max(); - float br_uf = -std::numeric_limits::max(); - float br_vf = -std::numeric_limits::max(); + float tl_uf = (std::numeric_limits::max)(); + float tl_vf = (std::numeric_limits::max)(); + float br_uf = -(std::numeric_limits::max)(); + float br_vf = -(std::numeric_limits::max)(); float u, v; for (float x = 0; x < src_size.width; ++x) { projector_.mapForward(static_cast(x), 0, u, v); - tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); - br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); + tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v); + br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v); projector_.mapForward(static_cast(x), static_cast(src_size.height - 1), u, v); - tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); - br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); + tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v); + br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v); } for (int y = 0; y < src_size.height; ++y) { projector_.mapForward(0, static_cast(y), u, v); - tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); - br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); + tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v); + br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v); projector_.mapForward(static_cast(src_size.width - 1), static_cast(y), u, v); - tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); - br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); + tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v); + br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v); } dst_tl.x = static_cast(tl_uf); @@ -771,4 +771,4 @@ void PlanePortraitProjector::mapBackward(float u0, float v0, float &x, float &y) //! @endcond -#endif // __OPENCV_STITCHING_WARPERS_INL_HPP__ +#endif // OPENCV_STITCHING_WARPERS_INL_HPP diff --git a/include/opencv2/stitching/warpers.hpp b/include/opencv2/stitching/warpers.hpp index 7e570d3..cf7699c 100644 --- a/include/opencv2/stitching/warpers.hpp +++ b/include/opencv2/stitching/warpers.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_STITCHING_WARPER_CREATORS_HPP__ -#define __OPENCV_STITCHING_WARPER_CREATORS_HPP__ +#ifndef OPENCV_STITCHING_WARPER_CREATORS_HPP +#define OPENCV_STITCHING_WARPER_CREATORS_HPP #include "opencv2/stitching/detail/warpers.hpp" @@ -65,7 +65,16 @@ public: class PlaneWarper : public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } +}; + +/** @brief Affine warper factory class. + @sa detail::AffineWarper + */ +class AffineWarper : public WarperCreator +{ +public: + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; /** @brief Cylindrical warper factory class. @@ -74,26 +83,26 @@ public: class CylindricalWarper: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; /** @brief Spherical warper factory class */ class SphericalWarper: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; class FisheyeWarper : public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; class StereographicWarper: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; class CompressedRectilinearWarper: public WarperCreator @@ -104,7 +113,7 @@ public: { a = A; b = B; } - Ptr create(float scale) const { return makePtr(scale, a, b); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale, a, b); } }; class CompressedRectilinearPortraitWarper: public WarperCreator @@ -115,7 +124,7 @@ public: { a = A; b = B; } - Ptr create(float scale) const { return makePtr(scale, a, b); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale, a, b); } }; class PaniniWarper: public WarperCreator @@ -126,7 +135,7 @@ public: { a = A; b = B; } - Ptr create(float scale) const { return makePtr(scale, a, b); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale, a, b); } }; class PaniniPortraitWarper: public WarperCreator @@ -137,19 +146,19 @@ public: { a = A; b = B; } - Ptr create(float scale) const { return makePtr(scale, a, b); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale, a, b); } }; class MercatorWarper: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; class TransverseMercatorWarper: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; @@ -158,21 +167,21 @@ public: class PlaneWarperGpu: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; class CylindricalWarperGpu: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; class SphericalWarperGpu: public WarperCreator { public: - Ptr create(float scale) const { return makePtr(scale); } + Ptr create(float scale) const CV_OVERRIDE { return makePtr(scale); } }; #endif @@ -180,4 +189,4 @@ public: } // namespace cv -#endif // __OPENCV_STITCHING_WARPER_CREATORS_HPP__ +#endif // OPENCV_STITCHING_WARPER_CREATORS_HPP diff --git a/include/opencv2/superres.hpp b/include/opencv2/superres.hpp index dec8e4e..16c11ac 100644 --- a/include/opencv2/superres.hpp +++ b/include/opencv2/superres.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_SUPERRES_HPP__ -#define __OPENCV_SUPERRES_HPP__ +#ifndef OPENCV_SUPERRES_HPP +#define OPENCV_SUPERRES_HPP #include "opencv2/core.hpp" #include "opencv2/superres/optical_flow.hpp" @@ -50,7 +50,7 @@ @defgroup superres Super Resolution The Super Resolution module contains a set of functions and classes that can be used to solve the -problem of resolution enhancement. There are a few methods implemented, most of them are descibed in +problem of resolution enhancement. There are a few methods implemented, most of them are described in the papers @cite Farsiu03 and @cite Mitzel09 . */ @@ -97,8 +97,8 @@ namespace cv @param frame Output result */ - void nextFrame(OutputArray frame); - void reset(); + void nextFrame(OutputArray frame) CV_OVERRIDE; + void reset() CV_OVERRIDE; /** @brief Clear all inner buffers. */ @@ -204,4 +204,4 @@ namespace cv } } -#endif // __OPENCV_SUPERRES_HPP__ +#endif // OPENCV_SUPERRES_HPP diff --git a/include/opencv2/superres/optical_flow.hpp b/include/opencv2/superres/optical_flow.hpp index d2f29a3..07e7ca9 100644 --- a/include/opencv2/superres/optical_flow.hpp +++ b/include/opencv2/superres/optical_flow.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_SUPERRES_OPTICAL_FLOW_HPP__ -#define __OPENCV_SUPERRES_OPTICAL_FLOW_HPP__ +#ifndef OPENCV_SUPERRES_OPTICAL_FLOW_HPP +#define OPENCV_SUPERRES_OPTICAL_FLOW_HPP #include "opencv2/core.hpp" @@ -200,4 +200,4 @@ namespace cv } } -#endif // __OPENCV_SUPERRES_OPTICAL_FLOW_HPP__ +#endif // OPENCV_SUPERRES_OPTICAL_FLOW_HPP diff --git a/include/opencv2/video.hpp b/include/opencv2/video.hpp index a593815..aa644a9 100644 --- a/include/opencv2/video.hpp +++ b/include/opencv2/video.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_VIDEO_HPP__ -#define __OPENCV_VIDEO_HPP__ +#ifndef OPENCV_VIDEO_HPP +#define OPENCV_VIDEO_HPP /** @defgroup video Video Analysis @@ -60,4 +60,4 @@ #include "opencv2/video/tracking_c.h" #endif -#endif //__OPENCV_VIDEO_HPP__ +#endif //OPENCV_VIDEO_HPP diff --git a/include/opencv2/video/background_segm.hpp b/include/opencv2/video/background_segm.hpp index dbeccbd..e1dfa15 100644 --- a/include/opencv2/video/background_segm.hpp +++ b/include/opencv2/video/background_segm.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_BACKGROUND_SEGM_HPP__ -#define __OPENCV_BACKGROUND_SEGM_HPP__ +#ifndef OPENCV_BACKGROUND_SEGM_HPP +#define OPENCV_BACKGROUND_SEGM_HPP #include "opencv2/core.hpp" @@ -188,13 +188,24 @@ public: A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel - is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiarra, + is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara, *Detecting Moving Shadows...*, IEEE PAMI,2003. */ CV_WRAP virtual double getShadowThreshold() const = 0; /** @brief Sets the shadow threshold */ CV_WRAP virtual void setShadowThreshold(double threshold) = 0; + + /** @brief Computes a foreground mask. + + @param image Next video frame. Floating point frame will be used without scaling and should be in range \f$[0,255]\f$. + @param fgmask The output foreground mask as an 8-bit binary image. + @param learningRate The value between 0 and 1 that indicates how fast the background model is + learnt. Negative parameter value makes the algorithm to use some automatically chosen learning + rate. 0 means that the background model is not updated at all, 1 means that the background model + is completely reinitialized from the last frame. + */ + CV_WRAP virtual void apply(InputArray image, OutputArray fgmask, double learningRate=-1) CV_OVERRIDE = 0; }; /** @brief Creates MOG2 Background Subtractor @@ -210,9 +221,9 @@ CV_EXPORTS_W Ptr createBackgroundSubtractorMOG2(int history=500, double varThreshold=16, bool detectShadows=true); -/** @brief K-nearest neigbours - based Background/Foreground Segmentation Algorithm. +/** @brief K-nearest neighbours - based Background/Foreground Segmentation Algorithm. -The class implements the K-nearest neigbours background subtraction described in @cite Zivkovic2006 . +The class implements the K-nearest neighbours background subtraction described in @cite Zivkovic2006 . Very efficient if number of foreground pixels is low. */ class CV_EXPORTS_W BackgroundSubtractorKNN : public BackgroundSubtractor @@ -250,7 +261,7 @@ public: pixel is matching the kNN background model. */ CV_WRAP virtual int getkNNSamples() const = 0; - /** @brief Sets the k in the kNN. How many nearest neigbours need to match. + /** @brief Sets the k in the kNN. How many nearest neighbours need to match. */ CV_WRAP virtual void setkNNSamples(int _nkNN) = 0; @@ -278,7 +289,7 @@ public: A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel - is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiarra, + is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara, *Detecting Moving Shadows...*, IEEE PAMI,2003. */ CV_WRAP virtual double getShadowThreshold() const = 0; diff --git a/include/opencv2/video/tracking.hpp b/include/opencv2/video/tracking.hpp index 217a26a..e757b0f 100644 --- a/include/opencv2/video/tracking.hpp +++ b/include/opencv2/video/tracking.hpp @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_TRACKING_HPP__ -#define __OPENCV_TRACKING_HPP__ +#ifndef OPENCV_TRACKING_HPP +#define OPENCV_TRACKING_HPP #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" @@ -74,10 +74,13 @@ See the OpenCV sample camshiftdemo.c that tracks colored objects. @note - (Python) A sample explaining the camshift tracking algorithm can be found at - opencv_source_code/samples/python2/camshift.py + opencv_source_code/samples/python/camshift.py */ CV_EXPORTS_W RotatedRect CamShift( InputArray probImage, CV_IN_OUT Rect& window, TermCriteria criteria ); +/** @example samples/cpp/camshiftdemo.cpp +An example using the mean-shift tracking algorithm +*/ /** @brief Finds an object on a back projection image. @@ -97,8 +100,6 @@ projection and remove the noise. For example, you can do this by retrieving conn with findContours , throwing away contours with small area ( contourArea ), and rendering the remaining contours with drawContours. -@note -- A mean-shift tracking sample can be found at opencv_source_code/samples/cpp/camshiftdemo.cpp */ CV_EXPORTS_W int meanShift( InputArray probImage, CV_IN_OUT Rect& window, TermCriteria criteria ); @@ -123,6 +124,10 @@ CV_EXPORTS_W int buildOpticalFlowPyramid( InputArray img, OutputArrayOfArrays py int derivBorder = BORDER_CONSTANT, bool tryReuseInputImage = true ); +/** @example samples/cpp/lkdemo.cpp +An example using the Lucas-Kanade optical flow algorithm +*/ + /** @brief Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with pyramids. @@ -166,9 +171,9 @@ The function implements a sparse iterative version of the Lucas-Kanade optical f - An example using the Lucas-Kanade optical flow algorithm can be found at opencv_source_code/samples/cpp/lkdemo.cpp - (Python) An example using the Lucas-Kanade optical flow algorithm can be found at - opencv_source_code/samples/python2/lk_track.py + opencv_source_code/samples/python/lk_track.py - (Python) An example using the Lucas-Kanade tracker for homography matching can be found at - opencv_source_code/samples/python2/lk_homography.py + opencv_source_code/samples/python/lk_homography.py */ CV_EXPORTS_W void calcOpticalFlowPyrLK( InputArray prevImg, InputArray nextImg, InputArray prevPts, InputOutputArray nextPts, @@ -213,7 +218,7 @@ The function finds an optical flow for each prev pixel using the @cite Farneback - An example using the optical flow algorithm described by Gunnar Farneback can be found at opencv_source_code/samples/cpp/fback.cpp - (Python) An example using the optical flow algorithm described by Gunnar Farneback can be - found at opencv_source_code/samples/python2/opt_flow.py + found at opencv_source_code/samples/python/opt_flow.py */ CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next, InputOutputArray flow, double pyr_scale, int levels, int winsize, @@ -226,7 +231,7 @@ CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next, In @param dst Second input 2D point set of the same size and the same type as A, or another image. @param fullAffine If true, the function finds an optimal affine transformation with no additional restrictions (6 degrees of freedom). Otherwise, the class of transformations to choose from is -limited to combinations of translation, rotation, and uniform scaling (5 degrees of freedom). +limited to combinations of translation, rotation, and uniform scaling (4 degrees of freedom). The function finds an optimal affine transform *[A|b]* (a 2 x 3 floating-point matrix) that approximates best the affine transformation between: @@ -245,9 +250,11 @@ where src[i] and dst[i] are the i-th points in src and dst, respectively when fullAffine=false. @sa -getAffineTransform, getPerspectiveTransform, findHomography +estimateAffine2D, estimateAffinePartial2D, getAffineTransform, getPerspectiveTransform, findHomography */ -CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine ); +CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine); +CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine, int ransacMaxIters, double ransacGoodRatio, + int ransacSize0); enum @@ -258,6 +265,10 @@ enum MOTION_HOMOGRAPHY = 3 }; +/** @example samples/cpp/image_alignment.cpp +An example using the image alignment ECC algorithm +*/ + /** @brief Finds the geometric transform (warp) between two images in terms of the ECC criterion @cite EP08 . @param templateImage single-channel template image; CV_8U or CV_32F array. @@ -297,7 +308,7 @@ row is ignored. Unlike findHomography and estimateRigidTransform, the function findTransformECC implements an area-based alignment that builds on intensity similarities. In essence, the function updates the initial transformation that roughly aligns the images. If this information is missing, the identity -warp (unity matrix) should be given as input. Note that if images undergo strong +warp (unity matrix) is used as an initialization. Note that if images undergo strong displacements/rotations, an initial transformation that roughly aligns the images is necessary (e.g., a simple euclidean/similarity transform that allows for the images showing the same image content approximately). Use inverse warping in the second image to take an image close to the first @@ -306,32 +317,28 @@ sample image_alignment.cpp that demonstrates the use of the function. Note that an exception if algorithm does not converges. @sa -estimateRigidTransform, findHomography +estimateAffine2D, estimateAffinePartial2D, findHomography */ CV_EXPORTS_W double findTransformECC( InputArray templateImage, InputArray inputImage, InputOutputArray warpMatrix, int motionType = MOTION_AFFINE, TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001), InputArray inputMask = noArray()); +/** @example samples/cpp/kalman.cpp +An example using the standard Kalman filter +*/ + /** @brief Kalman filter class. The class implements a standard Kalman filter , @cite Welch95 . However, you can modify transitionMatrix, controlMatrix, and measurementMatrix to get -an extended Kalman filter functionality. See the OpenCV sample kalman.cpp. - -@note - -- An example using the standard Kalman filter can be found at - opencv_source_code/samples/cpp/kalman.cpp +an extended Kalman filter functionality. +@note In C API when CvKalman\* kalmanFilter structure is not needed anymore, it should be released +with cvReleaseKalman(&kalmanFilter) */ class CV_EXPORTS_W KalmanFilter { public: - /** @brief The constructors. - - @note In C API when CvKalman\* kalmanFilter structure is not needed anymore, it should be released - with cvReleaseKalman(&kalmanFilter) - */ CV_WRAP KalmanFilter(); /** @overload @param dynamParams Dimensionality of the state. @@ -397,6 +404,27 @@ public: CV_WRAP virtual void collectGarbage() = 0; }; +/** @brief Base interface for sparse optical flow algorithms. + */ +class CV_EXPORTS_W SparseOpticalFlow : public Algorithm +{ +public: + /** @brief Calculates a sparse optical flow. + + @param prevImg First input image. + @param nextImg Second input image of the same size and the same type as prevImg. + @param prevPts Vector of 2D points for which the flow needs to be found. + @param nextPts Output vector of 2D points containing the calculated new positions of input features in the second image. + @param status Output status vector. Each element of the vector is set to 1 if the + flow for the corresponding features has been found. Otherwise, it is set to 0. + @param err Optional output vector that contains error response for each point (inverse confidence). + */ + CV_WRAP virtual void calc(InputArray prevImg, InputArray nextImg, + InputArray prevPts, InputOutputArray nextPts, + OutputArray status, + OutputArray err = cv::noArray()) = 0; +}; + /** @brief "Dual TV L1" Optical Flow Algorithm. The class implements the "Dual TV L1" optical flow algorithm described in @cite Zach2007 and @@ -444,70 +472,160 @@ class CV_EXPORTS_W DualTVL1OpticalFlow : public DenseOpticalFlow public: //! @brief Time step of the numerical scheme /** @see setTau */ - virtual double getTau() const = 0; + CV_WRAP virtual double getTau() const = 0; /** @copybrief getTau @see getTau */ - virtual void setTau(double val) = 0; + CV_WRAP virtual void setTau(double val) = 0; //! @brief Weight parameter for the data term, attachment parameter /** @see setLambda */ - virtual double getLambda() const = 0; + CV_WRAP virtual double getLambda() const = 0; /** @copybrief getLambda @see getLambda */ - virtual void setLambda(double val) = 0; + CV_WRAP virtual void setLambda(double val) = 0; //! @brief Weight parameter for (u - v)^2, tightness parameter /** @see setTheta */ - virtual double getTheta() const = 0; + CV_WRAP virtual double getTheta() const = 0; /** @copybrief getTheta @see getTheta */ - virtual void setTheta(double val) = 0; + CV_WRAP virtual void setTheta(double val) = 0; //! @brief coefficient for additional illumination variation term /** @see setGamma */ - virtual double getGamma() const = 0; + CV_WRAP virtual double getGamma() const = 0; /** @copybrief getGamma @see getGamma */ - virtual void setGamma(double val) = 0; + CV_WRAP virtual void setGamma(double val) = 0; //! @brief Number of scales used to create the pyramid of images /** @see setScalesNumber */ - virtual int getScalesNumber() const = 0; + CV_WRAP virtual int getScalesNumber() const = 0; /** @copybrief getScalesNumber @see getScalesNumber */ - virtual void setScalesNumber(int val) = 0; + CV_WRAP virtual void setScalesNumber(int val) = 0; //! @brief Number of warpings per scale /** @see setWarpingsNumber */ - virtual int getWarpingsNumber() const = 0; + CV_WRAP virtual int getWarpingsNumber() const = 0; /** @copybrief getWarpingsNumber @see getWarpingsNumber */ - virtual void setWarpingsNumber(int val) = 0; + CV_WRAP virtual void setWarpingsNumber(int val) = 0; //! @brief Stopping criterion threshold used in the numerical scheme, which is a trade-off between precision and running time /** @see setEpsilon */ - virtual double getEpsilon() const = 0; + CV_WRAP virtual double getEpsilon() const = 0; /** @copybrief getEpsilon @see getEpsilon */ - virtual void setEpsilon(double val) = 0; + CV_WRAP virtual void setEpsilon(double val) = 0; //! @brief Inner iterations (between outlier filtering) used in the numerical scheme /** @see setInnerIterations */ - virtual int getInnerIterations() const = 0; + CV_WRAP virtual int getInnerIterations() const = 0; /** @copybrief getInnerIterations @see getInnerIterations */ - virtual void setInnerIterations(int val) = 0; + CV_WRAP virtual void setInnerIterations(int val) = 0; //! @brief Outer iterations (number of inner loops) used in the numerical scheme /** @see setOuterIterations */ - virtual int getOuterIterations() const = 0; + CV_WRAP virtual int getOuterIterations() const = 0; /** @copybrief getOuterIterations @see getOuterIterations */ - virtual void setOuterIterations(int val) = 0; + CV_WRAP virtual void setOuterIterations(int val) = 0; //! @brief Use initial flow /** @see setUseInitialFlow */ - virtual bool getUseInitialFlow() const = 0; + CV_WRAP virtual bool getUseInitialFlow() const = 0; /** @copybrief getUseInitialFlow @see getUseInitialFlow */ - virtual void setUseInitialFlow(bool val) = 0; + CV_WRAP virtual void setUseInitialFlow(bool val) = 0; //! @brief Step between scales (<1) /** @see setScaleStep */ - virtual double getScaleStep() const = 0; + CV_WRAP virtual double getScaleStep() const = 0; /** @copybrief getScaleStep @see getScaleStep */ - virtual void setScaleStep(double val) = 0; + CV_WRAP virtual void setScaleStep(double val) = 0; //! @brief Median filter kernel size (1 = no filter) (3 or 5) /** @see setMedianFiltering */ - virtual int getMedianFiltering() const = 0; + CV_WRAP virtual int getMedianFiltering() const = 0; /** @copybrief getMedianFiltering @see getMedianFiltering */ - virtual void setMedianFiltering(int val) = 0; + CV_WRAP virtual void setMedianFiltering(int val) = 0; + + /** @brief Creates instance of cv::DualTVL1OpticalFlow*/ + CV_WRAP static Ptr create( + double tau = 0.25, + double lambda = 0.15, + double theta = 0.3, + int nscales = 5, + int warps = 5, + double epsilon = 0.01, + int innnerIterations = 30, + int outerIterations = 10, + double scaleStep = 0.8, + double gamma = 0.0, + int medianFiltering = 5, + bool useInitialFlow = false); }; /** @brief Creates instance of cv::DenseOpticalFlow */ CV_EXPORTS_W Ptr createOptFlow_DualTVL1(); +/** @brief Class computing a dense optical flow using the Gunnar Farneback's algorithm. + */ +class CV_EXPORTS_W FarnebackOpticalFlow : public DenseOpticalFlow +{ +public: + CV_WRAP virtual int getNumLevels() const = 0; + CV_WRAP virtual void setNumLevels(int numLevels) = 0; + + CV_WRAP virtual double getPyrScale() const = 0; + CV_WRAP virtual void setPyrScale(double pyrScale) = 0; + + CV_WRAP virtual bool getFastPyramids() const = 0; + CV_WRAP virtual void setFastPyramids(bool fastPyramids) = 0; + + CV_WRAP virtual int getWinSize() const = 0; + CV_WRAP virtual void setWinSize(int winSize) = 0; + + CV_WRAP virtual int getNumIters() const = 0; + CV_WRAP virtual void setNumIters(int numIters) = 0; + + CV_WRAP virtual int getPolyN() const = 0; + CV_WRAP virtual void setPolyN(int polyN) = 0; + + CV_WRAP virtual double getPolySigma() const = 0; + CV_WRAP virtual void setPolySigma(double polySigma) = 0; + + CV_WRAP virtual int getFlags() const = 0; + CV_WRAP virtual void setFlags(int flags) = 0; + + CV_WRAP static Ptr create( + int numLevels = 5, + double pyrScale = 0.5, + bool fastPyramids = false, + int winSize = 13, + int numIters = 10, + int polyN = 5, + double polySigma = 1.1, + int flags = 0); +}; + + +/** @brief Class used for calculating a sparse optical flow. + +The class can calculate an optical flow for a sparse feature set using the +iterative Lucas-Kanade method with pyramids. + +@sa calcOpticalFlowPyrLK + +*/ +class CV_EXPORTS_W SparsePyrLKOpticalFlow : public SparseOpticalFlow +{ +public: + CV_WRAP virtual Size getWinSize() const = 0; + CV_WRAP virtual void setWinSize(Size winSize) = 0; + + CV_WRAP virtual int getMaxLevel() const = 0; + CV_WRAP virtual void setMaxLevel(int maxLevel) = 0; + + CV_WRAP virtual TermCriteria getTermCriteria() const = 0; + CV_WRAP virtual void setTermCriteria(TermCriteria& crit) = 0; + + CV_WRAP virtual int getFlags() const = 0; + CV_WRAP virtual void setFlags(int flags) = 0; + + CV_WRAP virtual double getMinEigThreshold() const = 0; + CV_WRAP virtual void setMinEigThreshold(double minEigThreshold) = 0; + + CV_WRAP static Ptr create( + Size winSize = Size(21, 21), + int maxLevel = 3, TermCriteria crit = + TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), + int flags = 0, + double minEigThreshold = 1e-4); +}; + //! @} video_track } // cv diff --git a/include/opencv2/video/tracking_c.h b/include/opencv2/video/tracking_c.h index b355352..3e32fbd 100644 --- a/include/opencv2/video/tracking_c.h +++ b/include/opencv2/video/tracking_c.h @@ -41,8 +41,8 @@ // //M*/ -#ifndef __OPENCV_TRACKING_C_H__ -#define __OPENCV_TRACKING_C_H__ +#ifndef OPENCV_TRACKING_C_H +#define OPENCV_TRACKING_C_H #include "opencv2/imgproc/types_c.h" @@ -229,4 +229,4 @@ CVAPI(const CvMat*) cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement #endif -#endif // __OPENCV_TRACKING_C_H__ +#endif // OPENCV_TRACKING_C_H diff --git a/include/opencv2/videoio.hpp b/include/opencv2/videoio.hpp index 2547e4c..cc639d6 100644 --- a/include/opencv2/videoio.hpp +++ b/include/opencv2/videoio.hpp @@ -40,17 +40,26 @@ // //M*/ -#ifndef __OPENCV_VIDEOIO_HPP__ -#define __OPENCV_VIDEOIO_HPP__ +#ifndef OPENCV_VIDEOIO_HPP +#define OPENCV_VIDEOIO_HPP #include "opencv2/core.hpp" /** - @defgroup videoio Media I/O + @defgroup videoio Video I/O + + @brief Read and write video or images sequence with OpenCV + + ### See also: + - @ref videoio_overview + - Tutorials: @ref tutorial_table_of_content_videoio @{ - @defgroup videoio_c C API - @defgroup videoio_ios iOS glue - @defgroup videoio_winrt WinRT glue + @defgroup videoio_flags_base Flags for video I/O + @defgroup videoio_flags_others Additional flags for video I/O API backends + @defgroup videoio_c C API for video I/O + @defgroup videoio_ios iOS glue for video I/O + @defgroup videoio_winrt WinRT glue for video I/O + @defgroup videoio_registry Query I/O API backends registry @} */ @@ -65,57 +74,82 @@ namespace cv //! @addtogroup videoio //! @{ -// Camera API -enum { CAP_ANY = 0, // autodetect - CAP_VFW = 200, // platform native - CAP_V4L = 200, - CAP_V4L2 = CAP_V4L, - CAP_FIREWARE = 300, // IEEE 1394 drivers - CAP_FIREWIRE = CAP_FIREWARE, - CAP_IEEE1394 = CAP_FIREWARE, - CAP_DC1394 = CAP_FIREWARE, - CAP_CMU1394 = CAP_FIREWARE, - CAP_QT = 500, // QuickTime - CAP_UNICAP = 600, // Unicap drivers - CAP_DSHOW = 700, // DirectShow (via videoInput) - CAP_PVAPI = 800, // PvAPI, Prosilica GigE SDK - CAP_OPENNI = 900, // OpenNI (for Kinect) - CAP_OPENNI_ASUS = 910, // OpenNI (for Asus Xtion) - CAP_ANDROID = 1000, // Android - not used - CAP_XIAPI = 1100, // XIMEA Camera API - CAP_AVFOUNDATION = 1200, // AVFoundation framework for iOS (OS X Lion will have the same API) - CAP_GIGANETIX = 1300, // Smartek Giganetix GigEVisionSDK - CAP_MSMF = 1400, // Microsoft Media Foundation (via videoInput) - CAP_WINRT = 1410, // Microsoft Windows Runtime using Media Foundation - CAP_INTELPERC = 1500, // Intel Perceptual Computing SDK - CAP_OPENNI2 = 1600, // OpenNI2 (for Kinect) - CAP_OPENNI2_ASUS = 1610, // OpenNI2 (for Asus Xtion and Occipital Structure sensors) - CAP_GPHOTO2 = 1700 // gPhoto2 connection +//! @addtogroup videoio_flags_base +//! @{ + + +/** @brief %VideoCapture API backends identifier. + +Select preferred API for a capture object. +To be used in the VideoCapture::VideoCapture() constructor or VideoCapture::open() + +@note Backends are available only if they have been built with your OpenCV binaries. +See @ref videoio_overview for more information. +*/ +enum VideoCaptureAPIs { + CAP_ANY = 0, //!< Auto detect == 0 + CAP_VFW = 200, //!< Video For Windows (platform native) + CAP_V4L = 200, //!< V4L/V4L2 capturing support via libv4l + CAP_V4L2 = CAP_V4L, //!< Same as CAP_V4L + CAP_FIREWIRE = 300, //!< IEEE 1394 drivers + CAP_FIREWARE = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE + CAP_IEEE1394 = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE + CAP_DC1394 = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE + CAP_CMU1394 = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE + CAP_QT = 500, //!< QuickTime + CAP_UNICAP = 600, //!< Unicap drivers + CAP_DSHOW = 700, //!< DirectShow (via videoInput) + CAP_PVAPI = 800, //!< PvAPI, Prosilica GigE SDK + CAP_OPENNI = 900, //!< OpenNI (for Kinect) + CAP_OPENNI_ASUS = 910, //!< OpenNI (for Asus Xtion) + CAP_ANDROID = 1000, //!< Android - not used + CAP_XIAPI = 1100, //!< XIMEA Camera API + CAP_AVFOUNDATION = 1200, //!< AVFoundation framework for iOS (OS X Lion will have the same API) + CAP_GIGANETIX = 1300, //!< Smartek Giganetix GigEVisionSDK + CAP_MSMF = 1400, //!< Microsoft Media Foundation (via videoInput) + CAP_WINRT = 1410, //!< Microsoft Windows Runtime using Media Foundation + CAP_INTELPERC = 1500, //!< Intel Perceptual Computing SDK + CAP_OPENNI2 = 1600, //!< OpenNI2 (for Kinect) + CAP_OPENNI2_ASUS = 1610, //!< OpenNI2 (for Asus Xtion and Occipital Structure sensors) + CAP_GPHOTO2 = 1700, //!< gPhoto2 connection + CAP_GSTREAMER = 1800, //!< GStreamer + CAP_FFMPEG = 1900, //!< Open and record video file or stream using the FFMPEG library + CAP_IMAGES = 2000, //!< OpenCV Image Sequence (e.g. img_%02d.jpg) + CAP_ARAVIS = 2100, //!< Aravis SDK + CAP_OPENCV_MJPEG = 2200, //!< Built-in OpenCV MotionJPEG codec + CAP_INTEL_MFX = 2300, //!< Intel MediaSDK + CAP_XINE = 2400, //!< XINE engine (Linux) }; -// generic properties (based on DC1394 properties) -enum { CAP_PROP_POS_MSEC =0, - CAP_PROP_POS_FRAMES =1, - CAP_PROP_POS_AVI_RATIO =2, - CAP_PROP_FRAME_WIDTH =3, - CAP_PROP_FRAME_HEIGHT =4, - CAP_PROP_FPS =5, - CAP_PROP_FOURCC =6, - CAP_PROP_FRAME_COUNT =7, - CAP_PROP_FORMAT =8, - CAP_PROP_MODE =9, - CAP_PROP_BRIGHTNESS =10, - CAP_PROP_CONTRAST =11, - CAP_PROP_SATURATION =12, - CAP_PROP_HUE =13, - CAP_PROP_GAIN =14, - CAP_PROP_EXPOSURE =15, - CAP_PROP_CONVERT_RGB =16, - CAP_PROP_WHITE_BALANCE_BLUE_U =17, - CAP_PROP_RECTIFICATION =18, +/** @brief %VideoCapture generic properties identifier. + + Reading / writing properties involves many layers. Some unexpected result might happens along this chain. + Effective behaviour depends from device hardware, driver and API Backend. + @sa videoio_flags_others, VideoCapture::get(), VideoCapture::set() +*/ +enum VideoCaptureProperties { + CAP_PROP_POS_MSEC =0, //!< Current position of the video file in milliseconds. + CAP_PROP_POS_FRAMES =1, //!< 0-based index of the frame to be decoded/captured next. + CAP_PROP_POS_AVI_RATIO =2, //!< Relative position of the video file: 0=start of the film, 1=end of the film. + CAP_PROP_FRAME_WIDTH =3, //!< Width of the frames in the video stream. + CAP_PROP_FRAME_HEIGHT =4, //!< Height of the frames in the video stream. + CAP_PROP_FPS =5, //!< Frame rate. + CAP_PROP_FOURCC =6, //!< 4-character code of codec. see VideoWriter::fourcc . + CAP_PROP_FRAME_COUNT =7, //!< Number of frames in the video file. + CAP_PROP_FORMAT =8, //!< Format of the %Mat objects returned by VideoCapture::retrieve(). + CAP_PROP_MODE =9, //!< Backend-specific value indicating the current capture mode. + CAP_PROP_BRIGHTNESS =10, //!< Brightness of the image (only for those cameras that support). + CAP_PROP_CONTRAST =11, //!< Contrast of the image (only for cameras). + CAP_PROP_SATURATION =12, //!< Saturation of the image (only for cameras). + CAP_PROP_HUE =13, //!< Hue of the image (only for cameras). + CAP_PROP_GAIN =14, //!< Gain of the image (only for those cameras that support). + CAP_PROP_EXPOSURE =15, //!< Exposure (only for those cameras that support). + CAP_PROP_CONVERT_RGB =16, //!< Boolean flags indicating whether images should be converted to RGB. + CAP_PROP_WHITE_BALANCE_BLUE_U =17, //!< Currently unsupported. + CAP_PROP_RECTIFICATION =18, //!< Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently). CAP_PROP_MONOCHROME =19, CAP_PROP_SHARPNESS =20, - CAP_PROP_AUTO_EXPOSURE =21, // DC1394: exposure control done by camera, user can adjust refernce level using this feature + CAP_PROP_AUTO_EXPOSURE =21, //!< DC1394: exposure control done by camera, user can adjust reference level using this feature. CAP_PROP_GAMMA =22, CAP_PROP_TEMPERATURE =23, CAP_PROP_TRIGGER =24, @@ -130,44 +164,81 @@ enum { CAP_PROP_POS_MSEC =0, CAP_PROP_TILT =34, CAP_PROP_ROLL =35, CAP_PROP_IRIS =36, - CAP_PROP_SETTINGS =37 + CAP_PROP_SETTINGS =37, //!< Pop up video/camera filter dialog (note: only supported by DSHOW backend currently. The property value is ignored) + CAP_PROP_BUFFERSIZE =38, + CAP_PROP_AUTOFOCUS =39, + CAP_PROP_SAR_NUM =40, //!< Sample aspect ratio: num/den (num) + CAP_PROP_SAR_DEN =41, //!< Sample aspect ratio: num/den (den) + CAP_PROP_BACKEND =42, //!< Current backend (enum VideoCaptureAPIs). Read-only property + CAP_PROP_CHANNEL =43, //!< Video input or Channel Number (only for those cameras that support) + CAP_PROP_AUTO_WB =44, //!< enable/ disable auto white-balance + CAP_PROP_WB_TEMPERATURE=45, //!< white-balance color temperature +#ifndef CV_DOXYGEN + CV__CAP_PROP_LATEST +#endif }; -// Generic camera output modes. -// Currently, these are supported through the libv4l interface only. -enum { CAP_MODE_BGR = 0, // BGR24 (default) - CAP_MODE_RGB = 1, // RGB24 - CAP_MODE_GRAY = 2, // Y8 - CAP_MODE_YUYV = 3 // YUYV +/** @brief Generic camera output modes identifier. +@note Currently, these are supported through the libv4l backend only. +*/ +enum VideoCaptureModes { + CAP_MODE_BGR = 0, //!< BGR24 (default) + CAP_MODE_RGB = 1, //!< RGB24 + CAP_MODE_GRAY = 2, //!< Y8 + CAP_MODE_YUYV = 3 //!< YUYV }; +/** @brief %VideoWriter generic properties identifier. + @sa VideoWriter::get(), VideoWriter::set() +*/ +enum VideoWriterProperties { + VIDEOWRITER_PROP_QUALITY = 1, //!< Current quality (0..100%) of the encoded videostream. Can be adjusted dynamically in some codecs. + VIDEOWRITER_PROP_FRAMEBYTES = 2, //!< (Read-only): Size of just encoded video frame. Note that the encoding order may be different from representation order. + VIDEOWRITER_PROP_NSTRIPES = 3 //!< Number of stripes for parallel encoding. -1 for auto detection. +}; -// DC1394 only -// modes of the controlling registers (can be: auto, manual, auto single push, absolute Latter allowed with any other mode) -// every feature can have only one mode turned on at a time -enum { CAP_PROP_DC1394_OFF = -4, //turn the feature off (not controlled manually nor automatically) - CAP_PROP_DC1394_MODE_MANUAL = -3, //set automatically when a value of the feature is set by the user +//! @} videoio_flags_base + +//! @addtogroup videoio_flags_others +//! @{ + +/** @name IEEE 1394 drivers + @{ +*/ + +/** @brief Modes of the IEEE 1394 controlling registers +(can be: auto, manual, auto single push, absolute Latter allowed with any other mode) +every feature can have only one mode turned on at a time +*/ +enum { CAP_PROP_DC1394_OFF = -4, //!< turn the feature off (not controlled manually nor automatically). + CAP_PROP_DC1394_MODE_MANUAL = -3, //!< set automatically when a value of the feature is set by the user. CAP_PROP_DC1394_MODE_AUTO = -2, CAP_PROP_DC1394_MODE_ONE_PUSH_AUTO = -1, CAP_PROP_DC1394_MAX = 31 }; +//! @} IEEE 1394 drivers -// OpenNI map generators +/** @name OpenNI (for Kinect) + @{ +*/ + +//! OpenNI map generators enum { CAP_OPENNI_DEPTH_GENERATOR = 1 << 31, CAP_OPENNI_IMAGE_GENERATOR = 1 << 30, - CAP_OPENNI_GENERATORS_MASK = CAP_OPENNI_DEPTH_GENERATOR + CAP_OPENNI_IMAGE_GENERATOR + CAP_OPENNI_IR_GENERATOR = 1 << 29, + CAP_OPENNI_GENERATORS_MASK = CAP_OPENNI_DEPTH_GENERATOR + CAP_OPENNI_IMAGE_GENERATOR + CAP_OPENNI_IR_GENERATOR }; -// Properties of cameras available through OpenNI interfaces +//! Properties of cameras available through OpenNI backend enum { CAP_PROP_OPENNI_OUTPUT_MODE = 100, - CAP_PROP_OPENNI_FRAME_MAX_DEPTH = 101, // in mm - CAP_PROP_OPENNI_BASELINE = 102, // in mm - CAP_PROP_OPENNI_FOCAL_LENGTH = 103, // in pixels - CAP_PROP_OPENNI_REGISTRATION = 104, // flag that synchronizes the remapping depth map to image map - // by changing depth generator's view point (if the flag is "on") or - // sets this view point to its normal one (if the flag is "off"). + CAP_PROP_OPENNI_FRAME_MAX_DEPTH = 101, //!< In mm + CAP_PROP_OPENNI_BASELINE = 102, //!< In mm + CAP_PROP_OPENNI_FOCAL_LENGTH = 103, //!< In pixels + CAP_PROP_OPENNI_REGISTRATION = 104, //!< Flag that synchronizes the remapping depth map to image map + //!< by changing depth generator's view point (if the flag is "on") or + //!< sets this view point to its normal one (if the flag is "off"). CAP_PROP_OPENNI_REGISTRATION_ON = CAP_PROP_OPENNI_REGISTRATION, CAP_PROP_OPENNI_APPROX_FRAME_SYNC = 105, CAP_PROP_OPENNI_MAX_BUFFER_SIZE = 106, @@ -178,28 +249,31 @@ enum { CAP_PROP_OPENNI_OUTPUT_MODE = 100, CAP_PROP_OPENNI2_MIRROR = 111 }; -// OpenNI shortcats +//! OpenNI shortcuts enum { CAP_OPENNI_IMAGE_GENERATOR_PRESENT = CAP_OPENNI_IMAGE_GENERATOR + CAP_PROP_OPENNI_GENERATOR_PRESENT, CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CAP_OPENNI_IMAGE_GENERATOR + CAP_PROP_OPENNI_OUTPUT_MODE, + CAP_OPENNI_DEPTH_GENERATOR_PRESENT = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_GENERATOR_PRESENT, CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_BASELINE, CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_FOCAL_LENGTH, CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_REGISTRATION, - CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION + CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION, + CAP_OPENNI_IR_GENERATOR_PRESENT = CAP_OPENNI_IR_GENERATOR + CAP_PROP_OPENNI_GENERATOR_PRESENT, }; -// OpenNI data given from depth generator -enum { CAP_OPENNI_DEPTH_MAP = 0, // Depth values in mm (CV_16UC1) - CAP_OPENNI_POINT_CLOUD_MAP = 1, // XYZ in meters (CV_32FC3) - CAP_OPENNI_DISPARITY_MAP = 2, // Disparity in pixels (CV_8UC1) - CAP_OPENNI_DISPARITY_MAP_32F = 3, // Disparity in pixels (CV_32FC1) - CAP_OPENNI_VALID_DEPTH_MASK = 4, // CV_8UC1 +//! OpenNI data given from depth generator +enum { CAP_OPENNI_DEPTH_MAP = 0, //!< Depth values in mm (CV_16UC1) + CAP_OPENNI_POINT_CLOUD_MAP = 1, //!< XYZ in meters (CV_32FC3) + CAP_OPENNI_DISPARITY_MAP = 2, //!< Disparity in pixels (CV_8UC1) + CAP_OPENNI_DISPARITY_MAP_32F = 3, //!< Disparity in pixels (CV_32FC1) + CAP_OPENNI_VALID_DEPTH_MASK = 4, //!< CV_8UC1 - // Data given from RGB image generator - CAP_OPENNI_BGR_IMAGE = 5, - CAP_OPENNI_GRAY_IMAGE = 6 + CAP_OPENNI_BGR_IMAGE = 5, //!< Data given from RGB image generator + CAP_OPENNI_GRAY_IMAGE = 6, //!< Data given from RGB image generator + + CAP_OPENNI_IR_IMAGE = 7 //!< Data given from IR image generator }; -// Supported output modes of OpenNI image generator +//! Supported output modes of OpenNI image generator enum { CAP_OPENNI_VGA_30HZ = 0, CAP_OPENNI_SXGA_15HZ = 1, CAP_OPENNI_SXGA_30HZ = 2, @@ -207,73 +281,224 @@ enum { CAP_OPENNI_VGA_30HZ = 0, CAP_OPENNI_QVGA_60HZ = 4 }; +//! @} OpenNI -// GStreamer -enum { CAP_PROP_GSTREAMER_QUEUE_LENGTH = 200 // default is 1 +/** @name GStreamer + @{ +*/ + +enum { CAP_PROP_GSTREAMER_QUEUE_LENGTH = 200 //!< Default is 1 }; +//! @} GStreamer -// PVAPI -enum { CAP_PROP_PVAPI_MULTICASTIP = 300, // ip for anable multicast master mode. 0 for disable multicast - CAP_PROP_PVAPI_FRAMESTARTTRIGGERMODE = 301, // FrameStartTriggerMode: Determines how a frame is initiated - CAP_PROP_PVAPI_DECIMATIONHORIZONTAL = 302, // Horizontal sub-sampling of the image - CAP_PROP_PVAPI_DECIMATIONVERTICAL = 303, // Vertical sub-sampling of the image - CAP_PROP_PVAPI_BINNINGX = 304, // Horizontal binning factor - CAP_PROP_PVAPI_BINNINGY = 305, // Vertical binning factor - CAP_PROP_PVAPI_PIXELFORMAT = 306 // Pixel format +/** @name PvAPI, Prosilica GigE SDK + @{ +*/ + +//! PVAPI +enum { CAP_PROP_PVAPI_MULTICASTIP = 300, //!< IP for enable multicast master mode. 0 for disable multicast. + CAP_PROP_PVAPI_FRAMESTARTTRIGGERMODE = 301, //!< FrameStartTriggerMode: Determines how a frame is initiated. + CAP_PROP_PVAPI_DECIMATIONHORIZONTAL = 302, //!< Horizontal sub-sampling of the image. + CAP_PROP_PVAPI_DECIMATIONVERTICAL = 303, //!< Vertical sub-sampling of the image. + CAP_PROP_PVAPI_BINNINGX = 304, //!< Horizontal binning factor. + CAP_PROP_PVAPI_BINNINGY = 305, //!< Vertical binning factor. + CAP_PROP_PVAPI_PIXELFORMAT = 306 //!< Pixel format. }; -// PVAPI: FrameStartTriggerMode -enum { CAP_PVAPI_FSTRIGMODE_FREERUN = 0, // Freerun - CAP_PVAPI_FSTRIGMODE_SYNCIN1 = 1, // SyncIn1 - CAP_PVAPI_FSTRIGMODE_SYNCIN2 = 2, // SyncIn2 - CAP_PVAPI_FSTRIGMODE_FIXEDRATE = 3, // FixedRate - CAP_PVAPI_FSTRIGMODE_SOFTWARE = 4 // Software +//! PVAPI: FrameStartTriggerMode +enum { CAP_PVAPI_FSTRIGMODE_FREERUN = 0, //!< Freerun + CAP_PVAPI_FSTRIGMODE_SYNCIN1 = 1, //!< SyncIn1 + CAP_PVAPI_FSTRIGMODE_SYNCIN2 = 2, //!< SyncIn2 + CAP_PVAPI_FSTRIGMODE_FIXEDRATE = 3, //!< FixedRate + CAP_PVAPI_FSTRIGMODE_SOFTWARE = 4 //!< Software }; -// PVAPI: DecimationHorizontal, DecimationVertical -enum { CAP_PVAPI_DECIMATION_OFF = 1, // Off - CAP_PVAPI_DECIMATION_2OUTOF4 = 2, // 2 out of 4 decimation - CAP_PVAPI_DECIMATION_2OUTOF8 = 4, // 2 out of 8 decimation - CAP_PVAPI_DECIMATION_2OUTOF16 = 8 // 2 out of 16 decimation +//! PVAPI: DecimationHorizontal, DecimationVertical +enum { CAP_PVAPI_DECIMATION_OFF = 1, //!< Off + CAP_PVAPI_DECIMATION_2OUTOF4 = 2, //!< 2 out of 4 decimation + CAP_PVAPI_DECIMATION_2OUTOF8 = 4, //!< 2 out of 8 decimation + CAP_PVAPI_DECIMATION_2OUTOF16 = 8 //!< 2 out of 16 decimation }; -// PVAPI: PixelFormat -enum { CAP_PVAPI_PIXELFORMAT_MONO8 = 1, // Mono8 - CAP_PVAPI_PIXELFORMAT_MONO16 = 2, // Mono16 - CAP_PVAPI_PIXELFORMAT_BAYER8 = 3, // Bayer8 - CAP_PVAPI_PIXELFORMAT_BAYER16 = 4, // Bayer16 - CAP_PVAPI_PIXELFORMAT_RGB24 = 5, // Rgb24 - CAP_PVAPI_PIXELFORMAT_BGR24 = 6, // Bgr24 - CAP_PVAPI_PIXELFORMAT_RGBA32 = 7, // Rgba32 - CAP_PVAPI_PIXELFORMAT_BGRA32 = 8, // Bgra32 +//! PVAPI: PixelFormat +enum { CAP_PVAPI_PIXELFORMAT_MONO8 = 1, //!< Mono8 + CAP_PVAPI_PIXELFORMAT_MONO16 = 2, //!< Mono16 + CAP_PVAPI_PIXELFORMAT_BAYER8 = 3, //!< Bayer8 + CAP_PVAPI_PIXELFORMAT_BAYER16 = 4, //!< Bayer16 + CAP_PVAPI_PIXELFORMAT_RGB24 = 5, //!< Rgb24 + CAP_PVAPI_PIXELFORMAT_BGR24 = 6, //!< Bgr24 + CAP_PVAPI_PIXELFORMAT_RGBA32 = 7, //!< Rgba32 + CAP_PVAPI_PIXELFORMAT_BGRA32 = 8, //!< Bgra32 }; -// Properties of cameras available through XIMEA SDK interface -enum { CAP_PROP_XI_DOWNSAMPLING = 400, // Change image resolution by binning or skipping. - CAP_PROP_XI_DATA_FORMAT = 401, // Output data format. - CAP_PROP_XI_OFFSET_X = 402, // Horizontal offset from the origin to the area of interest (in pixels). - CAP_PROP_XI_OFFSET_Y = 403, // Vertical offset from the origin to the area of interest (in pixels). - CAP_PROP_XI_TRG_SOURCE = 404, // Defines source of trigger. - CAP_PROP_XI_TRG_SOFTWARE = 405, // Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE. - CAP_PROP_XI_GPI_SELECTOR = 406, // Selects general purpose input - CAP_PROP_XI_GPI_MODE = 407, // Set general purpose input mode - CAP_PROP_XI_GPI_LEVEL = 408, // Get general purpose level - CAP_PROP_XI_GPO_SELECTOR = 409, // Selects general purpose output - CAP_PROP_XI_GPO_MODE = 410, // Set general purpose output mode - CAP_PROP_XI_LED_SELECTOR = 411, // Selects camera signalling LED - CAP_PROP_XI_LED_MODE = 412, // Define camera signalling LED functionality - CAP_PROP_XI_MANUAL_WB = 413, // Calculates White Balance(must be called during acquisition) - CAP_PROP_XI_AUTO_WB = 414, // Automatic white balance - CAP_PROP_XI_AEAG = 415, // Automatic exposure/gain - CAP_PROP_XI_EXP_PRIORITY = 416, // Exposure priority (0.5 - exposure 50%, gain 50%). - CAP_PROP_XI_AE_MAX_LIMIT = 417, // Maximum limit of exposure in AEAG procedure - CAP_PROP_XI_AG_MAX_LIMIT = 418, // Maximum limit of gain in AEAG procedure - CAP_PROP_XI_AEAG_LEVEL = 419, // Average intensity of output signal AEAG should achieve(in %) - CAP_PROP_XI_TIMEOUT = 420 // Image capture timeout in milliseconds +//! @} PvAPI + +/** @name XIMEA Camera API + @{ +*/ + +//! Properties of cameras available through XIMEA SDK backend +enum { CAP_PROP_XI_DOWNSAMPLING = 400, //!< Change image resolution by binning or skipping. + CAP_PROP_XI_DATA_FORMAT = 401, //!< Output data format. + CAP_PROP_XI_OFFSET_X = 402, //!< Horizontal offset from the origin to the area of interest (in pixels). + CAP_PROP_XI_OFFSET_Y = 403, //!< Vertical offset from the origin to the area of interest (in pixels). + CAP_PROP_XI_TRG_SOURCE = 404, //!< Defines source of trigger. + CAP_PROP_XI_TRG_SOFTWARE = 405, //!< Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE. + CAP_PROP_XI_GPI_SELECTOR = 406, //!< Selects general purpose input. + CAP_PROP_XI_GPI_MODE = 407, //!< Set general purpose input mode. + CAP_PROP_XI_GPI_LEVEL = 408, //!< Get general purpose level. + CAP_PROP_XI_GPO_SELECTOR = 409, //!< Selects general purpose output. + CAP_PROP_XI_GPO_MODE = 410, //!< Set general purpose output mode. + CAP_PROP_XI_LED_SELECTOR = 411, //!< Selects camera signalling LED. + CAP_PROP_XI_LED_MODE = 412, //!< Define camera signalling LED functionality. + CAP_PROP_XI_MANUAL_WB = 413, //!< Calculates White Balance(must be called during acquisition). + CAP_PROP_XI_AUTO_WB = 414, //!< Automatic white balance. + CAP_PROP_XI_AEAG = 415, //!< Automatic exposure/gain. + CAP_PROP_XI_EXP_PRIORITY = 416, //!< Exposure priority (0.5 - exposure 50%, gain 50%). + CAP_PROP_XI_AE_MAX_LIMIT = 417, //!< Maximum limit of exposure in AEAG procedure. + CAP_PROP_XI_AG_MAX_LIMIT = 418, //!< Maximum limit of gain in AEAG procedure. + CAP_PROP_XI_AEAG_LEVEL = 419, //!< Average intensity of output signal AEAG should achieve(in %). + CAP_PROP_XI_TIMEOUT = 420, //!< Image capture timeout in milliseconds. + CAP_PROP_XI_EXPOSURE = 421, //!< Exposure time in microseconds. + CAP_PROP_XI_EXPOSURE_BURST_COUNT = 422, //!< Sets the number of times of exposure in one frame. + CAP_PROP_XI_GAIN_SELECTOR = 423, //!< Gain selector for parameter Gain allows to select different type of gains. + CAP_PROP_XI_GAIN = 424, //!< Gain in dB. + CAP_PROP_XI_DOWNSAMPLING_TYPE = 426, //!< Change image downsampling type. + CAP_PROP_XI_BINNING_SELECTOR = 427, //!< Binning engine selector. + CAP_PROP_XI_BINNING_VERTICAL = 428, //!< Vertical Binning - number of vertical photo-sensitive cells to combine together. + CAP_PROP_XI_BINNING_HORIZONTAL = 429, //!< Horizontal Binning - number of horizontal photo-sensitive cells to combine together. + CAP_PROP_XI_BINNING_PATTERN = 430, //!< Binning pattern type. + CAP_PROP_XI_DECIMATION_SELECTOR = 431, //!< Decimation engine selector. + CAP_PROP_XI_DECIMATION_VERTICAL = 432, //!< Vertical Decimation - vertical sub-sampling of the image - reduces the vertical resolution of the image by the specified vertical decimation factor. + CAP_PROP_XI_DECIMATION_HORIZONTAL = 433, //!< Horizontal Decimation - horizontal sub-sampling of the image - reduces the horizontal resolution of the image by the specified vertical decimation factor. + CAP_PROP_XI_DECIMATION_PATTERN = 434, //!< Decimation pattern type. + CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR = 587, //!< Selects which test pattern generator is controlled by the TestPattern feature. + CAP_PROP_XI_TEST_PATTERN = 588, //!< Selects which test pattern type is generated by the selected generator. + CAP_PROP_XI_IMAGE_DATA_FORMAT = 435, //!< Output data format. + CAP_PROP_XI_SHUTTER_TYPE = 436, //!< Change sensor shutter type(CMOS sensor). + CAP_PROP_XI_SENSOR_TAPS = 437, //!< Number of taps. + CAP_PROP_XI_AEAG_ROI_OFFSET_X = 439, //!< Automatic exposure/gain ROI offset X. + CAP_PROP_XI_AEAG_ROI_OFFSET_Y = 440, //!< Automatic exposure/gain ROI offset Y. + CAP_PROP_XI_AEAG_ROI_WIDTH = 441, //!< Automatic exposure/gain ROI Width. + CAP_PROP_XI_AEAG_ROI_HEIGHT = 442, //!< Automatic exposure/gain ROI Height. + CAP_PROP_XI_BPC = 445, //!< Correction of bad pixels. + CAP_PROP_XI_WB_KR = 448, //!< White balance red coefficient. + CAP_PROP_XI_WB_KG = 449, //!< White balance green coefficient. + CAP_PROP_XI_WB_KB = 450, //!< White balance blue coefficient. + CAP_PROP_XI_WIDTH = 451, //!< Width of the Image provided by the device (in pixels). + CAP_PROP_XI_HEIGHT = 452, //!< Height of the Image provided by the device (in pixels). + CAP_PROP_XI_REGION_SELECTOR = 589, //!< Selects Region in Multiple ROI which parameters are set by width, height, ... ,region mode. + CAP_PROP_XI_REGION_MODE = 595, //!< Activates/deactivates Region selected by Region Selector. + CAP_PROP_XI_LIMIT_BANDWIDTH = 459, //!< Set/get bandwidth(datarate)(in Megabits). + CAP_PROP_XI_SENSOR_DATA_BIT_DEPTH = 460, //!< Sensor output data bit depth. + CAP_PROP_XI_OUTPUT_DATA_BIT_DEPTH = 461, //!< Device output data bit depth. + CAP_PROP_XI_IMAGE_DATA_BIT_DEPTH = 462, //!< bitdepth of data returned by function xiGetImage. + CAP_PROP_XI_OUTPUT_DATA_PACKING = 463, //!< Device output data packing (or grouping) enabled. Packing could be enabled if output_data_bit_depth > 8 and packing capability is available. + CAP_PROP_XI_OUTPUT_DATA_PACKING_TYPE = 464, //!< Data packing type. Some cameras supports only specific packing type. + CAP_PROP_XI_IS_COOLED = 465, //!< Returns 1 for cameras that support cooling. + CAP_PROP_XI_COOLING = 466, //!< Start camera cooling. + CAP_PROP_XI_TARGET_TEMP = 467, //!< Set sensor target temperature for cooling. + CAP_PROP_XI_CHIP_TEMP = 468, //!< Camera sensor temperature. + CAP_PROP_XI_HOUS_TEMP = 469, //!< Camera housing temperature. + CAP_PROP_XI_HOUS_BACK_SIDE_TEMP = 590, //!< Camera housing back side temperature. + CAP_PROP_XI_SENSOR_BOARD_TEMP = 596, //!< Camera sensor board temperature. + CAP_PROP_XI_CMS = 470, //!< Mode of color management system. + CAP_PROP_XI_APPLY_CMS = 471, //!< Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE). + CAP_PROP_XI_IMAGE_IS_COLOR = 474, //!< Returns 1 for color cameras. + CAP_PROP_XI_COLOR_FILTER_ARRAY = 475, //!< Returns color filter array type of RAW data. + CAP_PROP_XI_GAMMAY = 476, //!< Luminosity gamma. + CAP_PROP_XI_GAMMAC = 477, //!< Chromaticity gamma. + CAP_PROP_XI_SHARPNESS = 478, //!< Sharpness Strength. + CAP_PROP_XI_CC_MATRIX_00 = 479, //!< Color Correction Matrix element [0][0]. + CAP_PROP_XI_CC_MATRIX_01 = 480, //!< Color Correction Matrix element [0][1]. + CAP_PROP_XI_CC_MATRIX_02 = 481, //!< Color Correction Matrix element [0][2]. + CAP_PROP_XI_CC_MATRIX_03 = 482, //!< Color Correction Matrix element [0][3]. + CAP_PROP_XI_CC_MATRIX_10 = 483, //!< Color Correction Matrix element [1][0]. + CAP_PROP_XI_CC_MATRIX_11 = 484, //!< Color Correction Matrix element [1][1]. + CAP_PROP_XI_CC_MATRIX_12 = 485, //!< Color Correction Matrix element [1][2]. + CAP_PROP_XI_CC_MATRIX_13 = 486, //!< Color Correction Matrix element [1][3]. + CAP_PROP_XI_CC_MATRIX_20 = 487, //!< Color Correction Matrix element [2][0]. + CAP_PROP_XI_CC_MATRIX_21 = 488, //!< Color Correction Matrix element [2][1]. + CAP_PROP_XI_CC_MATRIX_22 = 489, //!< Color Correction Matrix element [2][2]. + CAP_PROP_XI_CC_MATRIX_23 = 490, //!< Color Correction Matrix element [2][3]. + CAP_PROP_XI_CC_MATRIX_30 = 491, //!< Color Correction Matrix element [3][0]. + CAP_PROP_XI_CC_MATRIX_31 = 492, //!< Color Correction Matrix element [3][1]. + CAP_PROP_XI_CC_MATRIX_32 = 493, //!< Color Correction Matrix element [3][2]. + CAP_PROP_XI_CC_MATRIX_33 = 494, //!< Color Correction Matrix element [3][3]. + CAP_PROP_XI_DEFAULT_CC_MATRIX = 495, //!< Set default Color Correction Matrix. + CAP_PROP_XI_TRG_SELECTOR = 498, //!< Selects the type of trigger. + CAP_PROP_XI_ACQ_FRAME_BURST_COUNT = 499, //!< Sets number of frames acquired by burst. This burst is used only if trigger is set to FrameBurstStart. + CAP_PROP_XI_DEBOUNCE_EN = 507, //!< Enable/Disable debounce to selected GPI. + CAP_PROP_XI_DEBOUNCE_T0 = 508, //!< Debounce time (x * 10us). + CAP_PROP_XI_DEBOUNCE_T1 = 509, //!< Debounce time (x * 10us). + CAP_PROP_XI_DEBOUNCE_POL = 510, //!< Debounce polarity (pol = 1 t0 - falling edge, t1 - rising edge). + CAP_PROP_XI_LENS_MODE = 511, //!< Status of lens control interface. This shall be set to XI_ON before any Lens operations. + CAP_PROP_XI_LENS_APERTURE_VALUE = 512, //!< Current lens aperture value in stops. Examples: 2.8, 4, 5.6, 8, 11. + CAP_PROP_XI_LENS_FOCUS_MOVEMENT_VALUE = 513, //!< Lens current focus movement value to be used by XI_PRM_LENS_FOCUS_MOVE in motor steps. + CAP_PROP_XI_LENS_FOCUS_MOVE = 514, //!< Moves lens focus motor by steps set in XI_PRM_LENS_FOCUS_MOVEMENT_VALUE. + CAP_PROP_XI_LENS_FOCUS_DISTANCE = 515, //!< Lens focus distance in cm. + CAP_PROP_XI_LENS_FOCAL_LENGTH = 516, //!< Lens focal distance in mm. + CAP_PROP_XI_LENS_FEATURE_SELECTOR = 517, //!< Selects the current feature which is accessible by XI_PRM_LENS_FEATURE. + CAP_PROP_XI_LENS_FEATURE = 518, //!< Allows access to lens feature value currently selected by XI_PRM_LENS_FEATURE_SELECTOR. + CAP_PROP_XI_DEVICE_MODEL_ID = 521, //!< Returns device model id. + CAP_PROP_XI_DEVICE_SN = 522, //!< Returns device serial number. + CAP_PROP_XI_IMAGE_DATA_FORMAT_RGB32_ALPHA = 529, //!< The alpha channel of RGB32 output image format. + CAP_PROP_XI_IMAGE_PAYLOAD_SIZE = 530, //!< Buffer size in bytes sufficient for output image returned by xiGetImage. + CAP_PROP_XI_TRANSPORT_PIXEL_FORMAT = 531, //!< Current format of pixels on transport layer. + CAP_PROP_XI_SENSOR_CLOCK_FREQ_HZ = 532, //!< Sensor clock frequency in Hz. + CAP_PROP_XI_SENSOR_CLOCK_FREQ_INDEX = 533, //!< Sensor clock frequency index. Sensor with selected frequencies have possibility to set the frequency only by this index. + CAP_PROP_XI_SENSOR_OUTPUT_CHANNEL_COUNT = 534, //!< Number of output channels from sensor used for data transfer. + CAP_PROP_XI_FRAMERATE = 535, //!< Define framerate in Hz. + CAP_PROP_XI_COUNTER_SELECTOR = 536, //!< Select counter. + CAP_PROP_XI_COUNTER_VALUE = 537, //!< Counter status. + CAP_PROP_XI_ACQ_TIMING_MODE = 538, //!< Type of sensor frames timing. + CAP_PROP_XI_AVAILABLE_BANDWIDTH = 539, //!< Calculate and returns available interface bandwidth(int Megabits). + CAP_PROP_XI_BUFFER_POLICY = 540, //!< Data move policy. + CAP_PROP_XI_LUT_EN = 541, //!< Activates LUT. + CAP_PROP_XI_LUT_INDEX = 542, //!< Control the index (offset) of the coefficient to access in the LUT. + CAP_PROP_XI_LUT_VALUE = 543, //!< Value at entry LUTIndex of the LUT. + CAP_PROP_XI_TRG_DELAY = 544, //!< Specifies the delay in microseconds (us) to apply after the trigger reception before activating it. + CAP_PROP_XI_TS_RST_MODE = 545, //!< Defines how time stamp reset engine will be armed. + CAP_PROP_XI_TS_RST_SOURCE = 546, //!< Defines which source will be used for timestamp reset. Writing this parameter will trigger settings of engine (arming). + CAP_PROP_XI_IS_DEVICE_EXIST = 547, //!< Returns 1 if camera connected and works properly. + CAP_PROP_XI_ACQ_BUFFER_SIZE = 548, //!< Acquisition buffer size in buffer_size_unit. Default bytes. + CAP_PROP_XI_ACQ_BUFFER_SIZE_UNIT = 549, //!< Acquisition buffer size unit in bytes. Default 1. E.g. Value 1024 means that buffer_size is in KiBytes. + CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_SIZE = 550, //!< Acquisition transport buffer size in bytes. + CAP_PROP_XI_BUFFERS_QUEUE_SIZE = 551, //!< Queue of field/frame buffers. + CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_COMMIT = 552, //!< Number of buffers to commit to low level. + CAP_PROP_XI_RECENT_FRAME = 553, //!< GetImage returns most recent frame. + CAP_PROP_XI_DEVICE_RESET = 554, //!< Resets the camera to default state. + CAP_PROP_XI_COLUMN_FPN_CORRECTION = 555, //!< Correction of column FPN. + CAP_PROP_XI_ROW_FPN_CORRECTION = 591, //!< Correction of row FPN. + CAP_PROP_XI_SENSOR_MODE = 558, //!< Current sensor mode. Allows to select sensor mode by one integer. Setting of this parameter affects: image dimensions and downsampling. + CAP_PROP_XI_HDR = 559, //!< Enable High Dynamic Range feature. + CAP_PROP_XI_HDR_KNEEPOINT_COUNT = 560, //!< The number of kneepoints in the PWLR. + CAP_PROP_XI_HDR_T1 = 561, //!< Position of first kneepoint(in % of XI_PRM_EXPOSURE). + CAP_PROP_XI_HDR_T2 = 562, //!< Position of second kneepoint (in % of XI_PRM_EXPOSURE). + CAP_PROP_XI_KNEEPOINT1 = 563, //!< Value of first kneepoint (% of sensor saturation). + CAP_PROP_XI_KNEEPOINT2 = 564, //!< Value of second kneepoint (% of sensor saturation). + CAP_PROP_XI_IMAGE_BLACK_LEVEL = 565, //!< Last image black level counts. Can be used for Offline processing to recall it. + CAP_PROP_XI_HW_REVISION = 571, //!< Returns hardware revision number. + CAP_PROP_XI_DEBUG_LEVEL = 572, //!< Set debug level. + CAP_PROP_XI_AUTO_BANDWIDTH_CALCULATION = 573, //!< Automatic bandwidth calculation. + CAP_PROP_XI_FFS_FILE_ID = 594, //!< File number. + CAP_PROP_XI_FFS_FILE_SIZE = 580, //!< Size of file. + CAP_PROP_XI_FREE_FFS_SIZE = 581, //!< Size of free camera FFS. + CAP_PROP_XI_USED_FFS_SIZE = 582, //!< Size of used camera FFS. + CAP_PROP_XI_FFS_ACCESS_KEY = 583, //!< Setting of key enables file operations on some cameras. + CAP_PROP_XI_SENSOR_FEATURE_SELECTOR = 585, //!< Selects the current feature which is accessible by XI_PRM_SENSOR_FEATURE_VALUE. + CAP_PROP_XI_SENSOR_FEATURE_VALUE = 586, //!< Allows access to sensor feature value currently selected by XI_PRM_SENSOR_FEATURE_SELECTOR. }; -// Properties of cameras available through AVFOUNDATION interface +//! @} XIMEA + +/** @name AVFoundation framework for iOS + OS X Lion will have the same API + @{ +*/ + +//! Properties of cameras available through AVFOUNDATION backend enum { CAP_PROP_IOS_DEVICE_FOCUS = 9001, CAP_PROP_IOS_DEVICE_EXPOSURE = 9002, CAP_PROP_IOS_DEVICE_FLASH = 9003, @@ -281,8 +506,11 @@ enum { CAP_PROP_IOS_DEVICE_FOCUS = 9001, CAP_PROP_IOS_DEVICE_TORCH = 9005 }; +/** @name Smartek Giganetix GigEVisionSDK + @{ +*/ -// Properties of cameras available through Smartek Giganetix Ethernet Vision interface +//! Properties of cameras available through Smartek Giganetix Ethernet Vision backend /* --- Vladimir Litvinenko (litvinenko.vladimir@gmail.com) --- */ enum { CAP_PROP_GIGA_FRAME_OFFSET_X = 10001, CAP_PROP_GIGA_FRAME_OFFSET_Y = 10002, @@ -292,6 +520,11 @@ enum { CAP_PROP_GIGA_FRAME_OFFSET_X = 10001, CAP_PROP_GIGA_FRAME_SENS_HEIGH = 10006 }; +//! @} Smartek + +/** @name Intel Perceptual Computing SDK + @{ +*/ enum { CAP_PROP_INTELPERC_PROFILE_COUNT = 11001, CAP_PROP_INTELPERC_PROFILE_IDX = 11002, CAP_PROP_INTELPERC_DEPTH_LOW_CONFIDENCE_VALUE = 11003, @@ -301,133 +534,184 @@ enum { CAP_PROP_INTELPERC_PROFILE_COUNT = 11001, CAP_PROP_INTELPERC_DEPTH_FOCAL_LENGTH_VERT = 11007 }; -// Intel PerC streams +//! Intel Perceptual Streams enum { CAP_INTELPERC_DEPTH_GENERATOR = 1 << 29, CAP_INTELPERC_IMAGE_GENERATOR = 1 << 28, CAP_INTELPERC_GENERATORS_MASK = CAP_INTELPERC_DEPTH_GENERATOR + CAP_INTELPERC_IMAGE_GENERATOR }; -enum { CAP_INTELPERC_DEPTH_MAP = 0, // Each pixel is a 16-bit integer. The value indicates the distance from an object to the camera's XY plane or the Cartesian depth. - CAP_INTELPERC_UVDEPTH_MAP = 1, // Each pixel contains two 32-bit floating point values in the range of 0-1, representing the mapping of depth coordinates to the color coordinates. - CAP_INTELPERC_IR_MAP = 2, // Each pixel is a 16-bit integer. The value indicates the intensity of the reflected laser beam. +enum { CAP_INTELPERC_DEPTH_MAP = 0, //!< Each pixel is a 16-bit integer. The value indicates the distance from an object to the camera's XY plane or the Cartesian depth. + CAP_INTELPERC_UVDEPTH_MAP = 1, //!< Each pixel contains two 32-bit floating point values in the range of 0-1, representing the mapping of depth coordinates to the color coordinates. + CAP_INTELPERC_IR_MAP = 2, //!< Each pixel is a 16-bit integer. The value indicates the intensity of the reflected laser beam. CAP_INTELPERC_IMAGE = 3 }; -enum { VIDEOWRITER_PROP_QUALITY = 1, // Quality (0..100%) of the videostream encoded - VIDEOWRITER_PROP_FRAMEBYTES = 2, // (Read-only): Size of just encoded video frame +//! @} Intel Perceptual + +/** @name gPhoto2 connection + @{ +*/ + +/** @brief gPhoto2 properties + +If `propertyId` is less than 0 then work on widget with that __additive inversed__ camera setting ID +Get IDs by using CAP_PROP_GPHOTO2_WIDGET_ENUMERATE. +@see CvCaptureCAM_GPHOTO2 for more info +*/ +enum { CAP_PROP_GPHOTO2_PREVIEW = 17001, //!< Capture only preview from liveview mode. + CAP_PROP_GPHOTO2_WIDGET_ENUMERATE = 17002, //!< Readonly, returns (const char *). + CAP_PROP_GPHOTO2_RELOAD_CONFIG = 17003, //!< Trigger, only by set. Reload camera settings. + CAP_PROP_GPHOTO2_RELOAD_ON_CHANGE = 17004, //!< Reload all settings on set. + CAP_PROP_GPHOTO2_COLLECT_MSGS = 17005, //!< Collect messages with details. + CAP_PROP_GPHOTO2_FLUSH_MSGS = 17006, //!< Readonly, returns (const char *). + CAP_PROP_SPEED = 17007, //!< Exposure speed. Can be readonly, depends on camera program. + CAP_PROP_APERTURE = 17008, //!< Aperture. Can be readonly, depends on camera program. + CAP_PROP_EXPOSUREPROGRAM = 17009, //!< Camera exposure program. + CAP_PROP_VIEWFINDER = 17010 //!< Enter liveview mode. }; -// gPhoto2 properties, if propertyId is less than 0 then work on widget with that __additive inversed__ camera setting ID -// Get IDs by using CAP_PROP_GPHOTO2_WIDGET_ENUMERATE. -// @see CvCaptureCAM_GPHOTO2 for more info -enum { CAP_PROP_GPHOTO2_PREVIEW = 17001, // Capture only preview from liveview mode. - CAP_PROP_GPHOTO2_WIDGET_ENUMERATE = 17002, // Readonly, returns (const char *). - CAP_PROP_GPHOTO2_RELOAD_CONFIG = 17003, // Trigger, only by set. Reload camera settings. - CAP_PROP_GPHOTO2_RELOAD_ON_CHANGE = 17004, // Reload all settings on set. - CAP_PROP_GPHOTO2_COLLECT_MSGS = 17005, // Collect messages with details. - CAP_PROP_GPHOTO2_FLUSH_MSGS = 17006, // Readonly, returns (const char *). - CAP_PROP_SPEED = 17007, // Exposure speed. Can be readonly, depends on camera program. - CAP_PROP_APERTURE = 17008, // Aperture. Can be readonly, depends on camera program. - CAP_PROP_EXPOSUREPROGRAM = 17009, // Camera exposure program. - CAP_PROP_VIEWFINDER = 17010 // Enter liveview mode. +//! @} gPhoto2 + + +/** @name Images backend + @{ +*/ + +/** @brief Images backend properties + +*/ +enum { CAP_PROP_IMAGES_BASE = 18000, + CAP_PROP_IMAGES_LAST = 19000 // excluding }; -//enum { +//! @} Images + +//! @} videoio_flags_others + class IVideoCapture; -/** @brief Class for video capturing from video files, image sequences or cameras. The class provides C++ API -for capturing video from cameras or for reading video files and image sequences. Here is how the -class can be used: : -@code - #include "opencv2/opencv.hpp" +/** @brief Class for video capturing from video files, image sequences or cameras. - using namespace cv; +The class provides C++ API for capturing video from cameras or for reading video files and image sequences. - int main(int, char**) - { - VideoCapture cap(0); // open the default camera - if(!cap.isOpened()) // check if we succeeded - return -1; - - Mat edges; - namedWindow("edges",1); - for(;;) - { - Mat frame; - cap >> frame; // get a new frame from camera - cvtColor(frame, edges, COLOR_BGR2GRAY); - GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5); - Canny(edges, edges, 0, 30, 3); - imshow("edges", edges); - if(waitKey(30) >= 0) break; - } - // the camera will be deinitialized automatically in VideoCapture destructor - return 0; - } -@endcode -@note In C API the black-box structure CvCapture is used instead of VideoCapture. +Here is how the class can be used: +@include samples/cpp/videocapture_basic.cpp +@note In @ref videoio_c "C API" the black-box structure `CvCapture` is used instead of %VideoCapture. @note -- A basic sample on using the VideoCapture interface can be found at - opencv_source_code/samples/cpp/starter_video.cpp -- Another basic video processing sample can be found at - opencv_source_code/samples/cpp/video_dmtx.cpp -- (Python) A basic sample on using the VideoCapture interface can be found at - opencv_source_code/samples/python2/video.py -- (Python) Another basic video processing sample can be found at - opencv_source_code/samples/python2/video_dmtx.py +- (C++) A basic sample on using the %VideoCapture interface can be found at + `OPENCV_SOURCE_CODE/samples/cpp/videocapture_starter.cpp` +- (Python) A basic sample on using the %VideoCapture interface can be found at + `OPENCV_SOURCE_CODE/samples/python/video.py` - (Python) A multi threaded video processing sample can be found at - opencv_source_code/samples/python2/video_threaded.py + `OPENCV_SOURCE_CODE/samples/python/video_threaded.py` +- (Python) %VideoCapture sample showcasing some features of the Video4Linux2 backend + `OPENCV_SOURCE_CODE/samples/python/video_v4l2.py` */ class CV_EXPORTS_W VideoCapture { public: - /** @brief - @note In C API, when you finished working with video, release CvCapture structure with + /** @brief Default constructor + @note In @ref videoio_c "C API", when you finished working with video, release CvCapture structure with cvReleaseCapture(), or use Ptr\ that calls cvReleaseCapture() automatically in the destructor. */ CV_WRAP VideoCapture(); /** @overload - @param filename name of the opened video file (eg. video.avi) or image sequence (eg. - img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...) + @brief Open video file or a capturing device or a IP video stream for video capturing + + Same as VideoCapture(const String& filename, int apiPreference) but using default Capture API backends */ CV_WRAP VideoCapture(const String& filename); /** @overload - @param device id of the opened video capturing device (i.e. a camera index). If there is a single - camera connected, just pass 0. - */ - CV_WRAP VideoCapture(int device); + @brief Open video file or a capturing device or a IP video stream for video capturing with API Preference + @param filename it can be: + - name of video file (eg. `video.avi`) + - or image sequence (eg. `img_%02d.jpg`, which will read samples like `img_00.jpg, img_01.jpg, img_02.jpg, ...`) + - or URL of video stream (eg. `protocol://host:port/script_name?script_params|auth`). + Note that each video stream or IP camera feed has its own URL scheme. Please refer to the + documentation of source stream to know the right URL. + @param apiPreference preferred Capture API backends to use. Can be used to enforce a specific reader + implementation if multiple are available: e.g. cv::CAP_FFMPEG or cv::CAP_IMAGES or cv::CAP_DSHOW. + @sa The list of supported API backends cv::VideoCaptureAPIs + */ + CV_WRAP VideoCapture(const String& filename, int apiPreference); + + /** @overload + @brief Open a camera for video capturing + + @param index camera_id + domain_offset (CAP_*) id of the video capturing device to open. To open default camera using default backend just pass 0. + Use a `domain_offset` to enforce a specific reader implementation if multiple are available like cv::CAP_FFMPEG or cv::CAP_IMAGES or cv::CAP_DSHOW. + e.g. to open Camera 1 using the MS Media Foundation API use `index = 1 + cv::CAP_MSMF` + + @sa The list of supported API backends cv::VideoCaptureAPIs + */ + CV_WRAP VideoCapture(int index); + + /** @overload + @brief Opens a camera for video capturing + + @param index id of the video capturing device to open. To open default camera using default backend just pass 0. + (to backward compatibility usage of camera_id + domain_offset (CAP_*) is valid when apiPreference is CAP_ANY) + @param apiPreference preferred Capture API backends to use. Can be used to enforce a specific reader + implementation if multiple are available: e.g. cv::CAP_DSHOW or cv::CAP_MSMF or cv::CAP_V4L2. + + @sa The list of supported API backends cv::VideoCaptureAPIs + */ + CV_WRAP VideoCapture(int index, int apiPreference); + + /** @brief Default destructor + + The method first calls VideoCapture::release to close the already opened file or camera. + */ virtual ~VideoCapture(); - /** @brief Open video file or a capturing device for video capturing + /** @brief Open video file or a capturing device or a IP video stream for video capturing - @param filename name of the opened video file (eg. video.avi) or image sequence (eg. - img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...) + @overload - The methods first call VideoCapture::release to close the already opened file or camera. + Parameters are same as the constructor VideoCapture(const String& filename) + @return `true` if the file has been successfully opened + + The method first calls VideoCapture::release to close the already opened file or camera. */ CV_WRAP virtual bool open(const String& filename); - /** @overload - @param device id of the opened video capturing device (i.e. a camera index). + /** @brief Open a camera for video capturing + + @overload + + Parameters are same as the constructor VideoCapture(int index) + @return `true` if the camera has been successfully opened. + + The method first calls VideoCapture::release to close the already opened file or camera. */ - CV_WRAP virtual bool open(int device); + CV_WRAP virtual bool open(int index); + + /** @brief Open a camera for video capturing + + @overload + + Parameters are similar as the constructor VideoCapture(int index),except it takes an additional argument apiPreference. + Definitely, is same as open(int index) where `index=cameraNum + apiPreference` + @return `true` if the camera has been successfully opened. + */ + CV_WRAP bool open(int cameraNum, int apiPreference); /** @brief Returns true if video capturing has been initialized already. - If the previous call to VideoCapture constructor or VideoCapture::open succeeded, the method returns + If the previous call to VideoCapture constructor or VideoCapture::open() succeeded, the method returns true. */ CV_WRAP virtual bool isOpened() const; /** @brief Closes video file or capturing device. - The methods are automatically called by subsequent VideoCapture::open and by VideoCapture + The method is automatically called by subsequent VideoCapture::open and by VideoCapture destructor. The C function also deallocates memory and clears \*capture pointer. @@ -436,7 +720,9 @@ public: /** @brief Grabs the next frame from video file or capturing device. - The methods/functions grab the next frame from video file or camera and return true (non-zero) in + @return `true` (non-zero) in the case of success. + + The method/function grabs the next frame from video file or camera and returns true (non-zero) in the case of success. The primary use of the function is in multi-camera environments, especially when the cameras do not @@ -446,100 +732,104 @@ public: from different cameras will be closer in time. Also, when a connected camera is multi-head (for example, a stereo camera or a Kinect device), the - correct way of retrieving data from it is to call VideoCapture::grab first and then call - VideoCapture::retrieve one or more times with different values of the channel parameter. See - + correct way of retrieving data from it is to call VideoCapture::grab() first and then call + VideoCapture::retrieve() one or more times with different values of the channel parameter. + + @ref tutorial_kinect_openni */ CV_WRAP virtual bool grab(); /** @brief Decodes and returns the grabbed video frame. - The methods/functions decode and return the just grabbed frame. If no frames has been grabbed - (camera has been disconnected, or there are no more frames in video file), the methods return false - and the functions return NULL pointer. + @param [out] image the video frame is returned here. If no frames has been grabbed the image will be empty. + @param flag it could be a frame index or a driver specific flag + @return `false` if no frames has been grabbed - @note OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video + The method decodes and returns the just grabbed frame. If no frames has been grabbed + (camera has been disconnected, or there are no more frames in video file), the method returns false + and the function returns an empty image (with %cv::Mat, test it with Mat::empty()). + + @sa read() + + @note In @ref videoio_c "C API", functions cvRetrieveFrame() and cv.RetrieveFrame() return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using - :ocvcvCloneImage and then do whatever you want with the copy. + cvCloneImage and then do whatever you want with the copy. */ CV_WRAP virtual bool retrieve(OutputArray image, int flag = 0); + + /** @brief Stream operator to read the next video frame. + @sa read() + */ virtual VideoCapture& operator >> (CV_OUT Mat& image); + + /** @overload + @sa read() + */ virtual VideoCapture& operator >> (CV_OUT UMat& image); /** @brief Grabs, decodes and returns the next video frame. - The methods/functions combine VideoCapture::grab and VideoCapture::retrieve in one call. This is the - most convenient method for reading video files or capturing data from decode and return the just - grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more - frames in video file), the methods return false and the functions return NULL pointer. + @param [out] image the video frame is returned here. If no frames has been grabbed the image will be empty. + @return `false` if no frames has been grabbed - @note OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video + The method/function combines VideoCapture::grab() and VideoCapture::retrieve() in one call. This is the + most convenient method for reading video files or capturing data from decode and returns the just + grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more + frames in video file), the method returns false and the function returns empty image (with %cv::Mat, test it with Mat::empty()). + + @note In @ref videoio_c "C API", functions cvRetrieveFrame() and cv.RetrieveFrame() return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using - :ocvcvCloneImage and then do whatever you want with the copy. + cvCloneImage and then do whatever you want with the copy. */ CV_WRAP virtual bool read(OutputArray image); /** @brief Sets a property in the VideoCapture. - @param propId Property identifier. It can be one of the following: - - **CAP_PROP_POS_MSEC** Current position of the video file in milliseconds. - - **CAP_PROP_POS_FRAMES** 0-based index of the frame to be decoded/captured next. - - **CAP_PROP_POS_AVI_RATIO** Relative position of the video file: 0 - start of the - film, 1 - end of the film. - - **CAP_PROP_FRAME_WIDTH** Width of the frames in the video stream. - - **CAP_PROP_FRAME_HEIGHT** Height of the frames in the video stream. - - **CAP_PROP_FPS** Frame rate. - - **CAP_PROP_FOURCC** 4-character code of codec. - - **CAP_PROP_FRAME_COUNT** Number of frames in the video file. - - **CAP_PROP_FORMAT** Format of the Mat objects returned by retrieve() . - - **CAP_PROP_MODE** Backend-specific value indicating the current capture mode. - - **CAP_PROP_BRIGHTNESS** Brightness of the image (only for cameras). - - **CAP_PROP_CONTRAST** Contrast of the image (only for cameras). - - **CAP_PROP_SATURATION** Saturation of the image (only for cameras). - - **CAP_PROP_HUE** Hue of the image (only for cameras). - - **CAP_PROP_GAIN** Gain of the image (only for cameras). - - **CAP_PROP_EXPOSURE** Exposure (only for cameras). - - **CAP_PROP_CONVERT_RGB** Boolean flags indicating whether images should be converted - to RGB. - - **CAP_PROP_WHITE_BALANCE** Currently unsupported - - **CAP_PROP_RECTIFICATION** Rectification flag for stereo cameras (note: only supported - by DC1394 v 2.x backend currently) + @param propId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...) + or one from @ref videoio_flags_others @param value Value of the property. + @return `true` if the property is supported by backend used by the VideoCapture instance. + @note Even if it returns `true` this doesn't ensure that the property + value has been accepted by the capture device. See note in VideoCapture::get() */ CV_WRAP virtual bool set(int propId, double value); /** @brief Returns the specified VideoCapture property - @param propId Property identifier. It can be one of the following: - - **CAP_PROP_POS_MSEC** Current position of the video file in milliseconds or video - capture timestamp. - - **CAP_PROP_POS_FRAMES** 0-based index of the frame to be decoded/captured next. - - **CAP_PROP_POS_AVI_RATIO** Relative position of the video file: 0 - start of the - film, 1 - end of the film. - - **CAP_PROP_FRAME_WIDTH** Width of the frames in the video stream. - - **CAP_PROP_FRAME_HEIGHT** Height of the frames in the video stream. - - **CAP_PROP_FPS** Frame rate. - - **CAP_PROP_FOURCC** 4-character code of codec. - - **CAP_PROP_FRAME_COUNT** Number of frames in the video file. - - **CAP_PROP_FORMAT** Format of the Mat objects returned by retrieve() . - - **CAP_PROP_MODE** Backend-specific value indicating the current capture mode. - - **CAP_PROP_BRIGHTNESS** Brightness of the image (only for cameras). - - **CAP_PROP_CONTRAST** Contrast of the image (only for cameras). - - **CAP_PROP_SATURATION** Saturation of the image (only for cameras). - - **CAP_PROP_HUE** Hue of the image (only for cameras). - - **CAP_PROP_GAIN** Gain of the image (only for cameras). - - **CAP_PROP_EXPOSURE** Exposure (only for cameras). - - **CAP_PROP_CONVERT_RGB** Boolean flags indicating whether images should be converted - to RGB. - - **CAP_PROP_WHITE_BALANCE** Currently not supported - - **CAP_PROP_RECTIFICATION** Rectification flag for stereo cameras (note: only supported - by DC1394 v 2.x backend currently) + @param propId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...) + or one from @ref videoio_flags_others + @return Value for the specified property. Value 0 is returned when querying a property that is + not supported by the backend used by the VideoCapture instance. - @note When querying a property that is not supported by the backend used by the VideoCapture - class, value 0 is returned. - */ + @note Reading / writing properties involves many layers. Some unexpected result might happens + along this chain. + @code {.txt} + `VideoCapture -> API Backend -> Operating System -> Device Driver -> Device Hardware` + @endcode + The returned value might be different from what really used by the device or it could be encoded + using device dependent rules (eg. steps or percentage). Effective behaviour depends from device + driver and API Backend + + */ CV_WRAP virtual double get(int propId) const; + /** @brief Open video file or a capturing device or a IP video stream for video capturing with API Preference + + @overload + + Parameters are same as the constructor VideoCapture(const String& filename, int apiPreference) + @return `true` if the file has been successfully opened + + The method first calls VideoCapture::release to close the already opened file or camera. + */ + CV_WRAP virtual bool open(const String& filename, int apiPreference); + + /** @brief Returns used backend API name + + @note Stream should be opened. + */ + CV_WRAP String getBackendName() const; + protected: Ptr cap; Ptr icap; @@ -547,15 +837,27 @@ protected: class IVideoWriter; +/** @example samples/cpp/tutorial_code/videoio/video-write/video-write.cpp +Check @ref tutorial_video_write "the corresponding tutorial" for more details +*/ + +/** @example samples/cpp/videowriter_basic.cpp +An example using VideoCapture and VideoWriter class +*/ + /** @brief Video writer class. - */ + +The class provides C++ API for writing video files or image sequences. +*/ class CV_EXPORTS_W VideoWriter { public: - /** @brief VideoWriter constructors + /** @brief Default constructors - The constructors/functions initialize video writers. On Linux FFMPEG is used to write videos; on - Windows FFMPEG or VFW is used; on MacOSX QTKit is used. + The constructors/functions initialize video writers. + - On Linux FFMPEG is used to write videos; + - On Windows FFMPEG or VFW is used; + - On MacOSX QTKit is used. */ CV_WRAP VideoWriter(); @@ -564,72 +866,114 @@ public: @param fourcc 4-character code of codec used to compress the frames. For example, VideoWriter::fourcc('P','I','M','1') is a MPEG-1 codec, VideoWriter::fourcc('M','J','P','G') is a motion-jpeg codec etc. List of codes can be obtained at [Video Codecs by - FOURCC](http://www.fourcc.org/codecs.php) page. + FOURCC](http://www.fourcc.org/codecs.php) page. FFMPEG backend with MP4 container natively uses + other values as fourcc code: see [ObjectType](http://www.mp4ra.org/codecs.html), + so you may receive a warning message from OpenCV about fourcc code conversion. @param fps Framerate of the created video stream. @param frameSize Size of the video frames. @param isColor If it is not zero, the encoder will expect and encode color frames, otherwise it will work with grayscale frames (the flag is currently supported on Windows only). + + @b Tips: + - With some backends `fourcc=-1` pops up the codec selection dialog from the system. + - To save image sequence use a proper filename (eg. `img_%02d.jpg`) and `fourcc=0` + OR `fps=0`. Use uncompressed image format (eg. `img_%02d.BMP`) to save raw frames. + - Most codecs are lossy. If you want lossless video file you need to use a lossless codecs + (eg. FFMPEG FFV1, Huffman HFYU, Lagarith LAGS, etc...) + - If FFMPEG is enabled, using `codec=0; fps=0;` you can create an uncompressed (raw) video file. */ CV_WRAP VideoWriter(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true); + /** @overload + The `apiPreference` parameter allows to specify API backends to use. Can be used to enforce a specific reader implementation + if multiple are available: e.g. cv::CAP_FFMPEG or cv::CAP_GSTREAMER. + */ + CV_WRAP VideoWriter(const String& filename, int apiPreference, int fourcc, double fps, + Size frameSize, bool isColor = true); + + /** @brief Default destructor + + The method first calls VideoWriter::release to close the already opened file. + */ virtual ~VideoWriter(); /** @brief Initializes or reinitializes video writer. The method opens video writer. Parameters are the same as in the constructor VideoWriter::VideoWriter. + @return `true` if video writer has been successfully initialized + + The method first calls VideoWriter::release to close the already opened file. */ CV_WRAP virtual bool open(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true); + /** @overload + */ + CV_WRAP bool open(const String& filename, int apiPreference, int fourcc, double fps, + Size frameSize, bool isColor = true); + /** @brief Returns true if video writer has been successfully initialized. */ CV_WRAP virtual bool isOpened() const; /** @brief Closes the video writer. - The methods are automatically called by subsequent VideoWriter::open and by the VideoWriter + The method is automatically called by subsequent VideoWriter::open and by the VideoWriter destructor. */ CV_WRAP virtual void release(); + + /** @brief Stream operator to write the next video frame. + @sa write + */ virtual VideoWriter& operator << (const Mat& image); /** @brief Writes the next video frame - @param image The written frame + @param image The written frame. In general, color images are expected in BGR format. - The functions/methods write the specified image to video file. It must have the same size as has + The function/method writes the specified image to video file. It must have the same size as has been specified when opening the video writer. */ CV_WRAP virtual void write(const Mat& image); /** @brief Sets a property in the VideoWriter. - @param propId Property identifier. It can be one of the following: - - **VIDEOWRITER_PROP_QUALITY** Quality (0..100%) of the videostream encoded. Can be adjusted dynamically in some codecs. + @param propId Property identifier from cv::VideoWriterProperties (eg. cv::VIDEOWRITER_PROP_QUALITY) + or one of @ref videoio_flags_others + @param value Value of the property. + @return `true` if the property is supported by the backend used by the VideoWriter instance. */ CV_WRAP virtual bool set(int propId, double value); /** @brief Returns the specified VideoWriter property - @param propId Property identifier. It can be one of the following: - - **VIDEOWRITER_PROP_QUALITY** Current quality of the encoded videostream. - - **VIDEOWRITER_PROP_FRAMEBYTES** (Read-only) Size of just encoded video frame; note that the encoding order may be different from representation order. + @param propId Property identifier from cv::VideoWriterProperties (eg. cv::VIDEOWRITER_PROP_QUALITY) + or one of @ref videoio_flags_others - @note When querying a property that is not supported by the backend used by the VideoWriter - class, value 0 is returned. + @return Value for the specified property. Value 0 is returned when querying a property that is + not supported by the backend used by the VideoWriter instance. */ CV_WRAP virtual double get(int propId) const; /** @brief Concatenates 4 chars to a fourcc code + @return a fourcc code + This static method constructs the fourcc code of the codec to be used in the constructor VideoWriter::VideoWriter or VideoWriter::open. */ CV_WRAP static int fourcc(char c1, char c2, char c3, char c4); + /** @brief Returns used backend API name + + @note Stream should be opened. + */ + CV_WRAP String getBackendName() const; + protected: Ptr writer; Ptr iwriter; @@ -645,4 +989,4 @@ template<> CV_EXPORTS void DefaultDeleter::operator ()(CvVideoWri } // cv -#endif //__OPENCV_VIDEOIO_HPP__ +#endif //OPENCV_VIDEOIO_HPP diff --git a/include/opencv2/videoio/cap_ios.h b/include/opencv2/videoio/cap_ios.h index cf7f2e4..207ad46 100644 --- a/include/opencv2/videoio/cap_ios.h +++ b/include/opencv2/videoio/cap_ios.h @@ -39,38 +39,21 @@ @class CvAbstractCamera; -@interface CvAbstractCamera : NSObject +CV_EXPORTS @interface CvAbstractCamera : NSObject { - AVCaptureSession* captureSession; - AVCaptureConnection* videoCaptureConnection; - AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; - UIDeviceOrientation currentDeviceOrientation; BOOL cameraAvailable; - BOOL captureSessionLoaded; - BOOL running; - BOOL useAVCaptureVideoPreviewLayer; - - AVCaptureDevicePosition defaultAVCaptureDevicePosition; - AVCaptureVideoOrientation defaultAVCaptureVideoOrientation; - NSString *const defaultAVCaptureSessionPreset; - - int defaultFPS; - - UIView* parentView; - - int imageWidth; - int imageHeight; } -@property (nonatomic, retain) AVCaptureSession* captureSession; -@property (nonatomic, retain) AVCaptureConnection* videoCaptureConnection; +@property (nonatomic, strong) AVCaptureSession* captureSession; +@property (nonatomic, strong) AVCaptureConnection* videoCaptureConnection; @property (nonatomic, readonly) BOOL running; @property (nonatomic, readonly) BOOL captureSessionLoaded; @property (nonatomic, assign) int defaultFPS; +@property (nonatomic, readonly) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; @property (nonatomic, assign) AVCaptureDevicePosition defaultAVCaptureDevicePosition; @property (nonatomic, assign) AVCaptureVideoOrientation defaultAVCaptureVideoOrientation; @property (nonatomic, assign) BOOL useAVCaptureVideoPreviewLayer; @@ -79,24 +62,24 @@ @property (nonatomic, assign) int imageWidth; @property (nonatomic, assign) int imageHeight; -@property (nonatomic, retain) UIView* parentView; +@property (nonatomic, strong) UIView* parentView; -- (void)start; -- (void)stop; -- (void)switchCameras; +- CV_UNUSED(start); +- CV_UNUSED(stop); +- CV_UNUSED(switchCameras); - (id)initWithParentView:(UIView*)parent; -- (void)createCaptureOutput; -- (void)createVideoPreviewLayer; -- (void)updateOrientation; +- CV_UNUSED(createCaptureOutput); +- CV_UNUSED(createVideoPreviewLayer); +- CV_UNUSED(updateOrientation); -- (void)lockFocus; -- (void)unlockFocus; -- (void)lockExposure; -- (void)unlockExposure; -- (void)lockBalance; -- (void)unlockBalance; +- CV_UNUSED(lockFocus); +- CV_UNUSED(unlockFocus); +- CV_UNUSED(lockExposure); +- CV_UNUSED(unlockExposure); +- CV_UNUSED(lockBalance); +- CV_UNUSED(unlockBalance); @end @@ -104,7 +87,7 @@ @class CvVideoCamera; -@protocol CvVideoCameraDelegate +CV_EXPORTS @protocol CvVideoCameraDelegate #ifdef __cplusplus // delegate method for processing image frames @@ -113,38 +96,31 @@ @end -@interface CvVideoCamera : CvAbstractCamera +CV_EXPORTS @interface CvVideoCamera : CvAbstractCamera { AVCaptureVideoDataOutput *videoDataOutput; dispatch_queue_t videoDataOutputQueue; CALayer *customPreviewLayer; - BOOL grayscaleMode; - - BOOL recordVideo; - BOOL rotateVideo; - AVAssetWriterInput* recordAssetWriterInput; - AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; - AVAssetWriter* recordAssetWriter; - CMTime lastSampleTime; } -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; @property (nonatomic, assign) BOOL grayscaleMode; @property (nonatomic, assign) BOOL recordVideo; @property (nonatomic, assign) BOOL rotateVideo; -@property (nonatomic, retain) AVAssetWriterInput* recordAssetWriterInput; -@property (nonatomic, retain) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; -@property (nonatomic, retain) AVAssetWriter* recordAssetWriter; +@property (nonatomic, strong) AVAssetWriterInput* recordAssetWriterInput; +@property (nonatomic, strong) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; +@property (nonatomic, strong) AVAssetWriter* recordAssetWriter; - (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; -- (void)layoutPreviewLayer; -- (void)saveVideo; +- CV_UNUSED(layoutPreviewLayer); +- CV_UNUSED(saveVideo); - (NSURL *)videoFileURL; +- (NSString *)videoFileString; @end @@ -153,21 +129,21 @@ @class CvPhotoCamera; -@protocol CvPhotoCameraDelegate +CV_EXPORTS @protocol CvPhotoCameraDelegate - (void)photoCamera:(CvPhotoCamera*)photoCamera capturedImage:(UIImage *)image; - (void)photoCameraCancel:(CvPhotoCamera*)photoCamera; @end -@interface CvPhotoCamera : CvAbstractCamera +CV_EXPORTS @interface CvPhotoCamera : CvAbstractCamera { AVCaptureStillImageOutput *stillImageOutput; } -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; -- (void)takePicture; +- CV_UNUSED(takePicture); @end diff --git a/include/opencv2/videoio/registry.hpp b/include/opencv2/videoio/registry.hpp new file mode 100644 index 0000000..7404c68 --- /dev/null +++ b/include/opencv2/videoio/registry.hpp @@ -0,0 +1,44 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_VIDEOIO_REGISTRY_HPP +#define OPENCV_VIDEOIO_REGISTRY_HPP + +#include + +namespace cv { namespace videoio_registry { +/** @addtogroup videoio_registry +This section contains API description how to query/configure available Video I/O backends. + +Runtime configuration options: +- enable debug mode: `OPENCV_VIDEOIO_DEBUG=1` +- change backend priority: `OPENCV_VIDEOIO_PRIORITY_=9999` +- disable backend: `OPENCV_VIDEOIO_PRIORITY_=0` +- specify list of backends with high priority (>100000): `OPENCV_VIDEOIO_PRIORITY_LIST=FFMPEG,GSTREAMER` + +@{ + */ + + +/** @brief Returns backend API name or "unknown" +@param api backend ID (#VideoCaptureAPIs) +*/ +CV_EXPORTS_W cv::String getBackendName(VideoCaptureAPIs api); + +/** @brief Returns list of all builtin backends */ +CV_EXPORTS_W std::vector getBackends(); + +/** @brief Returns list of available backends which works via `cv::VideoCapture(int index)` */ +CV_EXPORTS_W std::vector getCameraBackends(); + +/** @brief Returns list of available backends which works via `cv::VideoCapture(filename)` */ +CV_EXPORTS_W std::vector getStreamBackends(); + +/** @brief Returns list of available backends which works via `cv::VideoWriter()` */ +CV_EXPORTS_W std::vector getWriterBackends(); + +//! @} +}} // namespace + +#endif // OPENCV_VIDEOIO_REGISTRY_HPP diff --git a/include/opencv2/videoio/videoio_c.h b/include/opencv2/videoio/videoio_c.h index b897385..32f6ec7 100644 --- a/include/opencv2/videoio/videoio_c.h +++ b/include/opencv2/videoio/videoio_c.h @@ -39,8 +39,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOIO_H__ -#define __OPENCV_VIDEOIO_H__ +#ifndef OPENCV_VIDEOIO_H +#define OPENCV_VIDEOIO_H #include "opencv2/core/core_c.h" @@ -57,12 +57,20 @@ extern "C" { * Working with Video Files and Cameras * \****************************************************************************************/ -/* "black box" capture structure */ +/** @brief "black box" capture structure + +In C++ use cv::VideoCapture +*/ typedef struct CvCapture CvCapture; -/* start capturing frames from video file */ +/** @brief start capturing frames from video file +*/ CVAPI(CvCapture*) cvCreateFileCapture( const char* filename ); +/** @brief start capturing frames from video file. allows specifying a preferred API to use +*/ +CVAPI(CvCapture*) cvCreateFileCaptureWithPreference( const char* filename , int apiPreference); + enum { CV_CAP_ANY =0, // autodetect @@ -111,28 +119,40 @@ enum CV_CAP_INTELPERC = 1500, // Intel Perceptual Computing CV_CAP_OPENNI2 = 1600, // OpenNI2 (for Kinect) + CV_CAP_GPHOTO2 = 1700, + CV_CAP_GSTREAMER = 1800, // GStreamer + CV_CAP_FFMPEG = 1900, // FFMPEG + CV_CAP_IMAGES = 2000, // OpenCV Image Sequence (e.g. img_%02d.jpg) - CV_CAP_GPHOTO2 = 1700 + CV_CAP_ARAVIS = 2100 // Aravis GigE SDK }; -/* start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*) */ +/** @brief start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*) +*/ CVAPI(CvCapture*) cvCreateCameraCapture( int index ); -/* grab a frame, return 1 on success, 0 on fail. - this function is thought to be fast */ +/** @brief grab a frame, return 1 on success, 0 on fail. + + this function is thought to be fast +*/ CVAPI(int) cvGrabFrame( CvCapture* capture ); -/* get the frame grabbed with cvGrabFrame(..) +/** @brief get the frame grabbed with cvGrabFrame(..) + This function may apply some frame processing like frame decompression, flipping etc. - !!!DO NOT RELEASE or MODIFY the retrieved frame!!! */ + @warning !!!DO NOT RELEASE or MODIFY the retrieved frame!!! +*/ CVAPI(IplImage*) cvRetrieveFrame( CvCapture* capture, int streamIdx CV_DEFAULT(0) ); -/* Just a combination of cvGrabFrame and cvRetrieveFrame - !!!DO NOT RELEASE or MODIFY the retrieved frame!!! */ +/** @brief Just a combination of cvGrabFrame and cvRetrieveFrame + + @warning !!!DO NOT RELEASE or MODIFY the retrieved frame!!! +*/ CVAPI(IplImage*) cvQueryFrame( CvCapture* capture ); -/* stop capturing/reading and free resources */ +/** @brief stop capturing/reading and free resources +*/ CVAPI(void) cvReleaseCapture( CvCapture** capture ); enum @@ -165,7 +185,7 @@ enum CV_CAP_PROP_MONOCHROME =19, CV_CAP_PROP_SHARPNESS =20, CV_CAP_PROP_AUTO_EXPOSURE =21, // exposure control done by camera, - // user can adjust refernce level + // user can adjust reference level // using this feature CV_CAP_PROP_GAMMA =22, CV_CAP_PROP_TEMPERATURE =23, @@ -184,6 +204,9 @@ enum CV_CAP_PROP_IRIS =36, CV_CAP_PROP_SETTINGS =37, CV_CAP_PROP_BUFFERSIZE =38, + CV_CAP_PROP_AUTOFOCUS =39, + CV_CAP_PROP_SAR_NUM =40, + CV_CAP_PROP_SAR_DEN =41, CV_CAP_PROP_AUTOGRAB =1024, // property for videoio class CvCapture_Android only CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING=1025, // readonly, tricky property, returns cpnst char* indeed @@ -192,7 +215,8 @@ enum // OpenNI map generators CV_CAP_OPENNI_DEPTH_GENERATOR = 1 << 31, CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 30, - CV_CAP_OPENNI_GENERATORS_MASK = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_OPENNI_IMAGE_GENERATOR, + CV_CAP_OPENNI_IR_GENERATOR = 1 << 29, + CV_CAP_OPENNI_GENERATORS_MASK = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_OPENNI_IR_GENERATOR, // Properties of cameras available through OpenNI interfaces CV_CAP_PROP_OPENNI_OUTPUT_MODE = 100, @@ -214,10 +238,12 @@ enum CV_CAP_OPENNI_IMAGE_GENERATOR_PRESENT = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT, CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE, + CV_CAP_OPENNI_DEPTH_GENERATOR_PRESENT = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT, CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE, CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH, CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION, CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION, + CV_CAP_OPENNI_IR_GENERATOR_PRESENT = CV_CAP_OPENNI_IR_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT, // Properties of cameras available through GStreamer interface CV_CAP_GSTREAMER_QUEUE_LENGTH = 200, // default is 1 @@ -232,27 +258,157 @@ enum CV_CAP_PROP_PVAPI_PIXELFORMAT = 306, // Pixel format // Properties of cameras available through XIMEA SDK interface - CV_CAP_PROP_XI_DOWNSAMPLING = 400, // Change image resolution by binning or skipping. - CV_CAP_PROP_XI_DATA_FORMAT = 401, // Output data format. - CV_CAP_PROP_XI_OFFSET_X = 402, // Horizontal offset from the origin to the area of interest (in pixels). - CV_CAP_PROP_XI_OFFSET_Y = 403, // Vertical offset from the origin to the area of interest (in pixels). - CV_CAP_PROP_XI_TRG_SOURCE = 404, // Defines source of trigger. - CV_CAP_PROP_XI_TRG_SOFTWARE = 405, // Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE. - CV_CAP_PROP_XI_GPI_SELECTOR = 406, // Selects general purpose input - CV_CAP_PROP_XI_GPI_MODE = 407, // Set general purpose input mode - CV_CAP_PROP_XI_GPI_LEVEL = 408, // Get general purpose level - CV_CAP_PROP_XI_GPO_SELECTOR = 409, // Selects general purpose output - CV_CAP_PROP_XI_GPO_MODE = 410, // Set general purpose output mode - CV_CAP_PROP_XI_LED_SELECTOR = 411, // Selects camera signalling LED - CV_CAP_PROP_XI_LED_MODE = 412, // Define camera signalling LED functionality - CV_CAP_PROP_XI_MANUAL_WB = 413, // Calculates White Balance(must be called during acquisition) - CV_CAP_PROP_XI_AUTO_WB = 414, // Automatic white balance - CV_CAP_PROP_XI_AEAG = 415, // Automatic exposure/gain - CV_CAP_PROP_XI_EXP_PRIORITY = 416, // Exposure priority (0.5 - exposure 50%, gain 50%). - CV_CAP_PROP_XI_AE_MAX_LIMIT = 417, // Maximum limit of exposure in AEAG procedure - CV_CAP_PROP_XI_AG_MAX_LIMIT = 418, // Maximum limit of gain in AEAG procedure - CV_CAP_PROP_XI_AEAG_LEVEL = 419, // Average intensity of output signal AEAG should achieve(in %) - CV_CAP_PROP_XI_TIMEOUT = 420, // Image capture timeout in milliseconds + CV_CAP_PROP_XI_DOWNSAMPLING = 400, // Change image resolution by binning or skipping. + CV_CAP_PROP_XI_DATA_FORMAT = 401, // Output data format. + CV_CAP_PROP_XI_OFFSET_X = 402, // Horizontal offset from the origin to the area of interest (in pixels). + CV_CAP_PROP_XI_OFFSET_Y = 403, // Vertical offset from the origin to the area of interest (in pixels). + CV_CAP_PROP_XI_TRG_SOURCE = 404, // Defines source of trigger. + CV_CAP_PROP_XI_TRG_SOFTWARE = 405, // Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE. + CV_CAP_PROP_XI_GPI_SELECTOR = 406, // Selects general purpose input + CV_CAP_PROP_XI_GPI_MODE = 407, // Set general purpose input mode + CV_CAP_PROP_XI_GPI_LEVEL = 408, // Get general purpose level + CV_CAP_PROP_XI_GPO_SELECTOR = 409, // Selects general purpose output + CV_CAP_PROP_XI_GPO_MODE = 410, // Set general purpose output mode + CV_CAP_PROP_XI_LED_SELECTOR = 411, // Selects camera signalling LED + CV_CAP_PROP_XI_LED_MODE = 412, // Define camera signalling LED functionality + CV_CAP_PROP_XI_MANUAL_WB = 413, // Calculates White Balance(must be called during acquisition) + CV_CAP_PROP_XI_AUTO_WB = 414, // Automatic white balance + CV_CAP_PROP_XI_AEAG = 415, // Automatic exposure/gain + CV_CAP_PROP_XI_EXP_PRIORITY = 416, // Exposure priority (0.5 - exposure 50%, gain 50%). + CV_CAP_PROP_XI_AE_MAX_LIMIT = 417, // Maximum limit of exposure in AEAG procedure + CV_CAP_PROP_XI_AG_MAX_LIMIT = 418, // Maximum limit of gain in AEAG procedure + CV_CAP_PROP_XI_AEAG_LEVEL = 419, // Average intensity of output signal AEAG should achieve(in %) + CV_CAP_PROP_XI_TIMEOUT = 420, // Image capture timeout in milliseconds + CV_CAP_PROP_XI_EXPOSURE = 421, // Exposure time in microseconds + CV_CAP_PROP_XI_EXPOSURE_BURST_COUNT = 422, // Sets the number of times of exposure in one frame. + CV_CAP_PROP_XI_GAIN_SELECTOR = 423, // Gain selector for parameter Gain allows to select different type of gains. + CV_CAP_PROP_XI_GAIN = 424, // Gain in dB + CV_CAP_PROP_XI_DOWNSAMPLING_TYPE = 426, // Change image downsampling type. + CV_CAP_PROP_XI_BINNING_SELECTOR = 427, // Binning engine selector. + CV_CAP_PROP_XI_BINNING_VERTICAL = 428, // Vertical Binning - number of vertical photo-sensitive cells to combine together. + CV_CAP_PROP_XI_BINNING_HORIZONTAL = 429, // Horizontal Binning - number of horizontal photo-sensitive cells to combine together. + CV_CAP_PROP_XI_BINNING_PATTERN = 430, // Binning pattern type. + CV_CAP_PROP_XI_DECIMATION_SELECTOR = 431, // Decimation engine selector. + CV_CAP_PROP_XI_DECIMATION_VERTICAL = 432, // Vertical Decimation - vertical sub-sampling of the image - reduces the vertical resolution of the image by the specified vertical decimation factor. + CV_CAP_PROP_XI_DECIMATION_HORIZONTAL = 433, // Horizontal Decimation - horizontal sub-sampling of the image - reduces the horizontal resolution of the image by the specified vertical decimation factor. + CV_CAP_PROP_XI_DECIMATION_PATTERN = 434, // Decimation pattern type. + CV_CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR = 587, // Selects which test pattern generator is controlled by the TestPattern feature. + CV_CAP_PROP_XI_TEST_PATTERN = 588, // Selects which test pattern type is generated by the selected generator. + CV_CAP_PROP_XI_IMAGE_DATA_FORMAT = 435, // Output data format. + CV_CAP_PROP_XI_SHUTTER_TYPE = 436, // Change sensor shutter type(CMOS sensor). + CV_CAP_PROP_XI_SENSOR_TAPS = 437, // Number of taps + CV_CAP_PROP_XI_AEAG_ROI_OFFSET_X = 439, // Automatic exposure/gain ROI offset X + CV_CAP_PROP_XI_AEAG_ROI_OFFSET_Y = 440, // Automatic exposure/gain ROI offset Y + CV_CAP_PROP_XI_AEAG_ROI_WIDTH = 441, // Automatic exposure/gain ROI Width + CV_CAP_PROP_XI_AEAG_ROI_HEIGHT = 442, // Automatic exposure/gain ROI Height + CV_CAP_PROP_XI_BPC = 445, // Correction of bad pixels + CV_CAP_PROP_XI_WB_KR = 448, // White balance red coefficient + CV_CAP_PROP_XI_WB_KG = 449, // White balance green coefficient + CV_CAP_PROP_XI_WB_KB = 450, // White balance blue coefficient + CV_CAP_PROP_XI_WIDTH = 451, // Width of the Image provided by the device (in pixels). + CV_CAP_PROP_XI_HEIGHT = 452, // Height of the Image provided by the device (in pixels). + CV_CAP_PROP_XI_REGION_SELECTOR = 589, // Selects Region in Multiple ROI which parameters are set by width, height, ... ,region mode + CV_CAP_PROP_XI_REGION_MODE = 595, // Activates/deactivates Region selected by Region Selector + CV_CAP_PROP_XI_LIMIT_BANDWIDTH = 459, // Set/get bandwidth(datarate)(in Megabits) + CV_CAP_PROP_XI_SENSOR_DATA_BIT_DEPTH = 460, // Sensor output data bit depth. + CV_CAP_PROP_XI_OUTPUT_DATA_BIT_DEPTH = 461, // Device output data bit depth. + CV_CAP_PROP_XI_IMAGE_DATA_BIT_DEPTH = 462, // bitdepth of data returned by function xiGetImage + CV_CAP_PROP_XI_OUTPUT_DATA_PACKING = 463, // Device output data packing (or grouping) enabled. Packing could be enabled if output_data_bit_depth > 8 and packing capability is available. + CV_CAP_PROP_XI_OUTPUT_DATA_PACKING_TYPE = 464, // Data packing type. Some cameras supports only specific packing type. + CV_CAP_PROP_XI_IS_COOLED = 465, // Returns 1 for cameras that support cooling. + CV_CAP_PROP_XI_COOLING = 466, // Start camera cooling. + CV_CAP_PROP_XI_TARGET_TEMP = 467, // Set sensor target temperature for cooling. + CV_CAP_PROP_XI_CHIP_TEMP = 468, // Camera sensor temperature + CV_CAP_PROP_XI_HOUS_TEMP = 469, // Camera housing tepmerature + CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP = 590, // Camera housing back side tepmerature + CV_CAP_PROP_XI_SENSOR_BOARD_TEMP = 596, // Camera sensor board temperature + CV_CAP_PROP_XI_CMS = 470, // Mode of color management system. + CV_CAP_PROP_XI_APPLY_CMS = 471, // Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE). + CV_CAP_PROP_XI_IMAGE_IS_COLOR = 474, // Returns 1 for color cameras. + CV_CAP_PROP_XI_COLOR_FILTER_ARRAY = 475, // Returns color filter array type of RAW data. + CV_CAP_PROP_XI_GAMMAY = 476, // Luminosity gamma + CV_CAP_PROP_XI_GAMMAC = 477, // Chromaticity gamma + CV_CAP_PROP_XI_SHARPNESS = 478, // Sharpness Strength + CV_CAP_PROP_XI_CC_MATRIX_00 = 479, // Color Correction Matrix element [0][0] + CV_CAP_PROP_XI_CC_MATRIX_01 = 480, // Color Correction Matrix element [0][1] + CV_CAP_PROP_XI_CC_MATRIX_02 = 481, // Color Correction Matrix element [0][2] + CV_CAP_PROP_XI_CC_MATRIX_03 = 482, // Color Correction Matrix element [0][3] + CV_CAP_PROP_XI_CC_MATRIX_10 = 483, // Color Correction Matrix element [1][0] + CV_CAP_PROP_XI_CC_MATRIX_11 = 484, // Color Correction Matrix element [1][1] + CV_CAP_PROP_XI_CC_MATRIX_12 = 485, // Color Correction Matrix element [1][2] + CV_CAP_PROP_XI_CC_MATRIX_13 = 486, // Color Correction Matrix element [1][3] + CV_CAP_PROP_XI_CC_MATRIX_20 = 487, // Color Correction Matrix element [2][0] + CV_CAP_PROP_XI_CC_MATRIX_21 = 488, // Color Correction Matrix element [2][1] + CV_CAP_PROP_XI_CC_MATRIX_22 = 489, // Color Correction Matrix element [2][2] + CV_CAP_PROP_XI_CC_MATRIX_23 = 490, // Color Correction Matrix element [2][3] + CV_CAP_PROP_XI_CC_MATRIX_30 = 491, // Color Correction Matrix element [3][0] + CV_CAP_PROP_XI_CC_MATRIX_31 = 492, // Color Correction Matrix element [3][1] + CV_CAP_PROP_XI_CC_MATRIX_32 = 493, // Color Correction Matrix element [3][2] + CV_CAP_PROP_XI_CC_MATRIX_33 = 494, // Color Correction Matrix element [3][3] + CV_CAP_PROP_XI_DEFAULT_CC_MATRIX = 495, // Set default Color Correction Matrix + CV_CAP_PROP_XI_TRG_SELECTOR = 498, // Selects the type of trigger. + CV_CAP_PROP_XI_ACQ_FRAME_BURST_COUNT = 499, // Sets number of frames acquired by burst. This burst is used only if trigger is set to FrameBurstStart + CV_CAP_PROP_XI_DEBOUNCE_EN = 507, // Enable/Disable debounce to selected GPI + CV_CAP_PROP_XI_DEBOUNCE_T0 = 508, // Debounce time (x * 10us) + CV_CAP_PROP_XI_DEBOUNCE_T1 = 509, // Debounce time (x * 10us) + CV_CAP_PROP_XI_DEBOUNCE_POL = 510, // Debounce polarity (pol = 1 t0 - falling edge, t1 - rising edge) + CV_CAP_PROP_XI_LENS_MODE = 511, // Status of lens control interface. This shall be set to XI_ON before any Lens operations. + CV_CAP_PROP_XI_LENS_APERTURE_VALUE = 512, // Current lens aperture value in stops. Examples: 2.8, 4, 5.6, 8, 11 + CV_CAP_PROP_XI_LENS_FOCUS_MOVEMENT_VALUE = 513, // Lens current focus movement value to be used by XI_PRM_LENS_FOCUS_MOVE in motor steps. + CV_CAP_PROP_XI_LENS_FOCUS_MOVE = 514, // Moves lens focus motor by steps set in XI_PRM_LENS_FOCUS_MOVEMENT_VALUE. + CV_CAP_PROP_XI_LENS_FOCUS_DISTANCE = 515, // Lens focus distance in cm. + CV_CAP_PROP_XI_LENS_FOCAL_LENGTH = 516, // Lens focal distance in mm. + CV_CAP_PROP_XI_LENS_FEATURE_SELECTOR = 517, // Selects the current feature which is accessible by XI_PRM_LENS_FEATURE. + CV_CAP_PROP_XI_LENS_FEATURE = 518, // Allows access to lens feature value currently selected by XI_PRM_LENS_FEATURE_SELECTOR. + CV_CAP_PROP_XI_DEVICE_MODEL_ID = 521, // Return device model id + CV_CAP_PROP_XI_DEVICE_SN = 522, // Return device serial number + CV_CAP_PROP_XI_IMAGE_DATA_FORMAT_RGB32_ALPHA = 529, // The alpha channel of RGB32 output image format. + CV_CAP_PROP_XI_IMAGE_PAYLOAD_SIZE = 530, // Buffer size in bytes sufficient for output image returned by xiGetImage + CV_CAP_PROP_XI_TRANSPORT_PIXEL_FORMAT = 531, // Current format of pixels on transport layer. + CV_CAP_PROP_XI_SENSOR_CLOCK_FREQ_HZ = 532, // Sensor clock frequency in Hz. + CV_CAP_PROP_XI_SENSOR_CLOCK_FREQ_INDEX = 533, // Sensor clock frequency index. Sensor with selected frequencies have possibility to set the frequency only by this index. + CV_CAP_PROP_XI_SENSOR_OUTPUT_CHANNEL_COUNT = 534, // Number of output channels from sensor used for data transfer. + CV_CAP_PROP_XI_FRAMERATE = 535, // Define framerate in Hz + CV_CAP_PROP_XI_COUNTER_SELECTOR = 536, // Select counter + CV_CAP_PROP_XI_COUNTER_VALUE = 537, // Counter status + CV_CAP_PROP_XI_ACQ_TIMING_MODE = 538, // Type of sensor frames timing. + CV_CAP_PROP_XI_AVAILABLE_BANDWIDTH = 539, // Calculate and return available interface bandwidth(int Megabits) + CV_CAP_PROP_XI_BUFFER_POLICY = 540, // Data move policy + CV_CAP_PROP_XI_LUT_EN = 541, // Activates LUT. + CV_CAP_PROP_XI_LUT_INDEX = 542, // Control the index (offset) of the coefficient to access in the LUT. + CV_CAP_PROP_XI_LUT_VALUE = 543, // Value at entry LUTIndex of the LUT + CV_CAP_PROP_XI_TRG_DELAY = 544, // Specifies the delay in microseconds (us) to apply after the trigger reception before activating it. + CV_CAP_PROP_XI_TS_RST_MODE = 545, // Defines how time stamp reset engine will be armed + CV_CAP_PROP_XI_TS_RST_SOURCE = 546, // Defines which source will be used for timestamp reset. Writing this parameter will trigger settings of engine (arming) + CV_CAP_PROP_XI_IS_DEVICE_EXIST = 547, // Returns 1 if camera connected and works properly. + CV_CAP_PROP_XI_ACQ_BUFFER_SIZE = 548, // Acquisition buffer size in buffer_size_unit. Default bytes. + CV_CAP_PROP_XI_ACQ_BUFFER_SIZE_UNIT = 549, // Acquisition buffer size unit in bytes. Default 1. E.g. Value 1024 means that buffer_size is in KiBytes + CV_CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_SIZE = 550, // Acquisition transport buffer size in bytes + CV_CAP_PROP_XI_BUFFERS_QUEUE_SIZE = 551, // Queue of field/frame buffers + CV_CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_COMMIT = 552, // Number of buffers to commit to low level + CV_CAP_PROP_XI_RECENT_FRAME = 553, // GetImage returns most recent frame + CV_CAP_PROP_XI_DEVICE_RESET = 554, // Resets the camera to default state. + CV_CAP_PROP_XI_COLUMN_FPN_CORRECTION = 555, // Correction of column FPN + CV_CAP_PROP_XI_ROW_FPN_CORRECTION = 591, // Correction of row FPN + CV_CAP_PROP_XI_SENSOR_MODE = 558, // Current sensor mode. Allows to select sensor mode by one integer. Setting of this parameter affects: image dimensions and downsampling. + CV_CAP_PROP_XI_HDR = 559, // Enable High Dynamic Range feature. + CV_CAP_PROP_XI_HDR_KNEEPOINT_COUNT = 560, // The number of kneepoints in the PWLR. + CV_CAP_PROP_XI_HDR_T1 = 561, // position of first kneepoint(in % of XI_PRM_EXPOSURE) + CV_CAP_PROP_XI_HDR_T2 = 562, // position of second kneepoint (in % of XI_PRM_EXPOSURE) + CV_CAP_PROP_XI_KNEEPOINT1 = 563, // value of first kneepoint (% of sensor saturation) + CV_CAP_PROP_XI_KNEEPOINT2 = 564, // value of second kneepoint (% of sensor saturation) + CV_CAP_PROP_XI_IMAGE_BLACK_LEVEL = 565, // Last image black level counts. Can be used for Offline processing to recall it. + CV_CAP_PROP_XI_HW_REVISION = 571, // Returns hardware revision number. + CV_CAP_PROP_XI_DEBUG_LEVEL = 572, // Set debug level + CV_CAP_PROP_XI_AUTO_BANDWIDTH_CALCULATION = 573, // Automatic bandwidth calculation, + CV_CAP_PROP_XI_FFS_FILE_ID = 594, // File number. + CV_CAP_PROP_XI_FFS_FILE_SIZE = 580, // Size of file. + CV_CAP_PROP_XI_FREE_FFS_SIZE = 581, // Size of free camera FFS. + CV_CAP_PROP_XI_USED_FFS_SIZE = 582, // Size of used camera FFS. + CV_CAP_PROP_XI_FFS_ACCESS_KEY = 583, // Setting of key enables file operations on some cameras. + CV_CAP_PROP_XI_SENSOR_FEATURE_SELECTOR = 585, // Selects the current feature which is accessible by XI_PRM_SENSOR_FEATURE_VALUE. + CV_CAP_PROP_XI_SENSOR_FEATURE_VALUE = 586, // Allows access to sensor feature value currently selected by XI_PRM_SENSOR_FEATURE_SELECTOR. + // Properties for Android cameras CV_CAP_PROP_ANDROID_FLASH_MODE = 8001, @@ -317,7 +473,10 @@ enum // Data given from RGB image generator. CV_CAP_OPENNI_BGR_IMAGE = 5, - CV_CAP_OPENNI_GRAY_IMAGE = 6 + CV_CAP_OPENNI_GRAY_IMAGE = 6, + + // Data given from IR image generator. + CV_CAP_OPENNI_IR_IMAGE = 7 }; // Supported output modes of OpenNI image generator @@ -355,51 +514,74 @@ enum CV_CAP_PROP_VIEWFINDER = 17010 // Enter liveview mode. }; -/* retrieve or set capture properties */ +/** @brief retrieve capture properties +*/ CVAPI(double) cvGetCaptureProperty( CvCapture* capture, int property_id ); +/** @brief set capture properties +*/ CVAPI(int) cvSetCaptureProperty( CvCapture* capture, int property_id, double value ); -// Return the type of the capturer (eg, CV_CAP_V4W, CV_CAP_UNICAP), which is unknown if created with CV_CAP_ANY +/** @brief Return the type of the capturer (eg, ::CV_CAP_VFW, ::CV_CAP_UNICAP) + +It is unknown if created with ::CV_CAP_ANY +*/ CVAPI(int) cvGetCaptureDomain( CvCapture* capture); -/* "black box" video file writer structure */ +/** @brief "black box" video file writer structure + +In C++ use cv::VideoWriter +*/ typedef struct CvVideoWriter CvVideoWriter; +//! Macro to construct the fourcc code of the codec. Same as CV_FOURCC() #define CV_FOURCC_MACRO(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24)) +/** @brief Constructs the fourcc code of the codec function + +Simply call it with 4 chars fourcc code like `CV_FOURCC('I', 'Y', 'U', 'V')` + +List of codes can be obtained at [Video Codecs by FOURCC](http://www.fourcc.org/codecs.php) page. +FFMPEG backend with MP4 container natively uses other values as fourcc code: +see [ObjectType](http://www.mp4ra.org/codecs.html). +*/ CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4) { return CV_FOURCC_MACRO(c1, c2, c3, c4); } -#define CV_FOURCC_PROMPT -1 /* Open Codec Selection Dialog (Windows only) */ -#define CV_FOURCC_DEFAULT CV_FOURCC('I', 'Y', 'U', 'V') /* Use default codec for specified filename (Linux only) */ +//! (Windows only) Open Codec Selection Dialog +#define CV_FOURCC_PROMPT -1 +//! (Linux only) Use default codec for specified filename +#define CV_FOURCC_DEFAULT CV_FOURCC('I', 'Y', 'U', 'V') -/* initialize video file writer */ +/** @brief initialize video file writer +*/ CVAPI(CvVideoWriter*) cvCreateVideoWriter( const char* filename, int fourcc, double fps, CvSize frame_size, int is_color CV_DEFAULT(1)); -/* write frame to video file */ +/** @brief write frame to video file +*/ CVAPI(int) cvWriteFrame( CvVideoWriter* writer, const IplImage* image ); -/* close video file writer */ +/** @brief close video file writer +*/ CVAPI(void) cvReleaseVideoWriter( CvVideoWriter** writer ); -/****************************************************************************************\ -* Obsolete functions/synonyms * -\****************************************************************************************/ +// *************************************************************************************** +//! @name Obsolete functions/synonyms +//! @{ +#define cvCaptureFromCAM cvCreateCameraCapture //!< @deprecated use cvCreateCameraCapture() instead +#define cvCaptureFromFile cvCreateFileCapture //!< @deprecated use cvCreateFileCapture() instead +#define cvCaptureFromAVI cvCaptureFromFile //!< @deprecated use cvCreateFileCapture() instead +#define cvCreateAVIWriter cvCreateVideoWriter //!< @deprecated use cvCreateVideoWriter() instead +#define cvWriteToAVI cvWriteFrame //!< @deprecated use cvWriteFrame() instead +//! @} Obsolete... -#define cvCaptureFromFile cvCreateFileCapture -#define cvCaptureFromCAM cvCreateCameraCapture -#define cvCaptureFromAVI cvCaptureFromFile -#define cvCreateAVIWriter cvCreateVideoWriter -#define cvWriteToAVI cvWriteFrame - -/** @} videoio_c */ +//! @} videoio_c #ifdef __cplusplus } #endif -#endif //__OPENCV_VIDEOIO_H__ +#endif //OPENCV_VIDEOIO_H diff --git a/include/opencv2/videostab.hpp b/include/opencv2/videostab.hpp index 17b061f..ca3f5ad 100644 --- a/include/opencv2/videostab.hpp +++ b/include/opencv2/videostab.hpp @@ -40,15 +40,15 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_HPP__ -#define __OPENCV_VIDEOSTAB_HPP__ +#ifndef OPENCV_VIDEOSTAB_HPP +#define OPENCV_VIDEOSTAB_HPP /** @defgroup videostab Video Stabilization The video stabilization module contains a set of functions and classes that can be used to solve the -problem of video stabilization. There are a few methods implemented, most of them are descibed in -the papers @cite OF06 and @cite G11 . However, there are some extensions and deviations from the orginal +problem of video stabilization. There are a few methods implemented, most of them are described in +the papers @cite OF06 and @cite G11 . However, there are some extensions and deviations from the original paper methods. ### References diff --git a/include/opencv2/videostab/deblurring.hpp b/include/opencv2/videostab/deblurring.hpp index 8028c1d..c665640 100644 --- a/include/opencv2/videostab/deblurring.hpp +++ b/include/opencv2/videostab/deblurring.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_DEBLURRING_HPP__ -#define __OPENCV_VIDEOSTAB_DEBLURRING_HPP__ +#ifndef OPENCV_VIDEOSTAB_DEBLURRING_HPP +#define OPENCV_VIDEOSTAB_DEBLURRING_HPP #include #include "opencv2/core.hpp" @@ -90,7 +90,7 @@ protected: class CV_EXPORTS NullDeblurer : public DeblurerBase { public: - virtual void deblur(int /*idx*/, Mat &/*frame*/) {} + virtual void deblur(int /*idx*/, Mat &/*frame*/) CV_OVERRIDE {} }; class CV_EXPORTS WeightingDeblurer : public DeblurerBase @@ -101,7 +101,7 @@ public: void setSensitivity(float val) { sensitivity_ = val; } float sensitivity() const { return sensitivity_; } - virtual void deblur(int idx, Mat &frame); + virtual void deblur(int idx, Mat &frame) CV_OVERRIDE; private: float sensitivity_; diff --git a/include/opencv2/videostab/fast_marching.hpp b/include/opencv2/videostab/fast_marching.hpp index c0c7985..43f8e4a 100644 --- a/include/opencv2/videostab/fast_marching.hpp +++ b/include/opencv2/videostab/fast_marching.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_FAST_MARCHING_HPP__ -#define __OPENCV_VIDEOSTAB_FAST_MARCHING_HPP__ +#ifndef OPENCV_VIDEOSTAB_FAST_MARCHING_HPP +#define OPENCV_VIDEOSTAB_FAST_MARCHING_HPP #include #include @@ -63,7 +63,7 @@ namespace videostab class CV_EXPORTS FastMarchingMethod { public: - FastMarchingMethod() : inf_(1e6f) {} + FastMarchingMethod() : inf_(1e6f), size_(0) {} /** @brief Template method that runs the Fast Marching Method. diff --git a/include/opencv2/videostab/fast_marching_inl.hpp b/include/opencv2/videostab/fast_marching_inl.hpp index 6388e69..fdd488a 100644 --- a/include/opencv2/videostab/fast_marching_inl.hpp +++ b/include/opencv2/videostab/fast_marching_inl.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP__ -#define __OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP__ +#ifndef OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP +#define OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP #include "opencv2/videostab/fast_marching.hpp" diff --git a/include/opencv2/videostab/frame_source.hpp b/include/opencv2/videostab/frame_source.hpp index 612fbdb..171c637 100644 --- a/include/opencv2/videostab/frame_source.hpp +++ b/include/opencv2/videostab/frame_source.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP__ -#define __OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP__ +#ifndef OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP +#define OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP #include #include "opencv2/core.hpp" @@ -65,8 +65,8 @@ public: class CV_EXPORTS NullFrameSource : public IFrameSource { public: - virtual void reset() {} - virtual Mat nextFrame() { return Mat(); } + virtual void reset() CV_OVERRIDE {} + virtual Mat nextFrame() CV_OVERRIDE { return Mat(); } }; class CV_EXPORTS VideoFileSource : public IFrameSource @@ -74,8 +74,8 @@ class CV_EXPORTS VideoFileSource : public IFrameSource public: VideoFileSource(const String &path, bool volatileFrame = false); - virtual void reset(); - virtual Mat nextFrame(); + virtual void reset() CV_OVERRIDE; + virtual Mat nextFrame() CV_OVERRIDE; int width(); int height(); diff --git a/include/opencv2/videostab/global_motion.hpp b/include/opencv2/videostab/global_motion.hpp index 5d51e42..fedca2c 100644 --- a/include/opencv2/videostab/global_motion.hpp +++ b/include/opencv2/videostab/global_motion.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__ -#define __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__ +#ifndef OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP +#define OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP #include #include @@ -139,7 +139,7 @@ public: void setMinInlierRatio(float val) { minInlierRatio_ = val; } float minInlierRatio() const { return minInlierRatio_; } - virtual Mat estimate(InputArray points0, InputArray points1, bool *ok = 0); + virtual Mat estimate(InputArray points0, InputArray points1, bool *ok = 0) CV_OVERRIDE; private: RansacParams ransacParams_; @@ -155,7 +155,7 @@ class CV_EXPORTS MotionEstimatorL1 : public MotionEstimatorBase public: MotionEstimatorL1(MotionModel model = MM_AFFINE); - virtual Mat estimate(InputArray points0, InputArray points1, bool *ok = 0); + virtual Mat estimate(InputArray points0, InputArray points1, bool *ok = 0) CV_OVERRIDE; private: std::vector obj_, collb_, colub_; @@ -194,7 +194,7 @@ class CV_EXPORTS FromFileMotionReader : public ImageMotionEstimatorBase public: FromFileMotionReader(const String &path); - virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0); + virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0) CV_OVERRIDE; private: std::ifstream file_; @@ -205,10 +205,10 @@ class CV_EXPORTS ToFileMotionWriter : public ImageMotionEstimatorBase public: ToFileMotionWriter(const String &path, Ptr estimator); - virtual void setMotionModel(MotionModel val) { motionEstimator_->setMotionModel(val); } - virtual MotionModel motionModel() const { return motionEstimator_->motionModel(); } + virtual void setMotionModel(MotionModel val) CV_OVERRIDE { motionEstimator_->setMotionModel(val); } + virtual MotionModel motionModel() const CV_OVERRIDE { return motionEstimator_->motionModel(); } - virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0); + virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0) CV_OVERRIDE; private: std::ofstream file_; @@ -223,8 +223,8 @@ class CV_EXPORTS KeypointBasedMotionEstimator : public ImageMotionEstimatorBase public: KeypointBasedMotionEstimator(Ptr estimator); - virtual void setMotionModel(MotionModel val) { motionEstimator_->setMotionModel(val); } - virtual MotionModel motionModel() const { return motionEstimator_->motionModel(); } + virtual void setMotionModel(MotionModel val) CV_OVERRIDE { motionEstimator_->setMotionModel(val); } + virtual MotionModel motionModel() const CV_OVERRIDE { return motionEstimator_->motionModel(); } void setDetector(Ptr val) { detector_ = val; } Ptr detector() const { return detector_; } @@ -235,7 +235,8 @@ public: void setOutlierRejector(Ptr val) { outlierRejector_ = val; } Ptr outlierRejector() const { return outlierRejector_; } - virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0); + virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0) CV_OVERRIDE; + Mat estimate(InputArray frame0, InputArray frame1, bool *ok = 0); private: Ptr motionEstimator_; @@ -256,13 +257,13 @@ class CV_EXPORTS KeypointBasedMotionEstimatorGpu : public ImageMotionEstimatorBa public: KeypointBasedMotionEstimatorGpu(Ptr estimator); - virtual void setMotionModel(MotionModel val) { motionEstimator_->setMotionModel(val); } - virtual MotionModel motionModel() const { return motionEstimator_->motionModel(); } + virtual void setMotionModel(MotionModel val) CV_OVERRIDE { motionEstimator_->setMotionModel(val); } + virtual MotionModel motionModel() const CV_OVERRIDE { return motionEstimator_->motionModel(); } void setOutlierRejector(Ptr val) { outlierRejector_ = val; } Ptr outlierRejector() const { return outlierRejector_; } - virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0); + virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0) CV_OVERRIDE; Mat estimate(const cuda::GpuMat &frame0, const cuda::GpuMat &frame1, bool *ok = 0); private: @@ -287,7 +288,7 @@ private: @param from Source frame index. @param to Destination frame index. @param motions Pair-wise motions. motions[i] denotes motion from the frame i to the frame i+1 -@return Motion from the frame from to the frame to. +@return Motion from the Source frame to the Destination frame. */ CV_EXPORTS Mat getMotion(int from, int to, const std::vector &motions); diff --git a/include/opencv2/videostab/inpainting.hpp b/include/opencv2/videostab/inpainting.hpp index 844c68c..9c123f0 100644 --- a/include/opencv2/videostab/inpainting.hpp +++ b/include/opencv2/videostab/inpainting.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_INPAINTINT_HPP__ -#define __OPENCV_VIDEOSTAB_INPAINTINT_HPP__ +#ifndef OPENCV_VIDEOSTAB_INPAINTINT_HPP +#define OPENCV_VIDEOSTAB_INPAINTINT_HPP #include #include "opencv2/core.hpp" @@ -102,7 +102,7 @@ protected: class CV_EXPORTS NullInpainter : public InpainterBase { public: - virtual void inpaint(int /*idx*/, Mat &/*frame*/, Mat &/*mask*/) {} + virtual void inpaint(int /*idx*/, Mat &/*frame*/, Mat &/*mask*/) CV_OVERRIDE {} }; class CV_EXPORTS InpaintingPipeline : public InpainterBase @@ -111,14 +111,14 @@ public: void pushBack(Ptr inpainter) { inpainters_.push_back(inpainter); } bool empty() const { return inpainters_.empty(); } - virtual void setRadius(int val); - virtual void setMotionModel(MotionModel val); - virtual void setFrames(const std::vector &val); - virtual void setMotions(const std::vector &val); - virtual void setStabilizedFrames(const std::vector &val); - virtual void setStabilizationMotions(const std::vector &val); + virtual void setRadius(int val) CV_OVERRIDE; + virtual void setMotionModel(MotionModel val) CV_OVERRIDE; + virtual void setFrames(const std::vector &val) CV_OVERRIDE; + virtual void setMotions(const std::vector &val) CV_OVERRIDE; + virtual void setStabilizedFrames(const std::vector &val) CV_OVERRIDE; + virtual void setStabilizationMotions(const std::vector &val) CV_OVERRIDE; - virtual void inpaint(int idx, Mat &frame, Mat &mask); + virtual void inpaint(int idx, Mat &frame, Mat &mask) CV_OVERRIDE; private: std::vector > inpainters_; @@ -132,7 +132,7 @@ public: void setStdevThresh(float val) { stdevThresh_ = val; } float stdevThresh() const { return stdevThresh_; } - virtual void inpaint(int idx, Mat &frame, Mat &mask); + virtual void inpaint(int idx, Mat &frame, Mat &mask) CV_OVERRIDE; private: float stdevThresh_; @@ -155,7 +155,7 @@ public: void setBorderMode(int val) { borderMode_ = val; } int borderMode() const { return borderMode_; } - virtual void inpaint(int idx, Mat &frame, Mat &mask); + virtual void inpaint(int idx, Mat &frame, Mat &mask) CV_OVERRIDE; private: FastMarchingMethod fmm_; @@ -174,7 +174,7 @@ private: class CV_EXPORTS ColorAverageInpainter : public InpainterBase { public: - virtual void inpaint(int idx, Mat &frame, Mat &mask); + virtual void inpaint(int idx, Mat &frame, Mat &mask) CV_OVERRIDE; private: FastMarchingMethod fmm_; @@ -185,7 +185,7 @@ class CV_EXPORTS ColorInpainter : public InpainterBase public: ColorInpainter(int method = INPAINT_TELEA, double radius = 2.); - virtual void inpaint(int idx, Mat &frame, Mat &mask); + virtual void inpaint(int idx, Mat &frame, Mat &mask) CV_OVERRIDE; private: int method_; diff --git a/include/opencv2/videostab/log.hpp b/include/opencv2/videostab/log.hpp index 28625ed..73e7049 100644 --- a/include/opencv2/videostab/log.hpp +++ b/include/opencv2/videostab/log.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_LOG_HPP__ -#define __OPENCV_VIDEOSTAB_LOG_HPP__ +#ifndef OPENCV_VIDEOSTAB_LOG_HPP +#define OPENCV_VIDEOSTAB_LOG_HPP #include "opencv2/core.hpp" @@ -63,13 +63,13 @@ public: class CV_EXPORTS NullLog : public ILog { public: - virtual void print(const char * /*format*/, ...) {} + virtual void print(const char * /*format*/, ...) CV_OVERRIDE {} }; class CV_EXPORTS LogToStdout : public ILog { public: - virtual void print(const char *format, ...); + virtual void print(const char *format, ...) CV_OVERRIDE; }; //! @} diff --git a/include/opencv2/videostab/motion_core.hpp b/include/opencv2/videostab/motion_core.hpp index 17448e3..4525cc7 100644 --- a/include/opencv2/videostab/motion_core.hpp +++ b/include/opencv2/videostab/motion_core.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_MOTION_CORE_HPP__ -#define __OPENCV_VIDEOSTAB_MOTION_CORE_HPP__ +#ifndef OPENCV_VIDEOSTAB_MOTION_CORE_HPP +#define OPENCV_VIDEOSTAB_MOTION_CORE_HPP #include #include "opencv2/core.hpp" diff --git a/include/opencv2/videostab/motion_stabilizing.hpp b/include/opencv2/videostab/motion_stabilizing.hpp index 3bdbfbd..c50095b 100644 --- a/include/opencv2/videostab/motion_stabilizing.hpp +++ b/include/opencv2/videostab/motion_stabilizing.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP__ -#define __OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP__ +#ifndef OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP +#define OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP #include #include @@ -75,7 +75,7 @@ public: virtual void stabilize( int size, const std::vector &motions, std::pair range, - Mat *stabilizationMotions); + Mat *stabilizationMotions) CV_OVERRIDE; private: std::vector > stabilizers_; @@ -91,7 +91,7 @@ public: virtual void stabilize( int size, const std::vector &motions, std::pair range, - Mat *stabilizationMotions); + Mat *stabilizationMotions) CV_OVERRIDE; }; class CV_EXPORTS GaussianMotionFilter : public MotionFilterBase @@ -104,7 +104,7 @@ public: float stdev() const { return stdev_; } virtual Mat stabilize( - int idx, const std::vector &motions, std::pair range); + int idx, const std::vector &motions, std::pair range) CV_OVERRIDE; private: int radius_; @@ -142,7 +142,7 @@ public: virtual void stabilize( int size, const std::vector &motions, std::pair range, - Mat *stabilizationMotions); + Mat *stabilizationMotions) CV_OVERRIDE; private: MotionModel model_; diff --git a/include/opencv2/videostab/optical_flow.hpp b/include/opencv2/videostab/optical_flow.hpp index 41d1953..5e06941 100644 --- a/include/opencv2/videostab/optical_flow.hpp +++ b/include/opencv2/videostab/optical_flow.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP__ -#define __OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP__ +#ifndef OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP +#define OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP #include "opencv2/core.hpp" #include "opencv2/opencv_modules.hpp" @@ -99,7 +99,7 @@ class CV_EXPORTS SparsePyrLkOptFlowEstimator public: virtual void run( InputArray frame0, InputArray frame1, InputArray points0, InputOutputArray points1, - OutputArray status, OutputArray errors); + OutputArray status, OutputArray errors) CV_OVERRIDE; }; #ifdef HAVE_OPENCV_CUDAOPTFLOW @@ -112,7 +112,7 @@ public: virtual void run( InputArray frame0, InputArray frame1, InputArray points0, InputOutputArray points1, - OutputArray status, OutputArray errors); + OutputArray status, OutputArray errors) CV_OVERRIDE; void run(const cuda::GpuMat &frame0, const cuda::GpuMat &frame1, const cuda::GpuMat &points0, cuda::GpuMat &points1, cuda::GpuMat &status, cuda::GpuMat &errors); @@ -133,7 +133,7 @@ public: virtual void run( InputArray frame0, InputArray frame1, InputOutputArray flowX, InputOutputArray flowY, - OutputArray errors); + OutputArray errors) CV_OVERRIDE; private: Ptr optFlowEstimator_; diff --git a/include/opencv2/videostab/outlier_rejection.hpp b/include/opencv2/videostab/outlier_rejection.hpp index 9e40f85..1d29896 100644 --- a/include/opencv2/videostab/outlier_rejection.hpp +++ b/include/opencv2/videostab/outlier_rejection.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP__ -#define __OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP__ +#ifndef OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP +#define OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP #include #include "opencv2/core.hpp" @@ -68,7 +68,7 @@ class CV_EXPORTS NullOutlierRejector : public IOutlierRejector { public: virtual void process( - Size frameSize, InputArray points0, InputArray points1, OutputArray mask); + Size frameSize, InputArray points0, InputArray points1, OutputArray mask) CV_OVERRIDE; }; class CV_EXPORTS TranslationBasedLocalOutlierRejector : public IOutlierRejector @@ -83,7 +83,7 @@ public: RansacParams ransacParams() const { return ransacParams_; } virtual void process( - Size frameSize, InputArray points0, InputArray points1, OutputArray mask); + Size frameSize, InputArray points0, InputArray points1, OutputArray mask) CV_OVERRIDE; private: Size cellSize_; diff --git a/include/opencv2/videostab/ring_buffer.hpp b/include/opencv2/videostab/ring_buffer.hpp index 7cc3f03..55d5244 100644 --- a/include/opencv2/videostab/ring_buffer.hpp +++ b/include/opencv2/videostab/ring_buffer.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_RING_BUFFER_HPP__ -#define __OPENCV_VIDEOSTAB_RING_BUFFER_HPP__ +#ifndef OPENCV_VIDEOSTAB_RING_BUFFER_HPP +#define OPENCV_VIDEOSTAB_RING_BUFFER_HPP #include #include "opencv2/imgproc.hpp" diff --git a/include/opencv2/videostab/stabilizer.hpp b/include/opencv2/videostab/stabilizer.hpp index c18d314..634a0aa 100644 --- a/include/opencv2/videostab/stabilizer.hpp +++ b/include/opencv2/videostab/stabilizer.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_STABILIZER_HPP__ -#define __OPENCV_VIDEOSTAB_STABILIZER_HPP__ +#ifndef OPENCV_VIDEOSTAB_STABILIZER_HPP +#define OPENCV_VIDEOSTAB_STABILIZER_HPP #include #include @@ -144,14 +144,14 @@ public: void setMotionFilter(Ptr val) { motionFilter_ = val; } Ptr motionFilter() const { return motionFilter_; } - virtual void reset(); - virtual Mat nextFrame() { return nextStabilizedFrame(); } + virtual void reset() CV_OVERRIDE; + virtual Mat nextFrame() CV_OVERRIDE { return nextStabilizedFrame(); } protected: - virtual void setUp(const Mat &firstFrame); - virtual Mat estimateMotion(); - virtual Mat estimateStabilizationMotion(); - virtual Mat postProcessFrame(const Mat &frame); + virtual void setUp(const Mat &firstFrame) CV_OVERRIDE; + virtual Mat estimateMotion() CV_OVERRIDE; + virtual Mat estimateStabilizationMotion() CV_OVERRIDE; + virtual Mat postProcessFrame(const Mat &frame) CV_OVERRIDE; Ptr motionFilter_; }; @@ -170,16 +170,16 @@ public: void setEstimateTrimRatio(bool val) { mustEstTrimRatio_ = val; } bool mustEstimateTrimaRatio() const { return mustEstTrimRatio_; } - virtual void reset(); - virtual Mat nextFrame(); + virtual void reset() CV_OVERRIDE; + virtual Mat nextFrame() CV_OVERRIDE; protected: void runPrePassIfNecessary(); - virtual void setUp(const Mat &firstFrame); - virtual Mat estimateMotion(); - virtual Mat estimateStabilizationMotion(); - virtual Mat postProcessFrame(const Mat &frame); + virtual void setUp(const Mat &firstFrame) CV_OVERRIDE; + virtual Mat estimateMotion() CV_OVERRIDE; + virtual Mat estimateStabilizationMotion() CV_OVERRIDE; + virtual Mat postProcessFrame(const Mat &frame) CV_OVERRIDE; Ptr motionStabilizer_; Ptr wobbleSuppressor_; diff --git a/include/opencv2/videostab/wobble_suppression.hpp b/include/opencv2/videostab/wobble_suppression.hpp index 3f0a943..d60ae6d 100644 --- a/include/opencv2/videostab/wobble_suppression.hpp +++ b/include/opencv2/videostab/wobble_suppression.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP__ -#define __OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP__ +#ifndef OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP +#define OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP #include #include "opencv2/core.hpp" @@ -95,7 +95,7 @@ protected: class CV_EXPORTS NullWobbleSuppressor : public WobbleSuppressorBase { public: - virtual void suppress(int idx, const Mat &frame, Mat &result); + virtual void suppress(int idx, const Mat &frame, Mat &result) CV_OVERRIDE; }; class CV_EXPORTS MoreAccurateMotionWobbleSuppressorBase : public WobbleSuppressorBase @@ -113,7 +113,7 @@ protected: class CV_EXPORTS MoreAccurateMotionWobbleSuppressor : public MoreAccurateMotionWobbleSuppressorBase { public: - virtual void suppress(int idx, const Mat &frame, Mat &result); + virtual void suppress(int idx, const Mat &frame, Mat &result) CV_OVERRIDE; private: Mat_ mapx_, mapy_; @@ -124,7 +124,7 @@ class CV_EXPORTS MoreAccurateMotionWobbleSuppressorGpu : public MoreAccurateMoti { public: void suppress(int idx, const cuda::GpuMat &frame, cuda::GpuMat &result); - virtual void suppress(int idx, const Mat &frame, Mat &result); + virtual void suppress(int idx, const Mat &frame, Mat &result) CV_OVERRIDE; private: cuda::GpuMat frameDevice_, resultDevice_; diff --git a/include/opencv2/world.hpp b/include/opencv2/world.hpp index 2442f2c..4902c2f 100644 --- a/include/opencv2/world.hpp +++ b/include/opencv2/world.hpp @@ -40,8 +40,8 @@ // //M*/ -#ifndef __OPENCV_WORLD_HPP__ -#define __OPENCV_WORLD_HPP__ +#ifndef OPENCV_WORLD_HPP +#define OPENCV_WORLD_HPP #include "opencv2/core.hpp" diff --git a/include/platform/alloc/ialloc.cpp b/include/platform/alloc/ialloc.cpp new file mode 100644 index 0000000..982ec6d --- /dev/null +++ b/include/platform/alloc/ialloc.cpp @@ -0,0 +1,281 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "alloc/ialloc.h" + #include "thread/mutex.h" + #include "log/log.h" + + using namespace GS::Alloc; + + +//------------------------------------------------------------------------------ +void *DefaultAllocator::Alloc(size_t size, System sys) +{ __NSTAT_WRAPALLOC(malloc(size), sys) } +void DefaultAllocator::Delete(void *addr, System sys) +{ __NSTAT_WRAPDELETE(free(addr), sys) } +//------------------------------------------------------------------------------ + + +#if __ENABLE_ALLOCATION_STAT__ + +namespace GS { + namespace Alloc { + +Stat system_stat[SystemCount]; +SystemDesc system_desc[SystemCount] = +{ + { "General", "System" }, + + { "Container", "List Item" }, + { "String", "String Buffer" }, + + { "I/O", "Filesystem" }, + { "I/O", "Metatag" }, + + { "Animation", "Curve" }, + { "Animation", "Motion" }, + { "Animation", "Animation Source" }, + + { "Maths", "Vector" }, + { "Maths", "Matrix" }, + + { "Physics", "Physics" }, + + { "Scene 3D", "Item" }, + + { "Resource", "Geometry" }, + { "Resource", "Material" }, + { "Resource", "Texture" }, + { "Resource", "Picture" }, + + { "Mixer", "System" }, + { "Resource", "Sound" }, + + { "Renderer", "System" }, + { "Renderer", "Render Job" }, + { "Renderer", "Terrain" }, + + { "Renderer", "VBO" }, + + { "Global", "Other" } +}; + +//------------------------------------------------------------------------------ +size_t GetAdjustedAllocationSize(size_t size) +{ return size + sizeof(Header); } +void *SetupAllocationStat(void *addr, size_t size) +{ + Header *h = (Header *)addr; + h->size = size; + return (void *)(h + 1); +} +void *GetAllocationStat(void *addr, Header *&h) +{ + h = ((Header *)addr) - 1; + return (void *)h; +} +//------------------------------------------------------------------------------ + +static Mutex stat_mutex; + +//------------------------------------------------------------------------------ +void UpdateStatAlloc(size_t size, System system) +{ + MutexLock lock(&stat_mutex); + + ++system_stat[system].alloc_count; + ++system_stat[system].alive_count; + if (system_stat[system].alive_count > system_stat[system].alive_count_peak) + system_stat[system].alive_count_peak = system_stat[system].alive_count; + system_stat[system].size += size; + if (system_stat[system].size > system_stat[system].size_peak) + system_stat[system].size_peak = system_stat[system].size; +} +void UpdateStatDelete(size_t size, System system) +{ + MutexLock lock(&stat_mutex); + + system_stat[system].alive_count--; + system_stat[system].size -= size; +} +//------------------------------------------------------------------------------ + + } // Alloc +} // GS + + +#endif // __ENABLE_ALLOCATION_STAT__ + + +#include "container/narray.h" + +//------------------------------------------------------------------------------ +class SmallBlockAllocatorPool +{ + void *root; + char *pool, *pool_end; + +public: + + bool Owns(void *p) const + { return (p >= (void *)pool) && (p < (void *)pool_end); } + + void *Alloc() + { + if (!root) + return NULL; + + void *p = root; + root = *((void **)root); + return p; + } + void Free(void *p) + { + *((void **)p) = root; + root = p; + } + + bool Init(size_t block_size, uint block_count) + { + Uninit(); + + pool = (char *)malloc(block_size * block_count); + if (pool == NULL) + return false; + pool_end = pool + block_size * block_count; + + for (uint n = 0; n < (block_count - 1); ++n) + *((void **)(pool + n * block_size)) = (void *)(pool + (n + 1) * block_size); + *((void **)(pool + (block_count - 1) * block_size)) = NULL; + + root = (void *)pool; + return true; + } + void Uninit() + { + free(pool); + root = NULL; + } + + SmallBlockAllocatorPool() + { + pool = pool_end = NULL; + root = NULL; + } + ~SmallBlockAllocatorPool() + { + Uninit(); + } +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +class MixedBlockAllocator +{ + SmallBlockAllocatorPool allocator[4]; + +public: + + void *operator new (size_t size) + { return malloc(size); } + void operator delete(void *addr) + { free(addr); } + + void *Alloc(size_t size) + { + void *p = NULL; + + if (size <= 8) + p = allocator[0].Alloc(); + else if (size <= 16) + p = allocator[1].Alloc(); + else if (size <= 32) + p = allocator[2].Alloc(); + else if (size <= 64) + p = allocator[3].Alloc(); + + return p ? p : malloc(size); + } + void Free(void *p) + { + if (allocator[0].Owns(p)) + allocator[0].Free(p); + else if (allocator[1].Owns(p)) + allocator[1].Free(p); + else if (allocator[2].Owns(p)) + allocator[2].Free(p); + else if (allocator[3].Owns(p)) + allocator[3].Free(p); + else + free(p); + } + + bool Init() + { + allocator[0].Init(8, 16000); // 128k + allocator[1].Init(16, 16000); // 256k + allocator[2].Init(32, 8000); // 256k + allocator[3].Init(64, 8000); // 512k + + return true; + } +}; +//------------------------------------------------------------------------------ + +#if __ENABLE_GLOBAL_SBA__ + +MixedBlockAllocator *mixed_allocator = NULL; + +MixedBlockAllocator *GetMixedAllocator() +{ + if (!mixed_allocator) + { + mixed_allocator = new MixedBlockAllocator; + mixed_allocator->Init(); + } + return mixed_allocator; +} + +//------------------------------------------------------------------------------ +void *operator new(size_t size) +{ + __NSTAT_WRAPALLOC(GetMixedAllocator()->Alloc(size), Alloc::Global) +} +void operator delete(void *addr) +{ + __NSTAT_WRAPDELETE(GetMixedAllocator()->Free(addr), Alloc::Global) +} +void *operator new [] (size_t size) +{ + __NSTAT_WRAPALLOC(GetMixedAllocator()->Alloc(size), Alloc::Global) +} +void operator delete [] (void *addr) +{ + __NSTAT_WRAPDELETE(GetMixedAllocator()->Free(addr), Alloc::Global) +} +//------------------------------------------------------------------------------ + +#endif + +//------------------------------------------------------------------------------ +void *_align_alloc(size_t size, size_t align) +{ +#ifdef _WIN32 + return _aligned_malloc(size, align); +#else + return malloc(size); +#endif +} +void _align_free(void *p) +{ +#ifdef _WIN32 + _aligned_free(p); +#else + free(p); +#endif +} +//------------------------------------------------------------------------------ diff --git a/include/platform/assert/nassert.cpp b/include/platform/assert/nassert.cpp new file mode 100644 index 0000000..328255b --- /dev/null +++ b/include/platform/assert/nassert.cpp @@ -0,0 +1,28 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #if __PLATFORM_WINDOWS__ + #define WINDOWS_LEAN_AND_MEAN + #include + #endif + + #include "assert/nassert.h" + #include "nstring/nstring.h" + + +//------------------------------------------------------------------------------ +void GS::Assert::Trigger(const char *source, int line, const char *condition, const char *message) +{ + String description = String::Format("%s\n\nFile: %s\nLine %d\n", condition, source, line); + if (message) + description += String("\nDetail: ") + message; + +#if __PLATFORM_WINDOWS__ + MessageBoxA(NULL, description.c_str(), "Assertion failed!", MB_ICONSTOP); + DebugBreak(); +#endif +} +//------------------------------------------------------------------------------ diff --git a/include/platform/async/job.cpp b/include/platform/async/job.cpp new file mode 100644 index 0000000..c738a68 --- /dev/null +++ b/include/platform/async/job.cpp @@ -0,0 +1,215 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "async/job.h" + #include "memory/memory.h" + #include "log/log.h" + + using namespace GS::ASync; + using namespace GS::Threading; + + #ifndef _DEBUG + #define __ENABLE_ITT_API__ 0 + #endif + + #if __ENABLE_ITT_API__ + #include "ittnotify.h" + static __itt_domain *domain = NULL; + #endif + + +//------------------------------------------------------------------------------ +void JobWorkerThread::Execute() +{ + running.Set(1); + + Thread::SetName(GS::String::Format("Job Worker Thread %d", worker_id)); + + while (running.Get() == 1) + { + // Execute as much jobs as possible until starvation. + while (manager.ExecutePendingJob(worker_id)); + + // Wait for notification on the queue event. + manager.job_queued_event.Wait(); + } + + running.Set(0); +} +void JobWorkerThread::Stop() +{ running.Set(2); } +bool JobWorkerThread::IsRunning() const +{ return running.Get() > 0; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool JobManager::CreateJobThreadPool(uint count) +{ + FreeJobThreadPool(); + + if (!pool.Allocate(count)) + return false; + + for (uint n = 0; n < count; ++n) + if ((pool[n] = new JobWorkerThread(*this, n + 1)) == NULL) + __ERR__(__LOG_E__ << "Failed to allocate a job worker thread.\n", false) + + // Create workers. + for (uint n = 0; n < count; ++n) + if (!pool[n]->Start()) + __LOG_W__ << "Failed to create worker thread " << pool[n]->GetWorkerId() << ".\n"; + + return true; +} +void JobManager::FreeJobThreadPool() +{ + // Set thread exit flag. + for (uint n = 0; n < pool.GetCount(); ++n) + pool[n]->Stop(); + + // Trigger event so that the thread processes the exit flag. + for (uint n = 0; n < pool.GetCount(); ++n) + job_queued_event.Trigger(); + + // Join threads. + for (uint n = 0; n < pool.GetCount(); ++n) + if (!pool[n]->IsRunning()) + delete pool[n]; + + pool.Free(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool JobManager::EnqueueJob(Job *job, JobGroup *group) +{ + if (pool.GetCount() == 0) + { + job->Execute(0); + job->done.Set(1); + } + else + { + job->done.Set(0); + + if (group) + { + MutexLock lock(group->job_list_mutex); + group->job_list.Add(job); + } + { + #if __USE_LOCK_FREE_JOB_QUEUE__ + while (!pending_queue.enqueue(job)) {} + #else + nMutexLock lock(pending_queue_mutex); + pending_queue.Push(job); + #endif + } + } + + job_queued_event.Trigger(); // wake workers + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool JobManager::JoinJob(Job *job, bool blocking) +{ + if (job) + while (job->done.Get() == 0) // spinlock + if (!blocking) + return false; + + return true; +} +bool JobManager::JoinGroup(JobGroup *group, bool blocking) +{ + if (group) + for (bool done = false; !done; ) // spinlock + { + done = true; + { + MutexLock glock(group->job_list_mutex); + ListForeachPtr(Job *, job, group->job_list) + if (job->done.Get() == 0) + { + done = false; + break; + } + } + if (!blocking) + return done; + + Thread::Switch(); + } + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool JobManager::ExecutePendingJob(uint worker_id) +{ + // Look for a job to execute. + Job *job = NULL; + { + #if __USE_LOCK_FREE_JOB_QUEUE__ + pending_queue.dequeue(job); + #else + nMutexLock pending_lock(pending_queue_mutex); + if (pending_queue.GetCount() > 0) + { + job = pending_queue.Top(); + pending_queue.Pop(); + } + #endif + } + + // Execute job. + if (job) + { + #if __ENABLE_ITT_API__ + __itt_task_begin(domain, __itt_null, __itt_null, __itt_string_handle_create(job->name)); + #endif + +// job->time_start = Platform::Get().GetTime(); + + job->Execute(worker_id); + job->done.Set(1); + +// job->time_end = Platform::Get().GetTime(); + + Thread::Switch(); // let other workers do their job + + #if __ENABLE_ITT_API__ + __itt_task_end(domain); + #endif + } + return asbool(job); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint JobManager::GetWorkerPoolSize() const +{ return pool.GetCount(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +JobManager::JobManager() : pending_queue(256) +{ +#if __ENABLE_ITT_API__ + domain = __itt_domain_create("GS.JobManager"); +#endif + +#if (__USE_LOCK_FREE_JOB_QUEUE__ == 0) + pending_queue_mutex = new nMutex; +#endif +} +JobManager::~JobManager() +{ FreeJobThreadPool(); } +JobGroup::JobGroup() +{ job_list_mutex = new Mutex; } +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/data_store.cpp b/include/platform/filesystem/data_store.cpp new file mode 100644 index 0000000..9e93b30 --- /dev/null +++ b/include/platform/filesystem/data_store.cpp @@ -0,0 +1,160 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/data_store.h" + #include "rand/rand.h" + #include "memory/nauto_ptr.h" + + using namespace GS; + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +DataStore::Entry *DataStore::GetEntry(const String &id) const +{ + ListForeachPtr(Entry *, e, entries) + if (e->id == id) + return e; + return NULL; +} +String DataStore::GetNewId() +{ + for ( ; ; ++id_seed) + { + String id = String::Format("store_%012d", id_seed); + if (GetEntry(id) == NULL) + return id; + } + return String(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t DataStore::GetEntrySize(const String &id) const +{ + if (Entry *e = GetEntry(id)) + return e->size; + return 0; +} +size_t DataStore::GetStoreSize() const +{ + size_t size = 0; + ListForeachPtr(Entry *, e, entries) + size += e->size; + return size; +} +size_t DataStore::GetFreeStore() const +{ return limit - GetStoreSize(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String DataStore::Reserve(size_t size) +{ + Threading::MutexLock lock(&mutex); + + if (limit > 0) // enforce size limit + { + size_t store_size = GetStoreSize(); + if (size > (limit - store_size)) + return String(); // store is full + } + + // Reserve a new entry. + Entry *entry = new Entry; + + entry->id = GetNewId(); + entry->size = size; + entries.Add(entry); + + return entry->id; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool DataStore::Store(const String &id, const void *data, size_t size, const char *user) +{ + Threading::MutexLock lock(&mutex); + + Entry *entry = GetEntry(id); + if ((entry == NULL) || (entry->size != size)) + return false; // invalid id/store size + + lock.Unlock(); + + entry->user = user; + + AutoPtr h(io->Open(id, ModeWrite)); + return h.IsValid() && (h->Write(data, size) == size); +} +bool DataStore::Free(const String &id) +{ + Threading::MutexLock lock(&mutex); + + Entry *entry = GetEntry(id); + if (entry == NULL) + return false; // invalid id + + if (!io->Delete(id)) + return false; + + return entries.Remove(entry); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Store format +// +// 18 bytes - id +// 4 bytes - size in bytes +// ----------------------------- +bool DataStore::Load(const char *path) +{ + AutoPtr h(io->Open(path)); + if (h.IsNull()) + return true; // nothing to restore + + entries.Clear(); + + char id[18]; + while (!h->IsEOF()) + { + if (h->Read((void *)id, 18) != 18) + return false; + + Entry *e = new Entry; + + e->id.Set(id, id + 18); + e->size = h->Read (); + + uint user_data_size = h->Read (); + if (!e->user.Allocate(user_data_size)) + return false; + + h->Read((void *)e->user.c_str(), user_data_size); + + entries.Add(e); + } + return true; +} +bool DataStore::Save(const char *path) +{ + AutoPtr h(io->Open(path, ModeWrite)); + if (h.IsNull()) + return false; + + ListForeachPtr(Entry *, e, entries) + { + h->Write(e->id.c_str(), 18); + h->Write(&e->size, 4); + + uint user_data_size = e->user.Len(); + h->Write(user_data_size); + if (user_data_size > 0) + h->Write(e->user.c_str(), user_data_size); + } + return true; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/filesystem.cpp b/include/platform/filesystem/filesystem.cpp new file mode 100644 index 0000000..c7f508f --- /dev/null +++ b/include/platform/filesystem/filesystem.cpp @@ -0,0 +1,218 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/filesystem.h" + #include "filesystem/io_handle.h" + #include "log/log.h" + + +#if __PLATFORM_POSIX__ +#include +#include +#elif __PLATFORM_WINDOWS__ +#include +#endif + +#include "filesystem/io_cfile.h" +#include "memory/nauto_ptr.h" + + + using GS::String; + using namespace GS::IO; + +//------------------------------------------------------------------------------ +bool Filesystem::Exists(const char *uri) const +{ + AutoPtr h(Open(uri)); + return h.IsValid(); +} +size_t Filesystem::FileSize(const char *uri) const +{ + AutoPtr h(Open(uri)); + return h.IsNull() ? 0 : h->GetSize(); +} +bool Filesystem::FileLoad(const char *uri, GS::Array &buffer, bool verbose) const +{ + AutoPtr h(Open(uri)); + if (h.IsNull()) + { + if (verbose) + __LOG_W__ << "Failed to open '" << uri << "'.\n"; + return false; + } + + // Warning: Do not load through IO::Base::FileLoad. That would create another handle! + size_t size = h->GetSize(); + if (!buffer.Allocate(size)) + __ERR__(__LOG_W__ << "Failed to allocate memory to load '" << uri << "'.\n", false) + + return asbool(h->Read(buffer.c_ptr(), size) == size); +} +bool Filesystem::FileSave(const char *uri, const GS::Array &buffer) const +{ + AutoPtr h(Open(uri, ModeWrite)); + if (h.IsNull()) + __ERR__(__LOG_W__ << "Failed to open '" << uri << "'.\n", false) + return asbool(h->Write(buffer.c_ptr(), buffer.GetSize()) == buffer.GetSize()); +} +bool Filesystem::FileCopy(const char *src, const char *dst) const +{ + Array buffer; + return FileLoad(src, buffer) && FileSave(dst, buffer); +} +bool Filesystem::FileMove(const char *src, const char *dst) const +{ + Array buffer; + return FileLoad(src, buffer) && FileSave(dst, buffer) && Delete(src); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String Filesystem::MapToAbsolute(const char *uri) const +{ + String _uri(uri); + ListForeachPtr(MountPoint *, m, mount_list) + if (_uri.StartsWith(m->mount_point)) + return m->io_sys->MapToAbsolute(_uri.Mid(m->mount_point.Len())).CleanFilePath(); + + ListForeachPtr(Base *, i, root_mount) + { + AutoPtr h(i->Open(_uri)); + if (h.IsValid()) + return i->MapToAbsolute(_uri).CleanFilePath(); + } + return _uri; +} +String Filesystem::StripRootPath(const char *path) const +{ + String _path(path); + _path.FileCleanName(); + ListForeachPtr(Base *, i, root_mount) + { + String rpath = i->MapToRelative(_path); + if (!rpath.IsEmpty()) + if (rpath != _path) + return rpath[0] == '/' ? rpath.Mid(1) : rpath; // Ensure no leading '/' remains. + } + return _path; +} +bool Filesystem::Mount(Base *io_sys, const char *mount_point) +{ + if (mount_point) + { + ListForeachPtr(MountPoint *, m, mount_list) + if (m->mount_point == mount_point) + { + delete io_sys; + return false; + } + + + return asbool(mount_list.Prepend(new MountPoint(mount_point, io_sys))); + } + else + { + ListForeachPtr(Base *, i, root_mount) + if (i == io_sys) + __ERR__(__LOG_E__ << "Cannot mount IO system twice as root.\n", false) + + return asbool(root_mount.Prepend(io_sys)); + } +} +void Filesystem::Unmount(const char *mount_point) +{ Unmount(GetIOSystem(mount_point)); } +void Filesystem::Unmount(Base *io_sys) +{ + ListForeachPtr(MountPoint *, m, mount_list) + if (m->io_sys.c_ptr() == io_sys) + mount_list.Remove(m); + ListForeachPtr(Base *, i, root_mount) + if (i == io_sys) + root_mount.Remove(i); +} +void Filesystem::UnmountAll() +{ + ListForeachPtr(MountPoint *, m, mount_list) + mount_list.Remove(m); + while (List ::Item *m = root_mount.GetRoot()) + root_mount.Remove(m); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Base *Filesystem::GetIOSystem(const char *mount_point) const +{ + ListForeachPtr(MountPoint *, m, mount_list) + if (m->mount_point == mount_point) + return m->io_sys; + return NULL; +} +const char *Filesystem::GetMountPoint(const Base *io_sys) const +{ + ListForeachPtr(MountPoint *, m, mount_list) + if (m->io_sys == io_sys) + return m->mount_point; + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *Filesystem::Open(const char *uri, Mode mode) const +{ + String _uri(uri); + + if (_uri.IsEmpty()) + return NULL; + + ListForeachPtr(MountPoint *, m, mount_list) + if (_uri.StartsWith(m->mount_point)) + return m->io_sys->Open(_uri.Mid(m->mount_point.Len()), mode); + ListForeachPtr(Base *, i, root_mount) + if (Handle *h = i->Open(uri, mode)) + return h; + + return NULL; +} +void Filesystem::Close(Handle *h) const +{ + ListForeachPtr(MountPoint *, m, mount_list) + if (m->io_sys.c_ptr() == h->GetIOSystem()) + m->io_sys->Close(h); + ListForeachPtr(Base *, i, root_mount) + if (i == h->GetIOSystem()) + i->Close(h); +} +bool Filesystem::Delete(const char *uri) const +{ + AutoPtr h(Open(uri)); + if (h.IsValid()) + { + Base *io_sys = h->GetIOSystem(); + h = NULL; + return io_sys->Delete(uri); + } + else + return asbool(unlink(uri) == 0); + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Filesystem::MkDir(const char *path) const +{ + String _path(path); + + if (_path.IsEmpty()) + return false; + + ListForeachPtr(MountPoint *, m, mount_list) + if (_path.StartsWith(m->mount_point)) + return m->io_sys->MkDir(_path.Mid(m->mount_point.Len())); + + // [EJ] No creation on a root filesystem here! + return false; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/ftp_lib.cpp b/include/platform/filesystem/ftp_lib.cpp new file mode 100644 index 0000000..ed34b8a --- /dev/null +++ b/include/platform/filesystem/ftp_lib.cpp @@ -0,0 +1,984 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/ftp_lib.h" + #include "nstring/nstring.h" + #include "platform_config.h" + #include "alloc/ialloc.h" + #include "log/log.h" + + using namespace GS; + + #define ConnectionBufferSize 1024 + +#if __PLATFORM_WINDOWS__ + +#define SETSOCKOPT_OPTVAL_TYPE (const char *) +#define net_read(x,y,z) recv(x,(char*)y,z,0) +#define net_write(x,y,z) send(x,(char*)y,z,0) +#define net_close closesocket +typedef int socklen_t; + +#elif (__PLATFORM_LINUX__ || __PLATFORM_OSX__) + + #include + #include + #include + #include + #include + +#define SETSOCKOPT_OPTVAL_TYPE (void *) +#define net_read read +#define net_write write +#define net_close close +#define SOCKET int + +#endif + + +//------------------------------------------------------------------------------ +#if (__PLATFORM_WINDOWS__ || __PLATFORM_LINUX__ || __PLATFORM_OSX__) + + +#define FTP_PROPAGATE_ERROR__(__C__) { State s = __C__; if (s != FtpOk) return s; } + + + #include + #include + #include + #include + #include + #include + + +//---------------------------- +FtpConnection::FtpConnection() +//---------------------------- +{ + handle = -1; + ready = false; + + buffer = 0; + buffer_usage = 0; +} + +//--------------------------------------------- +void FtpConnection::FreeBuffer() +//--------------------------------------------- +{ _safe_delete_array(buffer); } + +//------------------------------------------------- +bool FtpConnection::AllocateBuffer() +//------------------------------------------------- +{ + FreeBuffer(); + return (buffer = new char[ConnectionBufferSize]) != NULL ? true : false; +} + +//------------------------------------------------------------------- +FtpLibrary::State FtpLibrary::WaitSocket(FtpConnection *connection) +//------------------------------------------------------------------- +{ + fd_set fd, *rfd = NULL, *wfd = NULL; + + FD_ZERO(&fd); + if (connection->direction == FtpConnection::Upload) + wfd = &fd; + else + rfd = &fd; + + forever + { + FD_SET(connection->handle, &fd); + + // 5 seconds timeout. + timeval tv; + tv.tv_sec = 4; + tv.tv_usec = 100000; + + SOCKET rv = select((int)(connection->handle + 1), rfd, wfd, NULL, &tv); + + if (rv == -1) + return FtpError; + else if (!rv) + return FtpSocketTimeout; + else + break; +/* + if (!IdleCallback()) + FtpSocketTimeout; +*/ + } + return FtpOk; +} + +//--------------------------------------------------- +bool FtpLibrary::CheckResponse(char c) +//--------------------------------------------------- +{ + char match[5]; + int length; + if (ReadASCII(response, 256, &master_connection, length) != FtpOk) + return false; + + if (response[3] == '-') + { + strncpy(match, response, 3); + match[3] = ' '; + match[4] = '\0'; + + do + { + if (ReadASCII(response, 256, &master_connection, length) != FtpOk) + return false; + } while (strncmp(response, match, 4)); + } + return (response[0] == c) ? true : false; +} + +//------------------------------------------------------- +bool FtpLibrary::Connect(const char *host) +//------------------------------------------------------- +{ + sockaddr_in sin; + memset(&sin,0,sizeof(sin)); + sin.sin_family = AF_INET; + + char *lhost = strdup(host), *pnum = strchr(lhost,':'); + + servent *pse; + if (!pnum) + { + if ((pse = getservbyname("ftp", "tcp")) == NULL) + __ERR__(__LOG__ << "[!] (FTP) Failed to get service port.\n", false) + sin.sin_port = pse->s_port; + } + else + { + *pnum++ = 0; + if (isdigit(*pnum)) + sin.sin_port = htons((u_short)atoi(pnum)); + else + { + pse = getservbyname(pnum, "tcp"); + sin.sin_port = pse->s_port; + } + } + +#if __PLATFORM_WINDOWS__ + if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1) +#else + if (!inet_aton(lhost, &sin.sin_addr)) +#endif + { + hostent *phe; + if ((phe = gethostbyname(lhost)) == NULL) + __ERR__(__LOG__ << "[!] (FTP) Failed to resolve host.\n", false) + memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length); + } + free(lhost); + + //------------------------------------------------------------------------------------------------------- + #define __ConnectError__(_S_)\ + { __LOG__ << _S_; net_close(master_connection.handle); master_connection.handle = 0; return false; } + //------------------------------------------------------------------------------------------------------- + + master_connection.handle = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (master_connection.handle == -1) + __ConnectError__("[!] (FTP) Failed to create socket.\n") + + int on = 1; + if (setsockopt(master_connection.handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1) + __ConnectError__("[!] (FTP) Set socket option failed.\n") + if (connect(master_connection.handle, (struct sockaddr *)&sin, sizeof(sin)) == -1) + __ConnectError__("[!] (FTP) Socket failed to connect.\n") + if (!CheckResponse('2')) + __ConnectError__("") + + return true; +} + +//----------------------------------------------------------------- +bool FtpLibrary::CheckPASVResponse(unsigned char *v) +//----------------------------------------------------------------- +{ + sockaddr sa; + socklen_t l = sizeof(sa); + + if (getpeername(master_connection.handle, &sa, &l) == -1) + { + net_close(master_connection.handle); + return false; + } + for (int i = 2; i < 6; ++i) + v[i] = sa.sa_data[i]; + + return true; +} + +//--------------------------------------------------------------------------- +bool FtpLibrary::FtpSendCmd(const char *command, char expresp) +//--------------------------------------------------------------------------- +{ + if (!master_connection.handle) + return 0; + + char ftp_command[256]; + _snprintf(ftp_command, 255, "%s\r\n", command); + if (net_write(master_connection.handle, ftp_command, (int)strlen(ftp_command)) <= 0) + return false; + + SendCommandCallback(ftp_command); + return CheckResponse(expresp); +} + +//--------------------------------------------------------------------------- +bool FtpLibrary::Login(const char *user, const char *password) +//--------------------------------------------------------------------------- +{ + char ftp_command[64]; + + // Send user. + _snprintf(ftp_command, 63, "USER %s", user); + if (!FtpSendCmd(ftp_command, '3')) + { + if (*GetLastResponse() == '2') + return true; + return false; + } + + // Send password. + _snprintf(ftp_command, 63, "PASS %s", password); + return FtpSendCmd(ftp_command, '2'); +} + +//------------------------------------------------------------------------------------------------------------------------------ +FtpConnection *FtpLibrary::CreatePORTConnection(TransferMode mode, FtpConnection::Direction dir, char *connection_command) +//------------------------------------------------------------------------------------------------------------------------------ +{ + union + { + sockaddr sa; + sockaddr_in in; + } sin; + + // Create the new connection. + FtpConnection *connection = new FtpConnection; + if (!connection) + __ERR__(__LOG__ << "[!] (FTP) Failed to allocate new connection object.\n", NULL) + + // Get socket from the master connection. + socklen_t l = sizeof(sin); + if (getsockname(master_connection.handle, &sin.sa, &l) < 0) + return connection; + + // Create socket. + connection->handle = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (connection->handle == -1) + return connection; + + // Set socket options. + int on = 1; + if (setsockopt(connection->handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1) + return connection; + + linger lng = { 0, 0 }; + if (setsockopt(connection->handle, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE &lng, sizeof(lng)) == -1) + return connection; + + // Bind socket. + sin.in.sin_port = 0; + if ( + (bind(connection->handle, &sin.sa, sizeof(sin)) == -1) || + (listen(connection->handle, 1) < 0) || + (getsockname(connection->handle, &sin.sa, &l) < 0) + ) + return connection; + + // Open PORT connection. + char ftp_command[256]; + _snprintf(ftp_command, 255, "PORT %hhu,%hhu,%hhu,%hhu,%hhu,%hhu", + (unsigned char)sin.sa.sa_data[2], + (unsigned char)sin.sa.sa_data[3], + (unsigned char)sin.sa.sa_data[4], + (unsigned char)sin.sa.sa_data[5], + (unsigned char)sin.sa.sa_data[0], + (unsigned char)sin.sa.sa_data[1] ); + + if (!FtpSendCmd(ftp_command, '2')) + return connection; + + // Handle resuming. + if (offset) + { + _snprintf(ftp_command, 255, "REST %lld", offset); + if (!FtpSendCmd(ftp_command, '3')) + return connection; // TODO allow for a full restart here? + } + + // Allocate buffer for binary transaction. + if ((mode == TransferASCII) && !connection->AllocateBuffer()) + return connection; + + // Finally send the connection command. + if (!FtpSendCmd(connection_command, '1')) + return connection; + + // Connection is ready. + connection->direction = dir; + connection->ready = true; + return connection; +} + +//------------------------------------------------------------------------------------------------------------------------------ +FtpConnection *FtpLibrary::CreatePASVConnection(TransferMode mode, FtpConnection::Direction dir, char *connection_command) +//------------------------------------------------------------------------------------------------------------------------------ +{ + // Set PASV mode. + if (!FtpSendCmd("PASV", '2')) + return NULL; + + // Check server answer. + char *cp = strchr(response,'('); + if (!cp) + return NULL; + + unsigned char v[6]; + sscanf(++cp, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &v[2], &v[3], &v[4], &v[5], &v[0], &v[1]); + if (correctpasv && !CheckPASVResponse(v)) + __ERR__(__LOG__ << "[!] (FTP) Incorrect PASV response.\n", NULL) + + struct sockaddr sa; + sa.sa_family = AF_INET; + sa.sa_data[2] = v[2]; + sa.sa_data[3] = v[3]; + sa.sa_data[4] = v[4]; + sa.sa_data[5] = v[5]; + sa.sa_data[0] = v[0]; + sa.sa_data[1] = v[1]; + + // Handle resume. + char ftp_command[256]; + + if (offset) + { + _snprintf(ftp_command, 255, "REST %lld", offset); + if (!FtpSendCmd(ftp_command, '3')) + return NULL; + } + + // Create the new connection. + FtpConnection *connection = new FtpConnection; + if (!connection) + __ERR__(__LOG__ << "[!] (FTP) Failed to allocate new connection object.\n", NULL) + + // Create socket. + int on = 1; + linger lng = { 0, 0 }; + connection->handle = (int)socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); + if ( + (connection->handle == -1) || + (setsockopt(connection->handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1) || + (setsockopt(connection->handle, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE &lng, sizeof(lng)) == -1) + ) + return connection; + + // Setup connection. + _snprintf(ftp_command, 255, "%s\r\n", connection_command); + if (net_write(master_connection.handle, ftp_command, (int)strlen(ftp_command)) <= 0) + return connection; + + // Connect socket. + if ((connect(connection->handle, &sa, sizeof(sa)) == -1) || !CheckResponse('1')) + return connection; + + // Allocate buffer for binary transaction. + if ((mode == TransferASCII) && !connection->AllocateBuffer()) + return connection; + + // Connection is ready. + connection->direction = dir; + connection->ready = true; + return connection; +} + +//---------------------------------------------------------------------------- +bool FtpLibrary::FtpAcceptConnection(FtpConnection *connection) +//---------------------------------------------------------------------------- +{ + // Reset all connections. + fd_set mask; + + FD_ZERO(&mask); + FD_SET(master_connection.handle, &mask); + FD_SET(connection->handle, &mask); + + // Setup timeout. + timeval tv; + tv.tv_usec = 0; + tv.tv_sec = 30; + + // Select handle. + int i = (int)master_connection.handle; + if (i < connection->handle) + i = connection->handle; + i = select((int)(i + 1), &mask, NULL, NULL, &tv); + + switch (i) + { + case -1: // Error. + strncpy(response, strerror(errno), sizeof(response)); + break; + + case 0: // Time out. + strcpy(response, "Time out waiting for connection."); + break; + + default: + if (FD_ISSET(connection->handle, &mask)) + { + sockaddr addr; + socklen_t l = sizeof(addr); + int handle = (int)accept(connection->handle, &addr, &l); + i = errno; + net_close(connection->handle); + + if (handle > 0) + { + connection->handle = handle; + return true; + } + + strncpy(response, strerror((int)i), sizeof(response)); + connection->handle = 0; + return false; + } + else + if (FD_ISSET(connection->handle, &mask)) + CheckResponse('2'); + + break; + } + + net_close(connection->handle); + connection->handle = 0; + return false; +} + +//------------------------------------------------------------------------------ +FtpConnection *FtpLibrary::CreateConnection(const char *path, AccessType type, TransferMode mode) +{ + if (!path && ((type == AccessFileWrite) || (type == AccessFileRead) || (type == AccessFileReadAppend) || (type == AccessFileWriteAppend))) + __ERR__(__LOG__ << "[!] (FTP) Missing path argument.\n", NULL) + + // Setup transfer mode. + char ftp_command[256]; + _snprintf(ftp_command, 255, "TYPE %c", mode); + if (!FtpSendCmd(ftp_command, '2')) + __ERR__(__LOG__ << "[!] (FTP) Failed to set tranfer mode.\n", NULL) + + // Select sub command. + const char *sub_command; + FtpConnection::Direction direction = FtpConnection::Download; + + switch (type) + { + case AccessDir: + sub_command = "NLST"; + break; + + case AccessDirVerbose: + sub_command = "LIST -aL"; + break; + + case AccessFileReadAppend: + case AccessFileRead: + sub_command = "RETR"; + break; + + case AccessFileWriteAppend: + case AccessFileWrite: + sub_command = "STOR"; + direction = FtpConnection::Upload; + break; + + default: + __ERR__(__LOG__ << "[!] (FTP) Invalid access type.\n", NULL) + } + + // Append path. + if (path) + _snprintf(ftp_command, 255, "%s %s", sub_command, path); + + // Open connection. + FtpConnection *connection = NULL; + + switch (connection_mode) + { + case ConnectionPASV: + connection = CreatePASVConnection(mode, direction, ftp_command); + break; + + case ConnectionPORT: + connection = CreatePORTConnection(mode, direction, ftp_command); + if (!connection || !connection->ready) + break; + + if (!FtpAcceptConnection(connection)) + { + CloseConnection(connection); + return NULL; + } + break; + } + return connection; +} +bool FtpLibrary::CloseConnection(FtpConnection *connection) +{ + // Sanity check. + if (connection == &master_connection) + return false; + + // Purge writing cache. + int length; + if (connection->direction == FtpConnection::Upload) + if (connection->buffer) + WriteASCII(NULL, 0, connection, length); + + shutdown(connection->handle, 2); + net_close(connection->handle); + _safe_delete(connection); + + return CheckResponse('2'); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +FtpLibrary::State FtpLibrary::ReadASCII(char *buf, int max, FtpConnection *connection, int &total_read_count) +{ +/// TODO + // Early exit case. + if (max == 0) + return FtpOk; + if ((connection != &master_connection) && (connection->direction != FtpConnection::Download)) + return FtpError; + + // Read. + total_read_count = 0; + char *p_buffer = buf; + + forever + { + // Check available data on cache. + if (connection->buffer_usage > 0) + { + // Determine read size. + char *eol = (char *)memchr(connection->buffer, '\n', connection->buffer_usage); + int read_size = (int)(eol ? eol - connection->buffer + 1 : connection->buffer_usage); + + if (read_size > (max - 1)) + read_size = max - 1; + + // Perform reading. + memcpy(p_buffer, connection->buffer, read_size); + + max -= read_size; + total_read_count += read_size; + p_buffer += read_size; + + // Update cache. + if (read_size < connection->buffer_usage) + memcpy(connection->buffer, &connection->buffer[read_size], connection->buffer_usage - read_size); + connection->buffer_usage -= read_size; + + // Catch end of buffer. + if ((max == 1) || eol) + { + p_buffer[0] = 0; + break; + } + } + + // Wait socket. + FTP_PROPAGATE_ERROR__(WaitSocket(connection)) + + // Fill cache. + int buffer_left = (ConnectionBufferSize - connection->buffer_usage) - 1, + read_count = net_read(connection->handle, &connection->buffer[connection->buffer_usage], buffer_left); + + connection->buffer_usage += read_count; + + if (read_count == -1) + __ERR__(__LOG__ << "[!] (FTP) Read error.\n", FtpError) + else if (!read_count) + break; // EOF + } + return FtpOk; +} +FtpLibrary::State FtpLibrary::WriteASCII(char *output, int length, FtpConnection *connection, int &x) +{ +/// TODO + if (connection->direction != FtpConnection::Upload) + return FtpError; + + FTP_PROPAGATE_ERROR__(WaitSocket(connection)) + if ((x = net_write(connection->handle, output, length)) != length) + return FtpError; + + return FtpOk; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +FtpLibrary::State FtpLibrary::ReadBinary(void *buf, int max, FtpConnection *connection, int &length) +{ + if (connection->direction != FtpConnection::Download) + return FtpError; + + FTP_PROPAGATE_ERROR__(WaitSocket(connection)) + length = net_read(connection->handle, buf, max); + if (length == -1) + return FtpError; + + DataReadCallback(connection); + return FtpOk; +} +FtpLibrary::State FtpLibrary::WriteBinary(void *buf, int len, FtpConnection *connection) +{ + if (connection->direction != FtpConnection::Upload) + return FtpError; + + FTP_PROPAGATE_ERROR__(WaitSocket(connection)) + if (net_write(connection->handle, buf, len) != len) + return FtpError; + + DataWriteCallback(connection); + return FtpOk; +} +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------------------------------------------------- +FtpLibrary::State FtpLibrary::DataTransfer(const char *localfile, const char *path, AccessType type, TransferMode mode) +//----------------------------------------------------------------------------------------------------------------------- +{ + // Open local file or I/O stream. + FILE *file; + + if (localfile) + { + const char *access; + + switch (type) + { + default: + case AccessDir: + case AccessDirVerbose: + case AccessFileRead: + access = (mode == TransferBinary) ? "wb" : "w"; + break; + + case AccessFileReadAppend: + access = (mode == TransferBinary) ? "ab" : "a"; + break; + + case AccessFileWriteAppend: + case AccessFileWrite: + access = (mode == TransferBinary) ? "rb" : "r"; + break; + } + + file = fopen(localfile, access); + if (!file) + __ERR__(__LOG_E__ << "Failed to open FTP output file.\n", FtpError) + + if (type == AccessFileWriteAppend) + if (fseek(file, offset, SEEK_SET)) + { + fclose(file); + __ERR__(__LOG_E__ << "Failed to seek in FTP file for transfer.\n", FtpError) + } + } + else + file = (type == AccessFileWrite || type == AccessFileWriteAppend) ? stdin : stdout; + + // Create a new connection. + FtpConnection *connection = CreateConnection(path, type, mode); + if (!connection) + { + if (localfile) + fclose(file); + return FtpError; + } + + // Perform transfer. + State retv = FtpOk; + GS::Array temp_buffer(ConnectionBufferSize); + int length; + + if ((type == AccessFileWrite) || (type == AccessFileWriteAppend)) + { + while ((length = (int)fread(temp_buffer, 1, ConnectionBufferSize, file)) > 0) + if (WriteBinary(temp_buffer, length, connection) != FtpOk) + { + retv = FtpError; // FTP write failed. + break; + } + } + else + { + while ((retv = ReadBinary(temp_buffer, ConnectionBufferSize, connection, length)) == FtpOk) + if (!length || (fwrite(temp_buffer, 1, length, file) <= 0)) + break; // Done. + } + + // Flush file. + fflush(file); + if (localfile) + fclose(file); + + CloseConnection(connection); + return retv; +} + +//------------------------------------------------------------------------------ +FtpLibrary::State FtpLibrary::Download(const char *file, const char *path, TransferMode mode, int _offset) +{ + offset = _offset; + if (!offset) + return DataTransfer(file, path, AccessFileRead, mode); + else return DataTransfer(file, path, AccessFileReadAppend, mode); +} +FtpLibrary::State FtpLibrary::Upload(const char *file, const char *path, TransferMode mode, int _offset) +{ + offset = _offset; + if (!offset) + return DataTransfer(file, path, AccessFileWrite, mode); + else return DataTransfer(file, path, AccessFileWriteAppend, mode); +} +//------------------------------------------------------------------------------ + +//------------------------------------ +bool FtpLibrary::Quit() +//------------------------------------ +{ + if (!master_connection.handle) + return true; + + bool r = FtpSendCmd("QUIT", '2'); + + net_close(master_connection.handle); + master_connection.handle = 0; + return r; +} + +//------------------------------------------------------------------------------ +bool FtpLibrary::DeleteFile(const char *path) +{ return FtpSendCmd(String::Format("DELE %s", path).c_str(), '2'); } +bool FtpLibrary::ChangeDirectory(const char *path) +{ return FtpSendCmd(String::Format("CWD %s", path).c_str(), '2'); } +bool FtpLibrary::UpDirectory() +{ return FtpSendCmd("CDUP", '2'); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int FtpLibrary::GetFileSize(const char *path, TransferMode mode) +//------------------------------------------------------------------------------ +{ + int rs, sz = -1; + if ( FtpSendCmd(String::Format("TYPE %c", mode).c_str(), '2') && + FtpSendCmd(String::Format("SIZE %s", path).c_str(), '2') && + (sscanf(response, "%d %d", &rs, &sz) == 2) ) + return sz; + return -1; +} + +//---------------------------------------------------------------------------- +bool FtpLibrary::Nlst(const char *outputfile, const char *path) +//---------------------------------------------------------------------------- +{ + offset = 0; + return DataTransfer(outputfile, path, FtpLibrary::AccessDir, FtpLibrary::TransferASCII) == FtpOk ? true : false; +} + +//------------------------------------------------------------------------------ +FtpLibrary::FtpLibrary() +{ +#if __PLATFORM_WINDOWS__ + WSADATA wsa; + if (WSAStartup(MAKEWORD(1, 1), &wsa)) + __LOG__ << "[!] (FTP) WINSOCK startup error.\n"; +#endif + + connection_mode = ConnectionPORT; + master_connection.AllocateBuffer(); + + // + offset = 0; + correctpasv = false; +} +FtpLibrary::~FtpLibrary() +{ Quit(); } +//------------------------------------------------------------------------------ + + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* +int FtpLibrary::Site(const char *cmd) +{ + char buf[256]; + + if ((strlen(cmd) + 7) > sizeof(buf)) return 0; + sprintf(buf,"SITE %s",cmd); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0; + return 1; +} + +int FtpLibrary::Raw(const char *cmd) +{ + char buf[256]; + strncpy(buf, cmd, 256); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0; + return 1; +} + +int FtpLibrary::SysType(char *buf, int max) +{ + int l = max; + char *b = buf; + char *s; + if (!FtpSendCmd("SYST",'2',mp_ftphandle)) return 0; + s = &mp_ftphandle->response[4]; + while ((--l) && (*s != ' ')) *b++ = *s++; + *b++ = '\0'; + return 1; +} + +int FtpLibrary::Mkdir(const char *path) +{ + char buf[256]; + + if ((strlen(path) + 6) > sizeof(buf)) return 0; + sprintf(buf,"MKD %s",path); + if (!FtpSendCmd(buf,'2', mp_ftphandle)) return 0; + return 1; +} + + +int FtpLibrary::Rmdir(const char *path) +{ + char buf[256]; + + if ((strlen(path) + 6) > sizeof(buf)) return 0; + sprintf(buf,"RMD %s",path); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0; + return 1; +} + +int FtpLibrary::Pwd(char *path, int max) +{ + int l = max; + char *b = path; + char *s; + + if (!FtpSendCmd("PWD",'2',mp_ftphandle)) return 0; + s = strchr(mp_ftphandle->response, '"'); + if (s == NULL) return 0; + s++; + while ((--l) && (*s) && (*s != '"')) *b++ = *s++; + *b++ = '\0'; + return 1; +} + +int FtpLibrary::Dir(const char *outputfile, const char *path) +{ + mp_ftphandle->offset = 0; + return FtpXfer(outputfile, path, mp_ftphandle, FtpLibrary::dirverbose, FtpLibrary::ascii); +} + +int FtpLibrary::ModDate(const char *path, char *dt, int max) +{ + char buf[256]; + int rv = 1; + + if ((strlen(path) + 7) > sizeof(buf)) return 0; + sprintf(buf,"MDTM %s",path); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) rv = 0; + else strncpy(dt, &mp_ftphandle->response[4], max); + return rv; +} + +int FtpLibrary::Rename(const char *src, const char *dst) +{ + char cmd[256]; + + if (((strlen(src) + 7) > sizeof(cmd)) || ((strlen(dst) + 7) > sizeof(cmd))) return 0; + sprintf(cmd,"RNFR %s",src); + if (!FtpSendCmd(cmd,'3',mp_ftphandle)) return 0; + sprintf(cmd,"RNTO %s",dst); + if (!FtpSendCmd(cmd,'2',mp_ftphandle)) return 0; + + return 1; +} + + + + +void FtpLibrary::SetConnmode(connmode mode) +{ + mp_ftphandle->cmode = mode; +} + +ftphandle* FtpLibrary::RawOpen(const char *path, accesstype type, transfermode mode) +{ + int ret; + ftphandle* datahandle; + ret = CreateConnection(path, type, mode, mp_ftphandle, &datahandle); + if (ret) return datahandle; + else return NULL; +} + +int FtpLibrary::RawClose(ftphandle* handle) +{ + return FtpClose(handle); +} + +int FtpLibrary::RawWrite(void* buf, int len, ftphandle* handle) +{ + return FtpWrite(buf, len, handle); +} + +int FtpLibrary::RawRead(void* buf, int max, ftphandle* handle) +{ + return FtpRead(buf, max, handle); +} +*/ diff --git a/include/platform/filesystem/io_base.cpp b/include/platform/filesystem/io_base.cpp new file mode 100644 index 0000000..f49f127 --- /dev/null +++ b/include/platform/filesystem/io_base.cpp @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/io_base.h" + #include "filesystem/io_handle.h" + #include "memory/nauto_ptr.h" + #include "nstring/nstring.h" + #include "hash/nsha1.h" + #include "log/log.h" + + using GS::String; + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +bool Base::FileLoad(const char *uri, GS::Array &buffer) +{ + AutoPtr h(Open(uri)); + if (h.IsNull()) + return false; + + size_t size = h->GetSize(); + if (!buffer.Allocate(size)) + return false; + + return asbool(h->Read(buffer.c_ptr(), size) == size); +} +bool Base::FileSave(const char *uri, const GS::Array &buffer) +{ + AutoPtr h(Open(uri, ModeWrite)); + if (h.IsNull()) + return false; + + return asbool(h->Write(buffer.c_ptr(), buffer.GetSize()) == buffer.GetSize()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Base::Exists(const char *uri) +{ + AutoPtr h(Open(uri, ModeRead)); + return h.IsValid(); +} +String Base::Hash(const char *uri) +{ + Array data; + return FileLoad(uri, data) ? SHA1::ComputeHexa(data) : String(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String Base::MapToAbsolute(const char *uri) const +{ return String(uri); } +String Base::MapToRelative(const char *path) const +{ return String(path); } +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/io_buffer.cpp b/include/platform/filesystem/io_buffer.cpp new file mode 100644 index 0000000..5d5b5a8 --- /dev/null +++ b/include/platform/filesystem/io_buffer.cpp @@ -0,0 +1,130 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/io_buffer.h" + #include "log/log.h" + #include "ntypes.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +uint Buffer::GetCaps() const { return io->GetCaps(); } + +Handle *Buffer::Open(const char *path, Mode mode) +{ + AutoPtr io_h(io->Open(path, mode)); + if (io_h.IsNull()) + return NULL; + + AutoPtr b_h(new BufferHandle(this, io_h)); + if (b_h.IsNull()) + return NULL; + + if (!b_h->read_buffer.buffer.Allocate(read_buffer_size)) + return NULL; + + b_h->size = io_h->GetSize(); + + io_h.Detach(); + return b_h.Detach(); +} +void Buffer::Close(Handle *h) +{ + if (BufferHandle *b_h = (BufferHandle *)h) + b_h->handle = NULL; +} + +bool Buffer::Delete(const char *path) { return io->Delete(path); } + +size_t Buffer::Tell(Handle *h) { return ((BufferHandle *)h)->pos; } +size_t Buffer::Seek(Handle *h, ptrdiff_t offset, SeekRef seek) +{ + if (BufferHandle *c_h = (BufferHandle *)h) + { + switch (seek) + { + case SeekStart: + c_h->pos = Types::Clamp (offset, 0, c_h->size); + break; + case SeekCurrent: + c_h->pos = Types::Clamp (c_h->pos + offset, 0, c_h->size); + break; + case SeekEnd: + c_h->pos = Types::Clamp (c_h->size + offset, 0, c_h->size); + break; + } + return 0; + } + return size_t(-1); +} +size_t Buffer::Read(Handle *h, void *data, size_t size) +{ +// __LOG_V__ << "Buffer::Read: size = " << size << ".\n"; + + size_t read_size = 0; + if (BufferHandle *b_h = (BufferHandle *)h) + { + while (read_size < size) + { + ptrdiff_t buffer_pos = (b_h->pos + read_size) - b_h->read_buffer.start_pos; + + if ((buffer_pos >= 0) && (buffer_pos < ptrdiff_t(b_h->read_buffer.usage))) + { + ptrdiff_t copy_size = Types::Min (b_h->read_buffer.usage - buffer_pos, size - read_size); + Memory::Copy((char *)data + read_size, b_h->read_buffer.buffer.c_ptr() + buffer_pos, copy_size); +// __LOG_V__ << "Buffer read: pos = " << buffer_pos << ", size = " << copy_size << ".\n"; + read_size += copy_size; + } + else // refill cache + { + b_h->read_buffer.start_pos = b_h->pos + read_size; + if (b_h->read_buffer.start_pos >= b_h->size) + { + b_h->read_buffer.usage = 0; + break; // EJ 01/05: Improves EOF performance for the OGG streaming interface which makes many out of bound calls. + } + + io->Seek(b_h->handle, b_h->read_buffer.start_pos, SeekStart); + b_h->read_buffer.usage = io->Read(b_h->handle, b_h->read_buffer.buffer.c_ptr(), b_h->read_buffer.buffer.GetSize()); +// __LOG_V__ << "Buffer fill: pos = " << b_h->read_buffer.start_pos << ", size = " << b_h->read_buffer.usage << ".\n"; + if (b_h->read_buffer.usage == 0) + break; // EOF + } + } + b_h->pos += read_size; + } + return read_size; +} +size_t Buffer::Write(Handle *h, const void *data, size_t size) +{ + if (BufferHandle *b_h = (BufferHandle *)h) + { + size_t write_size = io->Write(b_h->handle, data, size); + b_h->pos += write_size; + return write_size; + } + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +GS::String Buffer::Hash(const char *path) +{ return io->Hash(path); } // [EJ] Do not perform a FileLoad here, IO::Buffer is typically sitting in front of a slow IO backend which potentially optimizes hash transfer. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Buffer::MkDir(const char *path) +{ return io->MkDir(path); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Buffer::Buffer(Base *base, size_t read_size, size_t write_size) : io(base) +{ + read_buffer_size = Types::Clamp (read_size, 0, Units::MB(16)); + write_buffer_size = Types::Clamp (write_size, 0, Units::MB(16)); +} +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/io_cache.cpp b/include/platform/filesystem/io_cache.cpp new file mode 100644 index 0000000..9e62d33 --- /dev/null +++ b/include/platform/filesystem/io_cache.cpp @@ -0,0 +1,280 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/io_cache.h" + #include "hash/nsha1.h" + #include "platform.h" + #include "log/log.h" + #include "ntypes.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +struct FreeEntry // should be in ReserveOnStore but local type on template is prohibited until C++0x +{ + Cache::Entry *entry; + int score; + + FreeEntry(Cache::Entry *e, int s) : entry(e), score(s) {} + +static int ComputeScore(const Cache::Entry *e, size_t request_size, const GS::Time &ctime) + { + int time_bonus = (int)(ctime - e->last_use).toSec(); + int size_bonus = e->size - request_size; + + return time_bonus + size_bonus / 8; + } +static int CompareScore(FreeEntry *a, FreeEntry *b) + { return b->score - a->score; } +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +GS::String Cache::ReserveOnStore(size_t size) +{ + String id = store.Reserve(size); + if (!id.IsEmpty()) + return id; + + // Build a list of reference free entries. + Time ctime = Platform::Get().GetTime(); + + // No need to drop anything if the request can't fit anyway... + size_t total_freeable_store = 0; + ListForeachPtr(Entry *, e, entries) + if (e->refc == 0) + total_freeable_store += e->size; + + if (size > (store.GetFreeStore() + total_freeable_store)) + return ""; + + // Drop entries until the request fits in the store. + List free_entries; + ListForeachPtr(Entry *, e, entries) + if (e->refc == 0) + free_entries.Add(new FreeEntry(e, FreeEntry::ComputeScore(e, size, ctime))); + + free_entries.MergeSort(FreeEntry::CompareScore); + + ListForeachPtr(FreeEntry *, e, free_entries) + { + __LOG_V__ << "IO::Cache: Disposing of cache entry '" << e->entry->path << "' (score: " << e->score << ").\n"; + + DeleteCacheEntry(e->entry); + + id = store.Reserve(size); + if (!id.IsEmpty()) + break; + } + + ListDeleteAllPtr(FreeEntry *, free_entries) + + store.Save(); + return id; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Cache::Entry *Cache::GetCacheEntry(const char *path) const +{ + ListForeachPtr(Entry *, entry, entries) + if (entry->path == path) + return entry; + return NULL; +} +Cache::Entry *Cache::CreateCacheEntry(const char *path) +{ + __LOG_V__ << "Create cache entry for '" << path << "'.\n"; + + Array data; + if (!io->FileLoad(path, data)) + return NULL; + + AutoPtr entry(new Entry); + if (entry.IsNull()) + return NULL; + + entry->path = path; + entry->id = ReserveOnStore(data.GetSize()); + if (entry->id.IsEmpty()) + return NULL; // store full + + Entry *e = entry.Detach(); + entries.Add(e); + + return UpdateCacheEntry(e, &data) ? e : NULL; +} +bool Cache::UpdateCacheEntry(Entry *entry, GS::Array *preloaded_data) +{ + __LOG_V__ << "Update cache entry for '" << entry->path << "'.\n"; + + Array data; + if (preloaded_data) + data.Transfer(*preloaded_data); + else + if (!io->FileLoad(entry->path, data)) + return false; + + // Check current store entry size. + if (store.GetEntrySize(entry->id) != data.GetSize()) + { + store.Free(entry->id); + entry->id = ReserveOnStore(data.GetSize()); + + if (entry->id.IsEmpty()) + return false; // store is full + } + + // Update store data. + if (!store.Store(entry->id, data.c_ptr(), data.GetSize(), entry->path)) + return false; + store.Save(); + + entry->hash = SHA1::ComputeHexa(data); + entry->size = data.GetSize(); + return true; +} +bool Cache::DeleteCacheEntry(Entry *entry) +{ + if (entry->refc > 0) + return false; + + store.Free(entry->id); + store.Save(); + + return entries.Remove(entry); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Cache::GetCaps() const { return io->GetCaps(); } + +Handle *Cache::Open(const char *path, Mode mode) +{ + if (mode == ModeRead) + { + Threading::MutexLock lock(&mutex); + + // Update cache. + Entry *entry = GetCacheEntry(path); + + if (entry) + { + __LOG_V__ << "Entry match for '" << path << "'.\n"; + + if (entry->hash != io->Hash(path)) + { + __LOG_V__ << "Hash mismatch for '" << path << "'.\n"; + + if (entry->refc > 0) + __LOG_W__ << "IO::Cache: Support file '" << entry->path << "' has changed but its cached version is in use and cannot be updated.\n"; + else + { + if (!UpdateCacheEntry(entry)) // contention risk here due to the mutex lock and a potentially long update (eg. networked fs) + DeleteCacheEntry(entry); + + // Check for a match in updated cache. + entry = GetCacheEntry(path); + } + } + } + else + entry = CreateCacheEntry(path); + + // Return handler to store fs. + if (entry) + { + __LOG_V__ << "Opening '" << path << "' from cache.\n"; + + entry->last_use = Platform::Get().GetTime(); + entry->refc++; + + return new CacheHandle(this, path, store.GetIO()->Open(entry->id, mode)); + } + } + + // Direct access to the underlying fs. + return io->Open(path, mode); +} +void Cache::Close(Handle *h) +{ + if (CacheHandle *c_h = (CacheHandle *)h) + { + Threading::MutexLock lock(&mutex); + + if (Entry *entry = GetCacheEntry(c_h->path)) + entry->refc--; + c_h->handle = NULL; + } +} + +bool Cache::Delete(const char *path) +{ + /* + [EJ] Minor synchronization issue warning. + + If a cached handle is already in use and the support fs file is deleted + the cached handle will remain valid. Further open requests will then + unexpectedly succeed as long as a single cached handler remains open. + + The correct fix would be to prevent deleting a support file as long as + a cached entry with a non-zero reference count exists for it. + */ + return io->Delete(path); +} + +size_t Cache::Tell(Handle *h) +{ return ((CacheHandle *)h)->handle->Tell(); } +size_t Cache::Seek(Handle *h, ptrdiff_t offset, SeekRef seek) +{ return ((CacheHandle *)h)->handle->Seek(offset, seek); } + +size_t Cache::Read(Handle *h, void *data, size_t size) +{ return ((CacheHandle *)h)->handle->Read(data, size); } +size_t Cache::Write(Handle *h, const void *data, size_t size) +{ return ((CacheHandle *)h)->handle->Write(data, size); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Cache::SynchronizeWithStore(const char *store_path) +{ + if (!store.Load(store_path)) + return false; + + entries.Clear(); + + __LOG_H__ << "IO::Cache: Synchronizing with store.\n"; + + ListForeachPtr(DataStore::Entry *, e, store.GetEntries()) + { + Entry *entry = new Entry; + + entry->id = e->id; + entry->size = e->size; + entry->path = e->user; + entry->hash = store.GetIO()->Hash(entry->id); + + entries.Add(entry); + } + + __LOG__ << "Done, " << entries.GetCount() << " entries synchronized.\n"; + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Cache::MkDir(const char *path) +{ return io->MkDir(path); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Cache::Cache(Base *base, Base *store_io, size_t store_size) : io(base), store(store_io, store_size) {} +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------- +CacheHandle::~CacheHandle() +{ GetIOSystem()->Close(this); } +//----------------------------------------------------------------------------- diff --git a/include/platform/filesystem/io_cfile.cpp b/include/platform/filesystem/io_cfile.cpp new file mode 100644 index 0000000..a755ee1 --- /dev/null +++ b/include/platform/filesystem/io_cfile.cpp @@ -0,0 +1,137 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #if __PLATFORM_POSIX__ + #include + #include + #elif __PLATFORM_WINDOWS__ + #include + #endif + #include "filesystem/io_cfile.h" + #include "memory/nauto_ptr.h" + + using GS::String; + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +void CFile::SetRootPath(const char *_root) +{ root = _root; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint CFile::GetCaps() const +{ + uint flags = CanRead | CanWrite | CanSeek | CanMkDir; +#ifndef __PLATFORM_WINDOWS__ + flags |= IsCaseSensitive; +#endif + return flags; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String CFile::MapToAbsolute(const char *uri) const +{ + if (!root.IsEmpty()) + return root + "/" + uri; + return String(uri); +} +String CFile::MapToRelative(const char *path) const +{ + String _path(path); + if (!root.IsEmpty() && _path.StartsWith(root, GetCaps() & IsCaseSensitive ? String::CaseSensitive : String::CaseInsensitive)) + return _path.Mid(root.Len()); + return _path; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *CFile::Open(const char *path, Mode mode) +{ + String _path(root.IsEmpty() ? path : (root + "/" + path).c_str()), + _access(mode == ModeRead ? "rb" : "wb"); + + AutoPtr h(new CFileHandle(this)); +#if __PLATFORM_WINDOWS__ + if (h->file = _wfopen((const wchar_t *)_path.toUcs2().c_ptr(), (const wchar_t *)_access.toUcs2().c_ptr())) + return h.Detach(); +#else + if ((h->file = fopen(_path, _access)) != NULL) + return h.Detach(); +#endif + return NULL; +} +void CFile::Close(Handle *h) +{ + if (CFileHandle *ch = (CFileHandle *)h) + if (ch->file) + fclose(ch->file); +} + +bool CFile::Delete(const char *uri) +{ return asbool(unlink(root + "/" + uri) == 0); } + +size_t CFile::Seek(Handle *h, ptrdiff_t offset, SeekRef ref) +{ + if (CFileHandle *ch = (CFileHandle *)h) + if (ch->file) + { + int c_seek[] = { SEEK_SET, SEEK_CUR, SEEK_END }; + return fseek(ch->file, offset, c_seek[ref]); + } + return (size_t)-1; +} +size_t CFile::Tell(Handle *h) +{ + if (CFileHandle *ch = (CFileHandle *)h) + if (ch->file) + return ftell(ch->file); + return (size_t)-1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t CFile::Read(Handle *h, void *b, size_t size) +{ + if (CFileHandle *ch = (CFileHandle *)h) + if (ch->file) + return fread(b, 1, size, ch->file); + return 0; +} +size_t CFile::Write(Handle *h, const void *b, size_t size) +{ + if (CFileHandle *ch = (CFileHandle *)h) + if (ch->file) + return fwrite(b, size, 1, ch->file) * size; + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool CFile::MkDir(const char *path) +{ + String _path(root.IsEmpty() ? path : (root + "/" + path).c_str()); + + bool r = false; +#if __PLATFORM_WINDOWS__ + r = _wmkdir((const wchar_t *)_path.toUcs2().c_ptr()) == 0; +#else + r = mkdir(path, 01777) == 0; +#endif + return r; +} +//------------------------------------------------------------------------------ + +CFile::CFile(const char *root_path) +{ SetRootPath(root_path); } + +//------------------------------------------------------------------------------ +CFileHandle::CFileHandle(Base *io) : Handle(io) +{ file = NULL; } +CFileHandle::~CFileHandle() +{ GetIOSystem()->Close(this); } +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/io_crypto.cpp b/include/platform/filesystem/io_crypto.cpp new file mode 100644 index 0000000..fcca039 --- /dev/null +++ b/include/platform/filesystem/io_crypto.cpp @@ -0,0 +1,173 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/io_crypto.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +uint Crypto::GetCaps() const +{ return wrapped_io->GetCaps(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Crypto::Encrypt(GS::Array &data) +{ + size_t len = key.Len(); + for (size_t n = 0; n < data.GetSize(); ++n) + data[(int)n] = data[(int)n] ^ key[(int)(n % len)]; +} +void Crypto::Decrypt(GS::Array &data) +{ + size_t len = key.Len(); + for (size_t n = 0; n < data.GetSize(); ++n) + data[(int)n] = data[(int)n] ^ key[(int)(n % len)]; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *Crypto::Open(const char *path, Mode mode) +{ + /* + When opening a file in read mode, the wrapped io file is decrypted and + stored in the cached io file system for further access. + When opening a file in write mode, the file is first created in clear + on the cached io then encrypted and committed to the wrapped io. + */ + Handle *h = NULL; + + switch (mode) + { + case ModeRead: + { + // Load wrapped IO file. + AutoPtr _h(wrapped_io->Open(path, mode)); + if (_h.IsNull()) + break; + + size_t size = _h->GetSize(); + Array data(size); + if (data.IsNull()) + break; + if (_h->Read(data.c_ptr(), size) != size) + break; + + // Decrypt buffer. + Decrypt(data); + + // Write decrypted content to cache IO. + if ((h = cache_io->Open(path, ModeWrite)) != NULL) + h->Write(data.c_ptr(), size); + _safe_delete(h); + + h = cache_io->Open(path, mode); + } + break; + + case ModeWrite: + h = cache_io->Open(path, mode); + break; + + default: break; + } + + return h ? new CryptoHandle(this, h, path, mode) : NULL; +} +void Crypto::Close(Handle *_h) +{ + if (CryptoHandle *h = (CryptoHandle *)_h) + { + h->cached_h = NULL; + + switch (h->io_mode) + { + case ModeRead: + cache_io->Delete(h->path); + break; + + case ModeWrite: + { + // Retrieve the whole cached file content and drop it from the cache IO. + h->cached_h = cache_io->Open(h->path); + + size_t size = h->cached_h->GetSize(); + Array data(size); + + if (data.IsValid()) + h->cached_h->Read(data.c_ptr(), size); + + h->cached_h = NULL; + cache_io->Delete(h->path); + + // Encrypt buffer. + Encrypt(data); + + // Commit file to the wrapped IO. + AutoPtr _h(wrapped_io->Open(h->path, ModeWrite)); + if (_h.IsValid()) + _h->Write(data.c_ptr(), size); + } + break; + + default: break; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Crypto::Delete(const char *path) +{ return wrapped_io->Delete(path); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t Crypto::Tell(Handle *_h) +{ + if (CryptoHandle *h = (CryptoHandle *)_h) + return h->cached_h->Tell(); + return (size_t)-1; +} +size_t Crypto::Seek(Handle *_h, ptrdiff_t offset, SeekRef seek) +{ + if (CryptoHandle *h = (CryptoHandle *)_h) + return h->cached_h->Seek(offset, seek); + return (size_t)-1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t Crypto::Read(Handle *_h, void *p, size_t s) +{ + if (CryptoHandle *h = (CryptoHandle *)_h) + return h->cached_h->Read(p, s); + return 0; +} +size_t Crypto::Write(Handle *_h, const void *p, size_t s) +{ + if (CryptoHandle *h = (CryptoHandle *)_h) + return h->cached_h->Write(p, s); + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Crypto::MkDir(const char *path) +{ return wrapped_io->MkDir(path); } +//------------------------------------------------------------------------------ + +Crypto::Crypto(Base *_io, const char *_key) : wrapped_io(_io) +{ + cache_io = new Memory; + key = _key; +} + +//------------------------------------------------------------------------------ +CryptoHandle::CryptoHandle(Base *io, Handle *h, const char *_path, Mode mode) : Handle(io), cached_h(h), path(_path), io_mode(mode) +{} +CryptoHandle::~CryptoHandle() +{ GetIOSystem()->Close(this); } +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/io_dispatcher.cpp b/include/platform/filesystem/io_dispatcher.cpp new file mode 100644 index 0000000..438fbfc --- /dev/null +++ b/include/platform/filesystem/io_dispatcher.cpp @@ -0,0 +1,141 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #if __PLATFORM_POSIX__ + #include + #endif + #include "filesystem/io_dispatcher.h" + #include "memory/nauto_ptr.h" + + using namespace GS; + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +bool Dispatcher::AddDispatch(Base *fs, const char *prefix) +{ + if (prefix) + { + DispatchFS *d = new DispatchFS; + if (!d) + return false; + + d->fs = fs; + d->prefix = prefix; + mounts.Add(d); + } + else + roots.Add(fs); + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Dispatcher::GetCaps() const +{ + uint flags = CanRead | CanWrite | CanSeek; +#ifndef __PLATFORM_WINDOWS__ + flags |= IsCaseSensitive; +#endif + return flags; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Base *Dispatcher::Dispatch(String &uri, Mode mode) +{ + ListForeachPtr(DispatchFS *, d, mounts) + if (uri.StartsWith(d->prefix)) + { + uri = uri.Mid(d->prefix.Len()); + return d->fs; + } + + // Root FS make no sense for write operations. + if (mode == ModeRead) + ListForeachPtr(Base *, d, roots) + if (d->Exists(uri)) + return d; + + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *Dispatcher::Open(const char *uri, Mode mode) +{ + String _uri(uri); + + Base *base = Dispatch(_uri, mode); + if (!base) + return NULL; + + Handle *h = base->Open(_uri, mode); + return h ? new DispatcherHandle(this, h) : NULL; +} +void Dispatcher::Close(Handle *h) +{ + if (DispatcherHandle *dh = (DispatcherHandle *)h) + dh->handle->GetIOSystem()->Close(dh->handle); +} +bool Dispatcher::Delete(const char *uri) +{ return false; } +size_t Dispatcher::Seek(Handle *h, ptrdiff_t offset, SeekRef ref) +{ + if (DispatcherHandle *dh = (DispatcherHandle *)h) + return dh->handle->GetIOSystem()->Seek(dh->handle, offset, ref); + return (size_t)-1; +} +size_t Dispatcher::Tell(Handle *h) +{ + if (DispatcherHandle *dh = (DispatcherHandle *)h) + return dh->handle->GetIOSystem()->Tell(dh->handle); + return (size_t)-1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t Dispatcher::Read(Handle *h, void *b, size_t size) +{ + if (DispatcherHandle *dh = (DispatcherHandle *)h) + return dh->handle->GetIOSystem()->Read(dh->handle, b, size); + return 0; +} +size_t Dispatcher::Write(Handle *h, const void *b, size_t size) +{ + if (DispatcherHandle *dh = (DispatcherHandle *)h) + return dh->handle->GetIOSystem()->Write(dh->handle, b, size); + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Dispatcher::MkDir(const char *path) +{ + String _path(path); + if (Base *base = Dispatch(_path, ModeWrite)) + return base->MkDir(_path); + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String Dispatcher::Hash(const char *uri) +{ + String _uri(uri); + if (Base *base = Dispatch(_uri, ModeRead)) + return base->Hash(_uri); + return String(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +DispatcherHandle::DispatcherHandle(Base *io, Handle *h) : Handle(io), handle(h) +{} +DispatcherHandle::~DispatcherHandle() +{ GetIOSystem()->Close(this); } +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/io_handle.cpp b/include/platform/filesystem/io_handle.cpp new file mode 100644 index 0000000..043168a --- /dev/null +++ b/include/platform/filesystem/io_handle.cpp @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "filesystem/io_handle.h" + #include "filesystem/io_base.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +size_t Handle::GetSize() +{ + size_t p = Tell(); + Seek(0, Base::SeekEnd); + size_t s = Tell(); + Seek(p, Base::SeekStart); + return s; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Handle::IsEOF() +{ return Tell() >= GetSize(); } +size_t Handle::Rewind() +{ return Seek(0, Base::SeekStart); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t Handle::Tell() +{ return io_sys.IsValid() ? io_sys->Tell(this) : 0; } +size_t Handle::Seek(ptrdiff_t offset, Base::SeekRef seek_ref) +{ return io_sys.IsValid() ? io_sys->Seek(this, offset, seek_ref) : 0; } + +size_t Handle::Read(void *p, size_t size) +{ return io_sys.IsValid() ? io_sys->Read(this, p, size) : 0; } +size_t Handle::Write(const void *p, size_t size) +{ return io_sys.IsValid() ? io_sys->Write(this, p, size) : 0; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle &Handle::operator << (const char *s) +{ + if (s) + Write(s, strlen(s)); + return *this; +} +Handle &Handle::operator << (char *s) +{ return *this << ((const char *)s); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle::Handle(Base *io) : io_sys(io) {} +Handle::~Handle() {} +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/io_handle_segment.cpp b/include/platform/filesystem/io_handle_segment.cpp new file mode 100644 index 0000000..05bcbb9 --- /dev/null +++ b/include/platform/filesystem/io_handle_segment.cpp @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/io_handle_segment.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +size_t HandleSegment::GetSize() +{ return size; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t HandleSegment::Tell() +{ return cursor; } +size_t HandleSegment::Seek(ptrdiff_t offset, Base::SeekRef ref) +{ + switch (ref) + { + case Base::SeekStart: + cursor = offset; + break; + case Base::SeekCurrent: + cursor += offset; + break; + case Base::SeekEnd: + cursor = size - offset; + break; + } + + if (cursor > size) + { + cursor = 0; + return (size_t)-1; + } + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/* + IO segment must always restore the original handle position and act as + transparently as possible. +*/ +size_t HandleSegment::Read(void *b, size_t s) +{ + size_t o = 0; + + size_t t = handle->Tell(); + + if (!handle->Seek(offset + cursor, Base::SeekStart)) + { + if (s > (size - cursor)) + s = size - cursor; + o = handle->Read(b, s); + cursor += o; + } + handle->Seek(t, Base::SeekStart); + + return o; +} +size_t HandleSegment::Write(const void *b, size_t s) +{ + size_t o = 0; + + size_t t = handle->Tell(); + if (!handle->Seek(offset + cursor, Base::SeekStart)) + { + o = handle->Write(b, s); + cursor += o; + } + handle->Seek(t, Base::SeekStart); + + return o; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/filesystem/io_memory.cpp b/include/platform/filesystem/io_memory.cpp new file mode 100644 index 0000000..4ccc665 --- /dev/null +++ b/include/platform/filesystem/io_memory.cpp @@ -0,0 +1,132 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "filesystem/io_memory.h" + + using namespace GS::IO; + + +//------------------------------------------------------------------------------ +uint Memory::GetCaps() const +{ return CanRead | CanWrite | CanSeek| IsCaseSensitive; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Handle *Memory::Open(const char *uri, Mode mode) +{ + switch (mode) + { + case ModeRead: + ListForeachPtr(MemoryFile *, f, fat) + if (f->uri == uri) + return new MemoryHandle(this, f, mode); + break; + + case ModeWrite: + { + MemoryFile *f_entry = NULL; + ListForeachPtr(MemoryFile *, f, fat) + if (f->uri == uri) + { + f_entry = f; + break; + } + + if (!f_entry) + fat.Add(f_entry = new MemoryFile(uri)); + + return f_entry ? new MemoryHandle(this, f_entry, mode) : NULL; + } + break; + + default: break; + } + return NULL; +} +void Memory::Close(Handle *h) +{ /* Nothing to be done. */ } + +bool Memory::Delete(const char *uri) +{ + ListForeachPtr(MemoryFile *, f, fat) + if (f->uri == uri) + return fat.Remove(f); + return false; +} + +size_t Memory::Tell(Handle *h) +{ + if (MemoryHandle *_h = (MemoryHandle *)h) + if (_h->file) + return _h->cursor; + return (size_t)-1; +} +size_t Memory::Seek(Handle *h, ptrdiff_t offset, SeekRef seek_ref) +{ + if (MemoryHandle *_h = (MemoryHandle *)h) + if (_h->file) + { + switch (seek_ref) + { + case SeekStart: + _h->cursor = Types::Clamp (offset, 0, _h->file->size); + break; + case SeekCurrent: + _h->cursor = Types::Clamp (_h->cursor + offset, 0, _h->file->size); + break; + case SeekEnd: + _h->cursor = Types::Clamp (_h->file->size - offset, 0, _h->file->size); + break; + } + return 0; + } + + return (size_t)-1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t Memory::Read(Handle *h, void *ptr, size_t size) +{ + size_t read_size = 0; + if (MemoryHandle *_h = (MemoryHandle *)h) + if (_h->file && (_h->mode == ModeRead)) + { + read_size = Types::Min (size, _h->file->size - _h->cursor); + GS::Memory::Copy(ptr, &_h->file->data[(int)_h->cursor], read_size); + _h->cursor += read_size; + } + + return read_size; +} +size_t Memory::Write(Handle *h, const void *ptr, size_t size) +{ + size_t write_size = 0; + if (MemoryHandle *_h = (MemoryHandle *)h) + if (_h->file && (_h->mode == ModeWrite)) + { + size_t req_size = _h->cursor + size; + if (req_size > _h->file->data.GetSize()) + if (!_h->file->data.Reallocate(req_size + 16384)) // required size + 16 kilobytes + return 0; + + GS::Memory::Copy(&_h->file->data[(int)_h->cursor], ptr, size); + write_size = size; + + _h->cursor += size; + _h->file->size = Types::Max(_h->file->size, req_size); + } + + return write_size; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +MemoryHandle::MemoryHandle(Base *io, MemoryFile *_file, Mode _mode) : Handle(io), file(_file), cursor(0), mode(_mode) +{} +MemoryHandle::~MemoryHandle() +{ GetIOSystem()->Close(this); } +//------------------------------------------------------------------------------ diff --git a/include/platform/hash/md5.cpp b/include/platform/hash/md5.cpp new file mode 100644 index 0000000..1106278 --- /dev/null +++ b/include/platform/hash/md5.cpp @@ -0,0 +1,374 @@ +/* + + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + +*/ + +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ + +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. +*/ + +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "hash/md5.h" + #include "memory/endian.h" + + using namespace GS::MD5; + + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +//------------------------------------------------------------------------------ +void Digest::Process(const md5_byte_t *data /*[64]*/) +{ + md5_word_t a = abcd[0], b = abcd[1], + c = abcd[2], d = abcd[3], + t; + + md5_word_t xbuf[16]; + const md5_word_t *X; + + if (GS::Endian::GetHostConfiguration() == GS::Endian::Little) + { + /* + On little-endian machines, we can process properly aligned + data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) + // Data are properly aligned. + X = (const md5_word_t *)data; + else + { + // Not aligned. + memcpy(xbuf, data, 64); + X = xbuf; + } + } + else // Dynamic big-endian. + { + /* + On big-endian machines, we must arrange the bytes in the + right order. + */ + const md5_byte_t *xp = data; + X = xbuf; + for (int i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define _G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + _G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* + Then perform the following additions. (That is increment each of the + four registers by the value it had before this block was started.) + */ + abcd[0] += a; + abcd[1] += b; + abcd[2] += c; + abcd[3] += d; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Digest::Reset() +{ + count[0] = count[1] = 0; + abcd[0] = 0x67452301; + abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + abcd[3] = 0x10325476; +} +void Digest::Append(const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes, + offset = (count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + // Update the message length. + count[1] += nbytes >> 29; + count[0] += nbits; + if (count[0] < nbits) + count[1]++; + + // Process an initial partial block. + if (offset) + { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(buf + offset, p, copy); + if (offset + copy < 64) + return; + + p += copy; + left -= copy; + Process(buf); + } + + // Process full blocks. + for (; left >= 64; p += 64, left -= 64) + Process(p); + + // Process a final partial block. + if (left) + memcpy(buf, p, left); +} +void Digest::Finish(md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + md5_byte_t data[8]; + int i; + + // Save the length before padding. + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(count[i >> 2] >> ((i & 3) << 3)); + // Pad to 56 bytes mod 64. + Append(pad, ((55 - (count[0] >> 3)) & 63) + 1); + // Append the length. + Append(data, 8); + + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(abcd[i >> 2] >> ((i & 3) << 3)); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void GS::MD5::DigestToString(const md5_byte_t digest[16], char *s) +{ + const char hex_table[17] = "0123456789abcdef"; + + for (int n = 0; n < 16; ++n) + { + *s++ = hex_table[(digest[n] >> 4) & 15]; + *s++ = hex_table[digest[n] & 15]; + } +} +//------------------------------------------------------------------------------ diff --git a/include/platform/hash/nsha1.cpp b/include/platform/hash/nsha1.cpp new file mode 100644 index 0000000..01876fb --- /dev/null +++ b/include/platform/hash/nsha1.cpp @@ -0,0 +1,47 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "hash/nsha1.h" + #include "hash/sha1.h" + #include "container/narray.h" + #include "nstring/nstring.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void SHA1::ComputeHash(const String &source, Array &hash) +{ + if (hash.Allocate(20)) + sha1::calc(source.c_str(), source.Len(), hash.c_ptr()); +} +String SHA1::ComputeHexa(const String &source) +{ + Array hash; + ComputeHash(source, hash); + + char hex[41]; + sha1::toHexString(hash.c_ptr(), hex); + return String(hex); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void SHA1::ComputeHash(const Array &data, Array &hash) +{ + if (hash.Allocate(20)) + sha1::calc(data.c_ptr(), data.GetSize(), hash.c_ptr()); +} +String SHA1::ComputeHexa(const Array &data) +{ + Array hash; + ComputeHash(data, hash); + + char hex[41]; + sha1::toHexString(hash.c_ptr(), hex); + return String(hex); +} +//------------------------------------------------------------------------------ diff --git a/include/platform/hash/sha1.cpp b/include/platform/hash/sha1.cpp new file mode 100644 index 0000000..bc0fa1c --- /dev/null +++ b/include/platform/hash/sha1.cpp @@ -0,0 +1,185 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + Contributors: + Gustav + Several members in the gamedev.se forum. + Gregory Petrosyan + */ + +#include "hash/sha1.h" + +namespace sha1 +{ + namespace // local + { + // Rotate an integer value to left. + inline const unsigned int rol(const unsigned int value, + const unsigned int steps) + { + return ((value << steps) | (value >> (32 - steps))); + } + + // Sets the first 16 integers in the buffert to zero. + // Used for clearing the W buffert. + inline void clearWBuffert(unsigned int* buffert) + { + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } + } + + void innerHash(unsigned int* result, unsigned int* w) + { + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; + } + } // namespace + + void calc(const void* src, const int bytelength, unsigned char* hash) + { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + const unsigned char* sarray = (const unsigned char*) src; + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + const int endOfFullBlocks = bytelength - 64; + int endCurrentBlock; + int currentBlock = 0; + + while (currentBlock <= endOfFullBlocks) + { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on little endian. + w[roundPos++] = (unsigned int) sarray[currentBlock + 3] + | (((unsigned int) sarray[currentBlock + 2]) << 8) + | (((unsigned int) sarray[currentBlock + 1]) << 16) + | (((unsigned int) sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + int lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) + { + w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); + } + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) + { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) + { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } + } + + void toHexString(const unsigned char* hash, char* hexstring) + { + const char hexDigits[] = { "0123456789abcdef" }; + + for (int hashByte = 20; --hashByte >= 0;) + { + hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf]; + hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf]; + } + hexstring[40] = 0; + } +} // namespace sha1 diff --git a/include/platform/input/input_keyboard.cpp b/include/platform/input/input_keyboard.cpp new file mode 100644 index 0000000..b27bf9b --- /dev/null +++ b/include/platform/input/input_keyboard.cpp @@ -0,0 +1,19 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "input/input_keyboard.h" + #include "memory/memory.h" + + using namespace GS::Input; + + +//------------------------------------------------------------------------------ +Keyboard::Keyboard() +{ + GS::Memory::Set(is_down, 0, sizeof(bool) * (uint)Key_Last); + GS::Memory::Set(was_down, 0, sizeof(bool) * (uint)Key_Last); +} +//------------------------------------------------------------------------------ diff --git a/include/platform/input/input_mouse.cpp b/include/platform/input/input_mouse.cpp new file mode 100644 index 0000000..7aa052d --- /dev/null +++ b/include/platform/input/input_mouse.cpp @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "input/input_mouse.h" + + using namespace GS::Input; + + +//------------------------------------------------------------------------------ +bool Mouse::IsDown(KeyCode key) const +{ + switch (key) + { + case Key_Button0: return state.left_button; + case Key_Button1: return state.right_button; + case Key_Button2: return state.middle_button; + + default: break; + } + return false; +} +bool Mouse::WasDown(KeyCode key) const +{ + switch (key) + { + case Key_Button0: return last_state.left_button; + case Key_Button1: return last_state.right_button; + case Key_Button2: return last_state.middle_button; + + default: break; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Mouse::GetInputRange(InputCode i, float &mn, float &mx) const +{ + switch (i) + { + case Input_AxisX: + case Input_AxisY: + mn = 0; mx = 1; + return true; + + case Input_RotX: // Horizontal wheel. + case Input_RotY: // Vertical wheel. + mn = 0; mx = 1024; + return true; + + default: break; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Mouse::GetValue(InputCode i) const +{ + switch (i) + { + case Input_AxisX: return state.x; + case Input_AxisY: return state.y; + case Input_RotX: return state.hwheel; + case Input_RotY: return state.wheel; + + default: break; + } + return 0; +} +float Mouse::GetLastValue(InputCode i) const +{ + switch (i) + { + case Input_AxisX: return last_state.x; + case Input_AxisY: return last_state.y; + case Input_RotX: return last_state.hwheel; + case Input_RotY: return last_state.wheel; + + default: break; + } + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Mouse::Mouse() +{ + state.x = 0; state.y = 0; + + state.left_button = false; + state.right_button = false; + state.middle_button = false; + state.wheel = 0; + state.hwheel = 0; + + last_state = state; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/input/input_touch.cpp b/include/platform/input/input_touch.cpp new file mode 100644 index 0000000..f5849f9 --- /dev/null +++ b/include/platform/input/input_touch.cpp @@ -0,0 +1,96 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "input/input_touch.h" + #include "nstring/nstring.h" + + using namespace GS::Input; + + +//------------------------------------------------------------------------------ +void TouchDevice::RegisterTouchEvent(float x, float y, float weight) +{ + pending_state.button = asbool(weight > 0); + pending_state.x = x; + pending_state.y = y; +} +void TouchDevice::Update() +{ + last_state = state; + state = pending_state; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool TouchDevice::IsDown(KeyCode key) const +{ return key == Key_Button0 ? state.button : false; } +bool TouchDevice::WasDown(KeyCode key) const +{ return key == Key_Button0 ? last_state.button : false; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool TouchDevice::GetInputRange(InputCode i, float &mn, float &mx) const +{ + switch (i) + { + case Input_AxisX: + case Input_AxisY: + mn = 0; mx = 1; + return true; + + case Input_RotX: // Horizontal wheel. + case Input_RotY: // Vertical wheel. + mn = 0; mx = 1024; + return true; + + default: break; + } + return false; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float TouchDevice::GetValue(InputCode i) const +{ + switch (i) + { + case Input_AxisX: return state.x; + case Input_AxisY: return state.y; + + default: break; + } + return 0; +} +float TouchDevice::GetLastValue(InputCode i) const +{ + switch (i) + { + case Input_AxisX: return last_state.x; + case Input_AxisY: return last_state.y; + + default: break; + } + return 0; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void TouchDevice::SetIndex(int _index) +{ index = _index; } +Device::Type TouchDevice::GetType() const +{ return index == -1 ? Type_Mouse : Type_Touch; } +const char *TouchDevice::GetName() const +{ return index == -1 ? "mouse" : GS::String::Format("touch%d", index).c_str(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +TouchDevice::TouchDevice(int i) : index(i) +{ + state.x = 0; state.y = 0; + state.button = false; + pending_state = last_state = state; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/locale/country.cpp b/include/platform/locale/country.cpp new file mode 100644 index 0000000..2e0910f --- /dev/null +++ b/include/platform/locale/country.cpp @@ -0,0 +1,285 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "locale/country.h" + + +namespace GS { + namespace Locale { + +//------------------------------------------------------------------------------ +static Info countries[] = +{ + { "Asia", "South Asia", "Afghanistan", "AF", "AF", "AFG", 4, "AF" }, + { "Europe", "South East Europe", "Albania", "AL", "AL", "ALB", 8, "AL" }, + { "Africa", "Northern Africa", "Algeria", "AG", "DZ", "DZA", 12, "DZ" }, + { "Oceania", "Pacific", "American Samoa", "AQ", "AS", "ASM", 16, "AS" }, + { "Europe", "South West Europe", "Andorra", "AN", "AD", "AND", 20, "AD" }, + { "Africa", "Southern Africa", "Angola", "AO", "AO", "AGO", 24, "AO" }, + { "Americas", "West Indies", "Anguilla", "AV", "AI", "AIA", 660, "AI" }, + { "Americas", "West Indies", "Antigua and Barbuda", "AC", "AG", "ATG", 28, "AG" }, + { "Americas", "South America", "Argentina", "AR", "AR", "ARG", 32, "AR" }, + { "Asia", "South West Asia", "Armenia", "AM", "AM", "ARM", 51, "AM" }, + { "Americas", "West Indies", "Aruba", "AA", "AW", "ABW", 533, "AW" }, + { "Oceania", "Pacific", "Australia", "AS", "AU", "AUS", 36, "AU" }, + { "Europe", "Central Europe", "Austria", "AU", "AT", "AUT", 40, "AT" }, + { "Asia", "South West Asia", "Azerbaijan", "AJ", "AZ", "AZE", 31, "AZ" }, + { "Americas", "West Indies", "Bahamas, The", "BF", "BS", "BHS", 44, "BS" }, + { "Asia", "South West Asia", "Bahrain", "BA", "BH", "BHR", 48, "BH" }, + { "Asia", "South Asia", "Bangladesh", "BG", "BD", "BGD", 50, "BD" }, + { "Americas", "West Indies", "Barbados", "BB", "BB", "BRB", 52, "BB" }, + { "Europe", "Eastern Europe", "Belarus", "BO", "BY", "BLR", 112, "BY" }, + { "Europe", "Western Europe", "Belgium", "BE", "BE", "BEL", 56, "BE" }, + { "Americas", "Central America", "Belize", "BH", "BZ", "BLZ", 84, "BZ" }, + { "Africa", "Western Africa", "Benin", "BN", "BJ", "BEN", 204, "BJ" }, + { "Americas", "West Indies", "Bermuda", "BD", "BM", "BMU", 60, "BM" }, + { "Asia", "South Asia", "Bhutan", "BT", "BT", "BTN", 64, "BT" }, + { "Americas", "South America", "Bolivia", "BL", "BO", "BOL", 68, "BO" }, + { "Europe", "South East Europe", "Bosnia and Herzegovina", "BK", "BA", "BIH", 70, "BA" }, + { "Africa", "Southern Africa", "Botswana", "BC", "BW", "BWA", 72, "BW" }, + { "Americas", "South America", "Brazil", "BR", "BR", "BRA", 76, "BR" }, + { "Americas", "West Indies", "British Virgin Islands", "VI", "VG", "VGB", 92, "VG" }, + { "Asia", "South East Asia", "Brunei", "BX", "BN", "BRN", 96, "BN" }, + { "Europe", "South East Europe", "Bulgaria", "BU", "BG", "BGR", 100, "BG" }, + { "Africa", "Western Africa", "Burkina Faso", "UV", "BF", "BFA", 854, "BF" }, + { "Africa", "Central Africa", "Burundi", "BY", "BI", "BDI", 108, "BI" }, + { "Asia", "South East Asia", "Cambodia", "CB", "KH", "KHM", 116, "KH" }, + { "Africa", "Western Africa", "Cameroon", "CM", "CM", "CMR", 120, "CM" }, + { "Americas", "North America", "Canada", "CA", "CA", "CAN", 124, "CA" }, + { "Africa", "Western Africa", "Cape Verde", "CV", "CV", "CPV", 132, "CV" }, + { "Americas", "West Indies", "Cayman Islands", "CJ", "KY", "CYM", 136, "KY" }, + { "Africa", "Central Africa", "Central African Republic", "CT", "CF", "CAF", 140, "CF" }, + { "Africa", "Central Africa", "Chad", "CD", "TD", "TCD", 148, "TD" }, + { "Americas", "South America", "Chile", "CI", "CL", "CHL", 152, "CL" }, + { "Asia", "East Asia", "China", "CH", "CN", "CHN", 156, "CN" }, + { "Asia", "South East Asia", "Christmas Island", "KT", "CX", "CXR", 162, "CX" }, + { "Asia", "South East Asia", "Cocos (Keeling) Islands", "CK", "CC", "CCK", 166, "CC" }, + { "Americas", "South America", "Colombia", "CO", "CO", "COL", 170, "CO" }, + { "Africa", "Indian Ocean", "Comoros", "CN", "KM", "COM", 174, "KM" }, + { "Africa", "Central Africa", "Congo, Republic of the", "CF", "CG", "COG", 178, "CG" }, + { "Oceania", "Pacific", "Cook Islands", "CW", "CK", "COK", 184, "CK" }, + { "Americas", "Central America", "Costa Rica", "CS", "CR", "CRI", 188, "CR" }, + { "Africa", "Western Africa", "Cote d'Ivoire", "IV", "CI", "CIV", 384, "CI" }, + { "Europe", "South East Europe", "Croatia", "HR", "HR", "HRV", 191, "HR" }, + { "Americas", "West Indies", "Cuba", "CU", "CU", "CUB", 192, "CU" }, + { "Asia", "South West Asia", "Cyprus", "CY", "CY", "CYP", 196, "CY" }, + { "Europe", "Central Europe", "Czech Republic", "EZ", "CZ", "CZE", 203, "CZ" }, + { "Europe", "Northern Europe", "Denmark", "DA", "DK", "DNK", 208, "DK" }, + { "Africa", "Eastern Africa", "Djibouti", "DJ", "DJ", "DJI", 262, "DJ" }, + { "Americas", "West Indies", "Dominica", "DO", "DM", "DMA", 212, "DM" }, + { "Americas", "West Indies", "Dominican Republic", "DR", "DO", "DOM", 214, "DO" }, + { "Americas", "South America", "Ecuador", "EC", "EC", "ECU", 218, "EC" }, + { "Africa", "Northern Africa", "Egypt", "EG", "EG", "EGY", 818, "EG" }, + { "Americas", "Central America", "El Salvador", "ES", "SV", "SLV", 222, "SV" }, + { "Africa", "Western Africa", "Equatorial Guinea", "EK", "GQ", "GNQ", 226, "GQ" }, + { "Africa", "Eastern Africa", "Eritrea", "ER", "ER", "ERI", 232, "ER" }, + { "Europe", "Eastern Europe", "Estonia", "EN", "EE", "EST", 233, "EE" }, + { "Africa", "Eastern Africa", "Ethiopia", "ET", "ET", "ETH", 231, "ET" }, + { "Americas", "South America", "Falkland Islands (Islas Malvinas)", "FA", "FK", "FLK", 238, "FK" }, + { "Europe", "Northern Europe", "Faroe Islands", "FO", "FO", "FRO", 234, "FO" }, + { "Oceania", "Pacific", "Fiji", "FJ", "FJ", "FJI", 242, "FJ" }, + { "Europe", "Northern Europe", "Finland", "FI", "FI", "FIN", 246, "FI" }, + { "Europe", "Western Europe", "France", "FR", "FR", "FRA", 250, "FR" }, + { "Americas", "South America", "French Guiana", "FG", "GF", "GUF", 254, "GF" }, + { "Oceania", "Pacific", "French Polynesia", "FP", "PF", "PYF", 258, "PF" }, + { "Africa", "Western Africa", "Gabon", "GB", "GA", "GAB", 266, "GA" }, + { "Africa", "Western Africa", "Gambia, The", "GA", "GM", "GMB", 270, "GM" }, + { "Asia", "South West Asia", "Georgia", "GG", "GE", "GEO", 268, "GE" }, + { "Europe", "Western Europe", "Germany", "GM", "DE", "DEU", 276, "DE" }, + { "Africa", "Western Africa", "Ghana", "GH", "GH", "GHA", 288, "GH" }, + { "Europe", "South West Europe", "Gibraltar", "GI", "GI", "GIB", 292, "GI" }, + { "Europe", "South East Europe", "Greece", "GR", "GR", "GRC", 300, "GR" }, + { "Americas", "North America", "Greenland", "GL", "GL", "GRL", 304, "GL" }, + { "Americas", "West Indies", "Grenada", "GJ", "GD", "GRD", 308, "GD" }, + { "Americas", "West Indies", "Guadeloupe", "GP", "GP", "GLP", 312, "GP" }, + { "Oceania", "Pacific", "Guam", "GQ", "GU", "GUM", 316, "GU" }, + { "Americas", "Central America", "Guatemala", "GT", "GT", "GTM", 320, "GT" }, + { "Europe", "Western Europe", "Guernsey", "--", "--", "--", 0, "--" }, + { "Africa", "Western Africa", "Guinea", "GV", "GN", "GIN", 324, "GN" }, + { "Africa", "Western Africa", "Guinea-Bissau", "PU", "GW", "GNB", 624, "GW" }, + { "Americas", "South America", "Guyana", "GY", "GY", "GUY", 328, "GY" }, + { "Americas", "West Indies", "Haiti", "HA", "HT", "HTI", 332, "HT" }, + { "Europe", "Southern Europe", "Holy See (Vatican City)", "VT", "VA", "VAT", 336, "VA" }, + { "Americas", "Central America", "Honduras", "HO", "HN", "HND", 340, "HN" }, + { "Europe", "Central Europe", "Hungary", "HU", "HU", "HUN", 348, "HU" }, + { "Europe", "Northern Europe", "Iceland", "IC", "IS", "ISL", 352, "IS" }, + { "Asia", "South Asia", "India", "IN", "IN", "IND", 356, "IN" }, + { "Asia", "South East Asia", "Indonesia", "ID", "ID", "IDN", 360, "ID" }, + { "Asia", "South West Asia", "Iran", "IR", "IR", "IRN", 364, "IR" }, + { "Asia", "South West Asia", "Iraq", "IZ", "IQ", "IRQ", 368, "IQ" }, + { "Europe", "Western Europe", "Ireland", "EI", "IE", "IRL", 372, "IE" }, + { "Asia", "South West Asia", "Israel", "IS", "IL", "ISR", 376, "IL" }, + { "Europe", "Southern Europe", "Italy", "IT", "IT", "ITA", 380, "IT" }, + { "Americas", "West Indies", "Jamaica", "JM", "JM", "JAM", 388, "JM" }, + { "Europe", "Northern Europe", "Jan Mayen", "--", "--", "--", 0, "--" }, + { "Asia", "East Asia", "Japan", "JA", "JP", "JPN", 392, "JP" }, + { "Europe", "Western Europe", "Jersey", "--", "--", "--", 0, "--" }, + { "Asia", "South West Asia", "Jordan", "JO", "JO", "JOR", 400, "JO" }, + { "Asia", "Central Asia", "Kazakhstan", "KZ", "KZ", "KAZ", 398, "KZ" }, + { "Africa", "Eastern Africa", "Kenya", "KE", "KE", "KEN", 404, "KE" }, + { "Oceania", "Pacific", "Kiribati", "KR", "KI", "KIR", 296, "KI" }, + { "Asia", "East Asia", "Korea, North", "KN", "KP", "PRK", 408, "KP" }, + { "Asia", "East Asia", "Korea, South", "KS", "KR", "KOR", 410, "KR" }, + { "Asia", "South West Asia", "Kuwait", "KU", "KW", "KWT", 414, "KW" }, + { "Asia", "Central Asia", "Kyrgyzstan", "KG", "KG", "KGZ", 417, "KG" }, + { "Asia", "South East Asia", "Laos", "LA", "LA", "LAO", 418, "LA" }, + { "Europe", "Eastern Europe", "Latvia", "LG", "LV", "LVA", 428, "LV" }, + { "Asia", "South West Asia", "Lebanon", "LE", "LB", "LBN", 422, "LB" }, + { "Africa", "Southern Africa", "Lesotho", "LT", "LS", "LSO", 426, "LS" }, + { "Africa", "Western Africa", "Liberia", "LI", "LR", "LBR", 430, "LR" }, + { "Africa", "Northern Africa", "Libya", "LY", "LY", "LBY", 434, "LY" }, + { "Europe", "Central Europe", "Liechtenstein", "LS", "LI", "LIE", 438, "LI" }, + { "Europe", "Eastern Europe", "Lithuania", "LH", "LT", "LTU", 440, "LT" }, + { "Europe", "Western Europe", "Luxembourg", "LU", "LU", "LUX", 442, "LU" }, + { "Europe", "South East Europe", "Macedonia", "MK", "MK", "MKD", 807, "MK" }, + { "Africa", "Indian Ocean", "Madagascar", "MA", "MG", "MDG", 450, "MG" }, + { "Africa", "Southern Africa", "Malawi", "MI", "MW", "MWI", 454, "MW" }, + { "Asia", "South East Asia", "Malaysia", "MY", "MY", "MYS", 458, "MY" }, + { "Asia", "South Asia", "Maldives", "MV", "MV", "MDV", 462, "MV" }, + { "Africa", "Western Africa", "Mali", "ML", "ML", "MLI", 466, "ML" }, + { "Europe", "Southern Europe", "Malta", "MT", "MT", "MLT", 470, "MT" }, + { "Europe", "Western Europe", "Man, Isle of", "--", "--", "--", 0, "--" }, + { "Oceania", "Pacific", "Marshall Islands", "RM", "MH", "MHL", 584, "MH" }, + { "Americas", "West Indies", "Martinique", "MB", "MQ", "MTQ", 474, "MQ" }, + { "Africa", "Western Africa", "Mauritania", "MR", "MR", "MRT", 478, "MR" }, + { "Africa", "Indian Ocean", "Mauritius", "MP", "MU", "MUS", 480, "MU" }, + { "Africa", "Indian Ocean", "Mayotte", "MF", "YT", "MYT", 175, "YT" }, + { "Americas", "Central America", "Mexico", "MX", "MX", "MEX", 484, "MX" }, + { "Oceania", "Pacific", "Micronesia, Federated States of", "FM", "FSM", "583", 0, "--" }, + { "Europe", "Eastern Europe", "Moldova", "MD", "MD", "MDA", 498, "MD" }, + { "Europe", "Western Europe", "Monaco", "MN", "MC", "MCO", 492, "MC" }, + { "Asia", "Northern Asia", "Mongolia", "MG", "MN", "MNG", 496, "MN" }, + { "Americas", "West Indies", "Montserrat", "MH", "MS", "MSR", 500, "MS" }, + { "Africa", "Northern Africa", "Morocco", "MO", "MA", "MAR", 504, "MA" }, + { "Africa", "Southern Africa", "Mozambique", "MZ", "MZ", "MOZ", 508, "MZ" }, + { "Asia", "South East Asia", "Myanmar (Burma)", "BM", "MM", "MMR", 104, "MM" }, + { "Africa", "Southern Africa", "Namibia", "WA", "NA", "NAM", 516, "NA" }, + { "Oceania", "Pacific", "Nauru", "NR", "NR", "NRU", 520, "NR" }, + { "Asia", "South Asia", "Nepal", "NP", "NP", "NPL", 524, "NP" }, + { "Europe", "Western Europe", "Netherlands", "NL", "NL", "NLD", 528, "NL" }, + { "Americas", "West Indies", "Netherlands Antilles", "NT", "AN", "ANT", 530, "AN" }, + { "Oceania", "Pacific", "New Caledonia", "NC", "NC", "NCL", 540, "NC" }, + { "Oceania", "Pacific", "New Zealand", "NZ", "NZ", "NZL", 554, "NZ" }, + { "Americas", "Central America", "Nicaragua", "NU", "NI", "NIC", 558, "NI" }, + { "Africa", "Western Africa", "Niger", "NG", "NE", "NER", 562, "NE" }, + { "Africa", "Western Africa", "Nigeria", "NI", "NG", "NGA", 566, "NG" }, + { "Oceania", "Pacific", "Niue", "NE", "NU", "NIU", 570, "NU" }, + { "Oceania", "Pacific", "Norfolk Island", "NF", "NF", "NFK", 574, "NF" }, + { "Oceania", "Pacific", "Northern Mariana Islands", "CQ", "MP", "MNP", 580, "MP" }, + { "Europe", "Northern Europe", "Norway", "NO", "NO", "NOR", 578, "NO" }, + { "Asia", "South West Asia", "Oman", "MU", "OM", "OMN", 512, "OM" }, + { "Asia", "South Asia", "Pakistan", "PK", "PK", "PAK", 586, "PK" }, + { "Oceania", "Pacific", "Palau", "PS", "PW", "PLW", 585, "PW" }, + { "Asia", "South West Asia", "Palestine", "--", "--", "--", 0, "--" }, + { "Americas", "Central America", "Panama", "PM", "PA", "PAN", 591, "PA" }, + { "Oceania", "Pacific", "Papua New Guinea", "PP", "PG", "PNG", 598, "PG" }, + { "Americas", "South America", "Paraguay", "PA", "PY", "PRY", 600, "PY" }, + { "Americas", "South America", "Peru", "PE", "PE", "PER", 604, "PE" }, + { "Asia", "South East Asia", "Philippines", "RP", "PH", "PHL", 608, "PH" }, + { "Oceania", "Pacific", "Pitcairn Islands", "PC", "PN", "PCN", 612, "PN" }, + { "Europe", "Eastern Europe", "Poland", "PL", "PL", "POL", 616, "PL" }, + { "Europe", "South West Europe", "Portugal", "PO", "PT", "PRT", 620, "PT" }, + { "Americas", "West Indies", "Puerto Rico", "RQ", "PR", "PRI", 630, "PR" }, + { "Asia", "South West Asia", "Qatar", "QA", "QA", "QAT", 634, "QA" }, + { "Africa", "Indian Ocean", "Reunion", "RE", "RE", "REU", 638, "RE" }, + { "Europe", "South East Europe", "Romania", "RO", "RO", "ROM", 642, "RO" }, + { "Asia", "Northern Asia", "Russia", "RS", "RU", "RUS", 643, "RU" }, + { "Africa", "Central Africa", "Rwanda", "RW", "RW", "RWA", 646, "RW" }, + { "Americas", "West Indies", "Saint Kitts and Nevis", "SC", "KN", "KNA", 659, "KN" }, + { "Americas", "West Indies", "Saint Lucia", "ST", "LC", "LCA", 662, "LC" }, + { "Americas", "North America", "Saint Pierre and Miquelon", "SB", "PM", "SPM", 666, "PM" }, + { "Americas", "West Indies", "Saint Vincent and the Grenadines", "VC", "VC", "VCT", 670, "VC" }, + { "Europe", "Southern Europe", "San Marino", "SM", "SM", "SMR", 674, "SM" }, + { "Africa", "Western Africa", "Sao Tome and Principe", "TP", "ST", "STP", 678, "ST" }, + { "Asia", "South West Asia", "Saudi Arabia", "SA", "SA", "SAU", 682, "SA" }, + { "Africa", "Western Africa", "Senegal", "SG", "SN", "SEN", 686, "SN" }, + { "Europe", "South East Europe", "Serbia and Montenegro", "SR", "--", "--", 0, "--" }, + { "Africa", "Indian Ocean", "Seychelles", "SE", "SC", "SYC", 690, "SC" }, + { "Africa", "Western Africa", "Sierra Leone", "SL", "SL", "SLE", 694, "SL" }, + { "Asia", "South East Asia", "Singapore", "SN", "SG", "SGP", 702, "SG" }, + { "Europe", "Central Europe", "Slovakia", "LO", "SK", "SVK", 703, "SK" }, + { "Europe", "South East Europe", "Slovenia", "SI", "SI", "SVN", 705, "SI" }, + { "Oceania", "Pacific", "Solomon Islands", "BP", "SB", "SLB", 90, "SB" }, + { "Africa", "Eastern Africa", "Somalia", "SO", "SO", "SOM", 706, "SO" }, + { "Africa", "Southern Africa", "South Africa", "SF", "ZA", "ZAF", 710, "ZA" }, + { "Europe", "South West Europe", "Spain", "SP", "ES", "ESP", 724, "ES" }, + { "Asia", "South Asia", "Sri Lanka", "CE", "LK", "LKA", 144, "LK" }, + { "Africa", "Northern Africa", "Sudan", "SU", "SD", "SDN", 736, "SD" }, + { "Americas", "South America", "Suriname", "NS", "SR", "SUR", 740, "SR" }, + { "Europe", "Northern Europe", "Svalbard", "SV", "SJ", "SJM", 744, "SJ" }, + { "Africa", "Southern Africa", "Swaziland", "WZ", "SZ", "SWZ", 748, "SZ" }, + { "Europe", "Northern Europe", "Sweden", "SW", "SE", "SWE", 752, "SE" }, + { "Europe", "Central Europe", "Switzerland", "SZ", "CH", "CHE", 756, "CH" }, + { "Asia", "South West Asia", "Syria", "SY", "SY", "SYR", 760, "SY" }, + { "Asia", "East Asia", "Taiwan", "TW", "TW", "TWN", 158, "TW" }, + { "Asia", "Central Asia", "Tajikistan", "TI", "TJ", "TJK", 762, "TJ" }, + { "Africa", "Eastern Africa", "Tanzania", "TZ", "TZ", "TZA", 834, "TZ" }, + { "Asia", "South East Asia", "Thailand", "TH", "TH", "THA", 764, "TH" }, + { "Africa", "Western Africa", "Togo", "TO", "TG", "TGO", 768, "TG" }, + { "Oceania", "Pacific", "Tokelau", "TL", "TK", "TKL", 772, "TK" }, + { "Oceania", "Pacific", "Tonga", "TN", "TO", "TON", 776, "TO" }, + { "Americas", "West Indies", "Trinidad and Tobago", "TD", "TT", "TTO", 780, "TT" }, + { "Africa", "Northern Africa", "Tunisia", "TS", "TN", "TUN", 788, "TN" }, + { "Asia", "South West Asia", "Turkey", "TU", "TR", "TUR", 792, "TR" }, + { "Asia", "Central Asia", "Turkmenistan", "TX", "TM", "TKM", 795, "TM" }, + { "Americas", "West Indies", "Turks and Caicos Islands", "TK", "TC", "TCA", 796, "TC" }, + { "Oceania", "Pacific", "Tuvalu", "TV", "TV", "TUV", 798, "TV" }, + { "Africa", "Eastern Africa", "Uganda", "UG", "UG", "UGA", 800, "UG" }, + { "Europe", "Eastern Europe", "Ukraine", "UP", "UA", "UKR", 804, "UA" }, + { "Asia", "South West Asia", "United Arab Emirates", "TC", "AE", "ARE", 784, "AE" }, + { "Europe", "Western Europe", "United Kingdom", "UK", "GB", "GBR", 826, "UK/GB" }, + { "Americas", "North America", "United States", "US", "US", "USA", 840, "US" }, + { "Americas", "South America", "Uruguay", "UY", "UY", "URY", 858, "UY" }, + { "Asia", "Central Asia", "Uzbekistan", "UZ", "UZ", "UZB", 860, "UZ" }, + { "Oceania", "Pacific", "Vanuatu", "NH", "VU", "VUT", 548, "VU" }, + { "Americas", "South America", "Venezuela", "VE", "VE", "VEN", 862, "UE" }, + { "Asia", "South East Asia", "Vietnam", "VM", "VN", "VNM", 704, "VN" }, + { "Americas", "West Indies", "Virgin Islands", "VQ", "VI", "VIR", 850, "VI" }, + { "Oceania", "Pacific", "Wallis and Futuna", "WF", "WF", "WLF", 876, "WF" }, + { "Africa", "Northern Africa", "Western Sahara", "WI", "EH", "ESH", 732, "EH" }, + { "Oceania", "Pacific", "Western Samoa", "WS", "WS", "WSM", 882, "WS" }, + { "Asia", "South West Asia", "Yemen", "YM", "YE", "YEM", 887, "YE" }, + { "Africa", "Central Africa", "Zaire (Dem Rep of Congo)", "CG", "ZR", "ZAR", 180, "ZR" }, + { "Africa", "Southern Africa", "Zambia", "ZA", "ZM", "ZWB", 894, "ZM" }, + { "Africa", "Southern Africa", "Zimbabwe", "ZI", "ZW", "ZWE", 716, "ZW" }, + + { 0, 0, 0, 0, 0, 0, -1, 0 } +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +const Info *GetFIPSCountry(const char *fips) +{ + for (int n = 0; countries[n].iso != -1; ++n) + if (countries[n].fips == fips) + return &countries[n]; + return NULL; +} +const Info *GetISO2Country(const char *iso) +{ + for (int n = 0; countries[n].iso != -1; ++n) + if (countries[n].iso2 == iso) + return &countries[n]; + return NULL; +} +const Info *GetISO3Country(const char *iso) +{ + for (int n = 0; countries[n].iso != -1; ++n) + if (countries[n].iso3 == iso) + return &countries[n]; + return NULL; +} +const Info *GetISOCountry(int iso) +{ + for (int n = 0; countries[n].iso != -1; ++n) + if (countries[n].iso == iso) + return &countries[n]; + return NULL; +} +//------------------------------------------------------------------------------ + + } // Locale +} // GS diff --git a/include/platform/log/file_log.cpp b/include/platform/log/file_log.cpp new file mode 100644 index 0000000..20d69e2 --- /dev/null +++ b/include/platform/log/file_log.cpp @@ -0,0 +1,39 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "log/file_log.h" + #include "filesystem/filesystem.h" + #include "platform.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +void FileLog::NewLog(const char *log, char entry_level) +{ + if (FILE *f = fopen(path, initial_write ? "w" : "a")) + { + initial_write = false; + + if (do_timestamp) + { + String timestamp = Platform::Get().GetTime().toString() + ": "; + fwrite(timestamp.c_str(), 1, timestamp.Len(), f); + } + + fwrite(log, 1, String::strlen(log), f); + fclose(f); + } +} +FileLog::FileLog(const char *_path, bool _do_timestamp) : path(_path), do_timestamp(_do_timestamp) +{ + initial_write = true; + FILE *f = fopen(path, "w"); + if(f) + fclose(f); +} +//------------------------------------------------------------------------------ diff --git a/include/platform/log/log.cpp b/include/platform/log/log.cpp new file mode 100644 index 0000000..cd7d35e --- /dev/null +++ b/include/platform/log/log.cpp @@ -0,0 +1,160 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include + #include "log/log.h" + #include "nstring/nstring.h" + #include "thread/mutex.h" + #include "platform_config.h" + #include "alloc/ialloc.h" + + using namespace GS; + + template<> LogSystem *Singleton ::i = NULL; + + +//------------------------------------------------------------------------------ +LogSystem::LogSystem() +{ SetLog(); } +void LogSystem::SetLog(Log *l) +{ + static Log s_log; + log = l ? l : &s_log; +} +Log &LogSystem::GetLog() +{ return *log; } +//------------------------------------------------------------------------------ + +#if __PLATFORM_LOG_SUPPORT__ + +//------------------------------------------------------------------------------ +void Log::NewLog(const char *log, char) +{ +// std::cout << log; +} +void Log::LogProcessed() +{ + full_a[0] = 0; + full_b[0] = 0; +} +//------------------------------------------------------------------------------ + +#define _FORMAT_LOG(__F__, __V__) \ +{\ + Threading::MutexLock lock(mutex);\ + if (a)\ + {\ + _snprintf(b, LOG_LINE_MAX_LEN - 1, __F__, a, __V__);\ + char *swp = a; a = b; b = swp;\ + }\ + return *this;\ +} + +//------------------------------------------------------------------------------ +Log &Log::operator << (const char v) +{ _FORMAT_LOG("%s%d", v) } +Log &Log::operator << (const short v) +{ _FORMAT_LOG("%s%d", v) } +Log &Log::operator << (const int v) +{ _FORMAT_LOG("%s%d", v) } +Log &Log::operator << (const uchar v) +{ _FORMAT_LOG("%s%d", v) } +Log &Log::operator << (const ushort v) +{ _FORMAT_LOG("%s%d", v) } +Log &Log::operator << (const uint v) +{ _FORMAT_LOG("%s%d", (int)v) } +Log &Log::operator << (const size_t v) +{ _FORMAT_LOG("%s%d", v) } +Log &Log::operator << (const float v) +{ _FORMAT_LOG("%s%.3f", v) } +Log &Log::operator << (const bool v) +{ _FORMAT_LOG("%s%s", v ? "True" : "False") } +Log &Log::operator << (const void *v) +{ _FORMAT_LOG("%s0x%p", v) } +Log &Log::operator << (const char *v) +{ + if (a && v) + { + Threading::MutexLock lock(mutex); + + _snprintf(b, LOG_LINE_MAX_LEN - 1, "%s%s", a, v); + char *swp = a; a = b; b = swp; + + // Look out for ENDL. + for (const char *p = v; p[0]; ++p) + if (p[0] == '\n') + { + // Compute entry level. + char entry_level = EngineLogStandard; + + if ((std::strlen(a) >= 3) && (a[0] == '[') && (a[2] == ']')) + switch (a[1]) + { + case '*': entry_level |= EngineLogWarning; break; + case '!': entry_level |= EngineLogError; break; + case 'H': entry_level |= EngineLogHeader; break; + case 'V': entry_level |= EngineLogVerbose; break; + case 'S': entry_level |= EngineLogScript; break; + } + + // Process output. + if (entry_level & log_level) + NewLog(a, entry_level); + + LogProcessed(); + } + } + return *this; +} +Log &Log::operator << (const String &v) +{ return *this << v.toUtf8(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Log::Log() +{ + LogProcessed(); + a = full_a; + b = full_b; + log_level = (uint)EngineLogAll; + + mutex = new Threading::Mutex; +} +Log::~Log() +{ + _safe_delete(mutex); +} +//------------------------------------------------------------------------------ + +#else + +//------------------------------------------------------------------------------ +void Log::NewLog(const char *, char) {} +void Log::LogProcessed() {} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Log &Log::operator << (const char) { return *this; } +Log &Log::operator << (const short) { return *this; } +Log &Log::operator << (const int) { return *this; } +Log &Log::operator << (const uchar) { return *this; } +Log &Log::operator << (const ushort) { return *this; } +Log &Log::operator << (const uint) { return *this; } +Log &Log::operator << (const size_t) { return *this; } +Log &Log::operator << (const float) { return *this; } +Log &Log::operator << (const bool) { return *this; } +Log &Log::operator << (const char *) { return *this; } +Log &Log::operator << (const String &) { return *this; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Log::Log() {} +Log::~Log() {} +//------------------------------------------------------------------------------ + +#endif diff --git a/include/platform/log/log.h b/include/platform/log/log.h index 82b44c3..e730e03 100644 --- a/include/platform/log/log.h +++ b/include/platform/log/log.h @@ -34,7 +34,7 @@ namespace GS { * __LOG_H__: Header (eg: __LOG_H__ << "Physics entry point.\n") * __LOG_W__: Warning * __LOG_E__: Error - * __LOG_E__: Non-maskable + * __LOG_N__: Non-maskable Standard logs may be output to the __LOG__ stream. @@ -81,9 +81,9 @@ public: Log &operator << (const uchar); Log &operator << (const ushort); Log &operator << (const uint); - #if __PLATFORM_IOS__ + Log &operator << (const size_t); - #endif + Log &operator << (const float); Log &operator << (const bool); Log &operator << (const void *); @@ -117,7 +117,6 @@ public: //------------------------------------------------------------------------------ #define __LOG__ GS::LogSystem::Get().GetLog() // Standard #define __LOG_H__ __LOG__ << "[H] " // Header -#define __LOG_CAM__ __LOG__ << "[WEBCAM] " // Header #if 0 #define __LOG_W__ __LOG__ << "[*] " << __FUNCTION__ << " (" << __FILE__ << ":" << __LINE__ << ") " // Warning #define __LOG_E__ __LOG__ << "[!] " << __FUNCTION__ << " (" << __FILE__ << ":" << __LINE__ << ") " // Error @@ -126,6 +125,8 @@ public: #define __LOG_E__ __LOG__ << "[!] " #endif #define __LOG_V__ __LOG__ << "[V] " // Verbose +#define __LOG_SENS__ __LOG__ << "[REALSENSE] " // Verbose +#define __LOG_CAM__ __LOG__ << "[WEBCAM] " // Verbose #define __LOG_F__ __LOG__ << __FUNCTION__ << ": " #define __LOG_FUNC__ __LOG_V__ << __FUNCTION__ << "\n"; diff --git a/include/platform/log/log_scope.cpp b/include/platform/log/log_scope.cpp new file mode 100644 index 0000000..0df22d6 --- /dev/null +++ b/include/platform/log/log_scope.cpp @@ -0,0 +1,18 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "log/log_scope.h" + #include "log/log.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +LogScope::LogScope(const char *s, const char *e) : exit(e) +{ __LOG_H__ << s; } +LogScope::~LogScope() +{ __LOG_H__ << exit; } +//------------------------------------------------------------------------------ diff --git a/include/platform/math/nmath.cpp b/include/platform/math/nmath.cpp new file mode 100644 index 0000000..ea4ed46 --- /dev/null +++ b/include/platform/math/nmath.cpp @@ -0,0 +1,127 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include "math/nmath.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +Math::rOrder Math::ReverserRotationOrder(rOrder r) +{ + switch (r) + { + case rOrder_ZYX: return rOrder_XYZ; + case rOrder_YZX: return rOrder_XZY; + case rOrder_ZXY: return rOrder_YXZ; + case rOrder_XZY: return rOrder_YZX; + case rOrder_YXZ: return rOrder_ZXY; + case rOrder_XYZ: return rOrder_ZYX; + default: return rOrder_Default; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Math::Sqrt(float v) +{ return sqrtf(v); } + +float Math::TestEqual(float a, float b, float e) +{ return Types::Abs(b - a) < e ? true : false; } +bool Math::EqualZero(float v, float e) +{ return (v < -e) || (v > e) ? false : true; } + +float Math::Pow(float v, float e) +{ return pow(v, e); } + +float Math::Ceil(float v) +{ return (v < 0) ? (float)((int)v) : (float)((int)(v + 1)); } +float Math::Floor(float v) +{ return (v < 0) ? (float)((int)(v - 1)) : (float)((int)v); } +float Math::Mod(float v) +{ + double integral; + return (float)modf(v, &integral); +} +float Math::RangeAdjust(float v, float old_min, float old_max, float new_min, float new_max) +{ return Types::Clamp((v - old_min) / (old_max - old_min) * (new_max - new_min) + new_min, new_min, new_max); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Math::IsFinite(float v) { return (v <= FLT_MAX && v >= -FLT_MAX); } +//------------------------------------------------------------------------------ + +#define __USE_LUT_BASED_TRIG__ 0 + +#if (__USE_LUT_BASED_TRIG__ == 0) + +void Math::Init() {} + +//------------------------------------------------------------------------------ +float Math::Quantize(float v, float q) { return Floor(v / q) * q; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Math::Sin(float v) { return sin(v); } +float Math::ASin(float v) { return asin(Types::Clamp(v, -1.f, 1.f)); } +float Math::Cos(float v) { return cos(v); } +float Math::ACos(float v) { return acos(Types::Clamp(v, -1.f, 1.f)); } +float Math::Tan(float v) { return tan(v); } +float Math::ATan(float v) { return atan(v); } +//------------------------------------------------------------------------------ + +#else + + #include "container/narray.h" + + // keep as power of 2 +#define __LUT_PRECISION 64 + +static nArray lCos, lSin, lTan, lACos, lASin, lAtan; + +//------------------------------------------------------------------------------ +void Math::Init() +{ + lCos.Allocate(__LUT_PRECISION); + lSin.Allocate(__LUT_PRECISION); + lTan.Allocate(__LUT_PRECISION); + lACos.Allocate(__LUT_PRECISION); + lASin.Allocate(__LUT_PRECISION); + + for (int v = 0; v < __LUT_PRECISION; ++v) + { + const float deg = ((float)v / __LUT_PRECISION) * (Pi * 2.f); + + lSin[v] = sin(deg); + lCos[v] = cos(deg); + lTan[v] = tan(deg); + + const float inv = ((float)v / __LUT_PRECISION) * 2.f - 1.f; + + lASin[v] = asin(inv); + lACos[v] = acos(inv); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Math::Sin(float v) +{ return lSin[int(v * (__LUT_PRECISION / (Pi * 2.f))) & (__LUT_PRECISION - 1)]; } +float Math::ASin(float v) +{ return lASin[int((v + 1.f) * (__LUT_PRECISION / 2)) & (__LUT_PRECISION - 1)]; } +float Math::Cos(float v) +{ return lCos[int(v * (__LUT_PRECISION / (Pi * 2.f))) & (__LUT_PRECISION - 1)]; } +float Math::ACos(float v) +{ return lACos[int((v + 1.f) * (__LUT_PRECISION / 2)) & (__LUT_PRECISION - 1)]; } +float Math::Tan(float v) +{ return lTan[int(v * (__LUT_PRECISION / (Pi * 2.f))) & (__LUT_PRECISION - 1)]; } +float Math::ATan(float v) +{ return atan(v); } +//------------------------------------------------------------------------------ + +#endif diff --git a/include/platform/memory/endian.cpp b/include/platform/memory/endian.cpp new file mode 100644 index 0000000..7858386 --- /dev/null +++ b/include/platform/memory/endian.cpp @@ -0,0 +1,63 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "memory/endian.h" + #include "platform_config.h" + #include "log/log.h" + + +namespace GS { + namespace Endian { + +static Config g_host_endian = Undefined; + +//------------------------------------------------------------------------------ +void SwapBytes(void *in_p, size_t n) +{ + if (n == 1) + return; + + __ASSERT__(!(n & 1)); + + char *p = (char *)in_p; + for (size_t c = 0; c < n / 2; ++c) + { + char tmp = p[c]; + p[c] = p[n - c - 1]; + p[n - c - 1] = tmp; + } +} +Config GetHostConfiguration() +{ + if (g_host_endian == Undefined) + { + union + { + uint i; + char c[4]; + } bint = { 0x01020304 }; + + g_host_endian = bint.c[0] == 1 ? Big : Little; + + if (g_host_endian == Big) + __LOG__ << "Memory configuration: Big endian.\n"; + else __LOG__ << "Memory configuration: Little endian.\n"; + } + return g_host_endian; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void *ToHost(void *p, size_t size, Config source_endian) +{ + if (GetHostConfiguration() != source_endian) + SwapBytes(p, size); + return p; +} +//------------------------------------------------------------------------------ + + } +} \ No newline at end of file diff --git a/include/platform/memory/memory.cpp b/include/platform/memory/memory.cpp new file mode 100644 index 0000000..8b89c86 --- /dev/null +++ b/include/platform/memory/memory.cpp @@ -0,0 +1,116 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include "memory/memory.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +uchar Memory::GetBitCount(int v) +{ + uchar n; + for (n = 0; v; ++n) + v &= (v - 1); + return n; +} +uchar Memory::GetShiftCount(int v) +{ + uchar n; + for (n = 0; !(v & 1) && (n < 32); ++n) + v >>= 1; + return n; +} +uchar Memory::CountSetBit(int v) +{ + uchar count = 0; + for (int n = 0; n < 32; ++n) + { + count += v & 1; + v >>= 1; + } + return count; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Memory::WriteBit(uchar *mem , uint bitoffset, uint bitcount, uint v) +{ + mem += bitoffset >> 3; + bitoffset &= 7; + + while (bitcount--) + { + mem[0] |= ((v >> bitcount) & 1) << bitoffset; + + if (bitoffset == 7) + { + bitoffset = 0; + mem++; + } + else + ++bitoffset; + } +} +uint Memory::ReadBit(uchar *base, uint offsetbit, uint nbit) +{ + base += offsetbit >> 3; + offsetbit &= 7; + + uint v = 0; + while (nbit--) + { + v += v; + if (base[0] & (1 << offsetbit)) + v |= 1; + if (offsetbit == 7) {offsetbit = 0; base++;} else offsetbit++; + } + return v; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Memory::Compare(const void *a, const void *b, size_t n) +{ + if (!a || !b) + return true; + + // 8 bit padding. + uchar *ba = (uchar *)a, *bb = (uchar *)b; + for (uint c = n & 3; c; --c) + if (*ba++ != *bb++) + return true; + + // 32 bit compare. + uint *la = (uint *)ba, *lb = (uint *)bb; + for (uint l = n >> 2; l; --l) + if (*la++ != *lb++) + return true; + + return false; +} +void Memory::Copy(void *d, const void *s, size_t n) +{ memcpy(d, s, n); } +void Memory::Set(void *a, char v, size_t s) +{ memset(a, v, s); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Memory::Fill(void *p, const char *pattern, size_t s) +{ + size_t p_l = 0; + for ( ; pattern[p_l] != 0; ++p_l) {} + + char *out = (char *)p; + for (; s >= p_l; s -= p_l) + { + Copy((void *)out, pattern, p_l); + out += p_l; + } + Copy((void *)out, pattern, s); +} +//------------------------------------------------------------------------------ diff --git a/include/platform/network/network_interface.cpp b/include/platform/network/network_interface.cpp new file mode 100644 index 0000000..a98a6c7 --- /dev/null +++ b/include/platform/network/network_interface.cpp @@ -0,0 +1,22 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "network/network_interface.h" + #include "nstring/nstring.h" + + using namespace GS::Network; + + +//------------------------------------------------------------------------------ +bool INetwork::SendString(void *peer, const GS::String &s) +{ + return Send(peer, (void *)s.c_str(), (size_t)(s.Len() + 1)); +} +bool INetwork::BroadcastString(const GS::String &s) +{ + return Broadcast((void *)s.c_str(), (size_t)(s.Len() + 1)); +} +//------------------------------------------------------------------------------ diff --git a/include/platform/nstring/nstring.cpp b/include/platform/nstring/nstring.cpp new file mode 100644 index 0000000..262d09a --- /dev/null +++ b/include/platform/nstring/nstring.cpp @@ -0,0 +1,1310 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include + + #if __PLATFORM_WINDOWS__ + #include + #elif __PLATFORM_NINTENDO_WII__ + #include + #elif __PLATFORM_POSIX__ + #include + #include + #endif + + #include "nstring/nstring.h" + #include "container/nlist.h" + #include "container/narray.h" + #include "platform_config.h" + #include "alloc/ialloc.h" + + using namespace GS; + + +//------------------------------------------------------------------------------ +static char __lowercase(char c) +{ + if ((c >= 'A') && (c <= 'Z')) + c = c - 'A' + 'a'; + return c; +} +static bool __isValidSymbolCharacter(char c) +{ + return ( + ((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + ((c >= '0') && (c <= '9')) || + (c == '_') + ); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +#if (__PLATFORM_LINUX__ || __PLATFORM_OSX__ || __PLATFORM_IOS__ || __PLATFORM_ANDROID_NDK__) +void strupr(char *s) +{ + for (; s[0]; ++s) + if ((s[0] >= 'a') || (s[0] <= 'z')) + s[0] = toupper(s[0]); +} +void strlwr(char *s) +{ + for (; s[0]; ++s) + if ((s[0] >= 0x41) || (s[0] <= 0x5A)) + s[0] = tolower(s[0]); +} +#endif +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void String::NormalizeEOL(EOLConvention to_eol) +{ + switch (to_eol) + { + case EOLUnix: + { + uint invalid_eol_count = 0; + for (char *p = _p.c_ptr(); p[0] && p[1]; ++p) + if ((p[0] == '\r') && (p[1] == '\n')) + { + ++invalid_eol_count; + ++p; + } + + Array _o(Size() - invalid_eol_count + 1); // remove 1 byte per invalid EOL + + char *o = _o.c_ptr(), *p = _p.c_ptr(); + for ( ; p[0] && p[1]; ++p) + if ((p[0] == '\r') && (p[1] == '\n')) + { + *o++ = '\n'; + ++p; + } + else + *o++ = p[0]; + + if (p[0] != 0) + *o++ = *p++; + + *o = 0; + _p.Transfer(_o); + } + break; + + case EOLWindows: + { + uint invalid_eol_count = 0; + char *p = _p.c_ptr(); + for (int n = 0; p[n]; ++n) + if ((p[n] == '\n') && ((n > 0) && (p[n - 1] != '\r'))) + ++invalid_eol_count; + + Array _o(Size() + invalid_eol_count + 1); // add 1 byte per invalid EOL + + char *o = _o.c_ptr(); + p = _p.c_ptr(); + for (int n = 0; p[n]; ++n) + if ((p[n] == '\n') && ((n > 0) && (p[n - 1] != '\r'))) + { + *o++ = '\r'; + *o++ = '\n'; + } + else + *o++ = p[n]; + + *o = 0; + _p.Transfer(_o); + } + break; + } + Touch(); +} +String String::NormalizedEOL(EOLConvention to_eol) const +{ + String o(*this); + o.NormalizeEOL(to_eol); + return o; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint String::Len() const +{ + if (len == -1) + (const_cast (len)) = _p.IsValid() ? strlen(_p) : 0; + return len; +} +size_t String::Size() const +{ + size_t size = 0; + for (char *p = _p; p[0]; ++p) + ++size; + return size; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String String::RewritePatternAll(const char *p, const char *pattern, RewriteFunc &rewrite_func) +{ + String out; + + forever + { + const char *s, *e; + s = String::LocatePattern(p, pattern, &e); + + if (!s) + { + // append reminder + out += String(p, p + String::strlen(p)); + break; + } + + // append skipped segment + out += String(p, s); + + // extract args... + List args; + + String source(s, e); + if (!source.Extract(pattern, args)) + break; + + // ...do rewrite. + out += rewrite_func(source, args); + + p = e; + } + return out; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::Extract(const char *format, List &arg) +{ + arg.Clear(); + + const char *o = format; + for (const char *i = c_str(); i[0] && o[0]; ) + { + if (o[0] == '%') + { + ++o; + + // get arg value + const char *e = i; + for (; (e[0] != o[0]) && e[0]; ++e); + + arg.Add(String(i, e)); + i = e; + } + else + { + if (i[0] != o[0]) + { + // ignore character mismatch on space + if (i[0] == ' ') + { + ++i; + continue; + } + + // source format mismatch + return false; + } + + ++i; + ++o; + } + } + return true; +} +const char *String::LocatePattern(const char *s, const char *format, const char **e) +{ + for (; s[0]; ++s) + { + const char *o = format; + + if (s[0] != o[0]) + continue; + + const char *i = s; + while (i[0] && o[0]) + { + if (o[0] == '%') + { + ++o; + for (; (i[0] != o[0]) && i[0]; ++i); + } + else + { + if (i[0] != o[0]) + { + // ignore character mismatch on space + if (i[0] == ' ') + { + ++i; + continue; + } + + // source format mismatch + o = NULL; + break; + } + + ++i; + ++o; + } + } + if (o == NULL) + continue; + + if (e) + *e = i; + return s; + } + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::Compare(const char *s, CaseSensitivity cs) const +{ + char *p = _p.c_ptr(); + + if (!s) + return true; + if (!p) + return false; + + if (cs == CaseSensitive) + { + while (*p && *s) + if (*p++ != *s++) + return false; + } + else + { + while (*p && *s) + if (__lowercase(*p++) != __lowercase(*s++)) + return false; + } + return p[0] == s[0]; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::StartsWith(const char *b, CaseSensitivity cs) const +{ + uint b_len = strlen(b); + if (b_len > Len()) + return false; + return c_str() ? Left(b_len).Compare(b, cs) : false; +} +bool String::EndsWith(const char *b, CaseSensitivity cs) const +{ + uint b_len = strlen(b); + if (b_len > Len()) + return false; + return c_str() ? Right(b_len).Compare(b, cs) : false; +} +bool String::Contains(const char *b, CaseSensitivity cs) const +{ return c_str() ? asbool(FindString(b, cs)) : false; } +bool String::Replace(const char *what, const char *by, CaseSensitivity cs) +{ + char *sp = _p.c_ptr() ? FindString(what, 0, cs) : NULL; + if (!sp) + return false; + + uint what_len = strlen(what), + by_len = strlen(by); + uint final_len = Len() - what_len + by_len; + + Array np(final_len + 1, Alloc::StringBuffer); + char *wp = np; + if (np.IsNull()) + return false; + + memcpy(wp, _p.c_ptr(), sp - _p.c_ptr()); + wp += sp - _p; + memcpy(wp, by, by_len); + wp += by_len; + memcpy(wp, sp + what_len, (_p + Len()) - (sp + what_len) + 1); + + Clear(); + _p = np; + return true; +} +bool String::ReplaceAll(const char **what, const char **by, bool match_whole_word) +{ + if (!_p) + return false; // no replace + + uint final_len = Len(); + + Array p_out(Alloc::StringBuffer); + char *_p_out = NULL; + + for (uint p = 0; p < 2; ++p) + { + bool has_replacement = false; + for (char *c_p = _p; *c_p; ) + { + // Search for a match. + uint n; + for (n = 0; what[n] && by[n]; ++n) + if (!strccmp(c_p, what[n])) + break; + + if (what[n] && by[n]) + { + // Got a match. + size_t what_len = strlen(what[n]), + by_len = strlen(by[n]); + + // Check whole word constraint. + bool do_replace = true; + + if (match_whole_word) + { + if ((c_p > _p) && __isValidSymbolCharacter(c_p[-1])) + do_replace = false; + else + if (c_p[what_len] && __isValidSymbolCharacter(c_p[what_len])) + do_replace = false; + } + + if (do_replace) + { + if (_p_out) + { + strncpy(_p_out, by[n], by_len); + _p_out += by_len; + } + else + final_len += by_len - what_len; + + has_replacement = true; + } + else + if (_p_out) + { + strncpy(_p_out, c_p, what_len); + _p_out += what_len; + } + + c_p += what_len; + } + else + { + if (_p_out) + *_p_out++ = *c_p; + ++c_p; + } + } + + if (!has_replacement) + return false; // no replace + + if (!_p_out) + { + p_out.Allocate(final_len + 1); + _p_out = p_out; + } + } + + // Commit modified buffer to string. + Clear(); + p_out[final_len] = 0; + _p = p_out; + len = final_len; + hash = 0; + return true; +} +bool String::ReplaceAll(const char *what, const char *by, bool match_whole_word) +{ + const char *_what[] = { what, NULL }, *_by[] = { by, NULL }; + return ReplaceAll(_what, _by, match_whole_word); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t String::Utf8toUtf32(const uchar *utf8, uint *utf32) +{ + __ASSERT__(utf8); + __ASSERT__(utf32); + + const uchar *p = utf8; + int length = GetUtf8CharSize(utf8); + + switch (length) + { + case 4: *utf32 = (*p ^ 0xf0); break; + case 3: *utf32 = (*p ^ 0xe0); break; + case 2: *utf32 = (*p ^ 0xc0); break; + case 1: *utf32 = *p; break; + + default: + *utf32 = 0; + break; + } + + for (int n = length; n > 1; --n) + { + ++p; + *utf32 <<= 6; + *utf32 |= (*p ^ 0x80); + } + return length; +} +size_t String::GetUtf8CharSize(const uchar *utf8) +{ + __ASSERT__(utf8); + + uchar c = utf8[0] >> 3; + + // 6 => 0x7e + // 5 => 0x3e + if (c == 0x1e) + return 4; + + c >>= 1; + if (c == 0xe) + return 3; + c >>= 1; + if (c == 0x6) + return 2; + + return 1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String String::FromUcs2(const ushort *ucs2) +{ + Array out(256); + size_t out_count = 0; + + for (uint n = 0; ucs2[n]; ++n) + { + wchar_t w = ucs2[n]; + + if (out_count > (out.GetCount() - 4)) + out.Reallocate(out.GetCount() * 2); + + if (w <= 0x7f) + out[(int)out_count++] = (char)w; + + else if (w <= 0x7ff) + { + out[(int)out_count++] = 0xc0 | ((w >> 6) & 0x1f); + out[(int)out_count++] = 0x80 | (w & 0x3f); + } + else /* if (w <= 0xffff) */ + { + out[(int)out_count++] = 0xe0 | ((w >> 12) & 0x0f); + out[(int)out_count++] = 0x80 | ((w >> 6) & 0x3f); + out[(int)out_count++] = 0x80 | (w & 0x3f); + } +/* else if (w <= 0x10ffff) + { + out[out_count++] = 0xf0 | ((w >> 18) & 0x07); + out[out_count++] = 0x80 | ((w >> 12) & 0x3f); + out[out_count++] = 0x80 | ((w >> 6) & 0x3f); + out[out_count++] = 0x80 | (w & 0x3f); + } + else + out[out_count++] = '?'; */ + } + + return String(out.c_ptr(), out.c_ptr() + out_count); +} +Array String::toUcs2() const +{ + if (!_p) + return Array (Alloc::StringBuffer); + + // Get utf-8 character count. + int ccount = 0; + + char *p = _p; + for (; p[0]; ++ccount) + p += GetUtf8CharSize((const uchar *)p); + + // Allocate array. + Array ucs2(ccount + 1, Alloc::StringBuffer); + + p = _p; + for (ccount = 0; p[0]; ++ccount) + { + uint utf32; + p += Utf8toUtf32((const uchar *)p, &utf32); + ucs2[ccount] = utf32 & 0xffff; + } + ucs2[ccount] = 0; + + return ucs2; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::IsAbsolutePath() const +{ return asbool((Len() > 2) && (c_str()[1] == ':')); } +String String::BeautifyFileName(bool allow_spaces) const +{ + if (!_p) + return String(); + + Array p(Len() + 1, Alloc::StringBuffer); + strncpy(p.c_ptr(), c_str(), Len() + 1); + + for (uint n = 0; n < Len(); ++n) + { + if (p[n] == ' ') + { + if (!allow_spaces) + p[n] = '_'; + } + else + { + if (p[n] == '_') + p[n] = ' '; + + else + { + if (n > 0) + { + if ((p[n - 1] == ' ') && (p[n] >= 'a') && (p[n] <= 'z')) + p[n] += 'A' - 'a'; + } + else + if ((p[n] >= 'a') && (p[n] <= 'z')) + p[n] += 'A' - 'a'; + } + } + } + return String(&p[0]); +} +String String::CutFilePath() const +{ + String b = *this; + b.FileCutPath(); + return b; +} +String String::CutFileExtension() const +{ + String b = *this; + b.FileCutExtension(); + return b; +} +String String::CutFileName() const +{ + String b = *this; + b.FileCutName(); + return b; +} +String String::CleanFilePath() const +{ + String b = *this; + b.FileCleanName(); + return b; +} +String String::GetFileName() const +{ + String b = *this; + b.FileCutPathAndExtension(); + return b; +} +String String::GetFileNameAndExtension() const +{ + String b = *this; + b.FileCutPath(); + return b; +} +String String::GetFilePath() const +{ + String b = *this; + b.FileCutName(); + return b; +} +String String::GetFileExtension() const +{ return FileGetExtension(c_str()); } +String String::GetSwappedExtension(const char *ext) const +{ + String b = *this; + b.FileSwapExtension(ext); + return b; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int String::Compare(const String &c, const String &n) +{ + const char *a = c.c_str(), *b = n.c_str(); + + if (!a || !b) + return a == b ? 0 : 1; + + while (a[0] || b[0]) + { + if (!b[0]) return -1; + if (!a[0]) return 1; + + if (b[0] < a[0]) return -1; + if (b[0] > a[0]) return 1; + + a++; + b++; + } + return 0; +} +String String::Upper() const +{ + String s(_p); + if (!s.IsEmpty()) + strupr(s._p); + s.Touch(); + return s; +} +String String::Lower() const +{ + String s(_p); + if (!s.IsEmpty()) + strlwr(s._p); + s.Touch(); + return s; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String String::Slice(uint s, uint e) const +{ + if (s > Len()) s = Len(); + if (e > Len()) e = Len(); + return String(_p + s, _p + e); +} +String String::TrimChar(char c) +{ + int occurence = 0; + for (char *p = _p; p[0]; p++) + if (p[0] == c) + occurence++; + if (!occurence) + return *this; + + // Trim character occurrences. + Array new_string(Len() - occurence + 1, Alloc::StringBuffer); + char *pnew_string = &new_string[0]; + + for (char *p = _p; p[0]; p++) + if (p[0] != c) + *pnew_string++ = p[0]; + pnew_string[0] = 0; + + return String(&new_string[0]); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t String::IndexOf(char c, uint p) const +{ + for (size_t n = p; n < Len(); ++n) + if (_p[(int)n] == c) + return n; + return (size_t)-1; +} +char *String::FindString(const char *c, uint p, CaseSensitivity cs) const +{ + size_t len_c = strlen(c); + + if (len_c <= Len()) + for (size_t n = p; n <= (Len() - len_c); ++n) + { + size_t i = 0; + + switch (cs) + { + case CaseSensitive: + for (; i < len_c; ++i) + if (_p[(int)(n + i)] != c[i]) + break; + break; + + case CaseInsensitive: + for (; i < len_c; ++i) + if (__lowercase(_p[(int)(n + i)]) != __lowercase(c[i])) + break; + break; + } + + if (i == len_c) + return &_p[(int)n]; // match + } + + return NULL; +} +String String::Left(uint n) const +{ return String(_p, _p + Types::Min(n, Len())); } +String String::Right(uint n) const +{ + const uint l = Len(); + return String(_p + Types::Min(n, l), _p + l); +} +String String::Mid(uint p, int n) const +{ + uint l = Len(); + p = Types::Min(p, l); + + int char_left = int(l) - int(p); + n = (n < 0) || (n > char_left) ? char_left : n; + + return String(_p + p, _p + p + n); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String String::Format(const char *format, ...) +{ + char static_buffer[4096]; + + va_list varg; + va_start(varg, format); + vsnprintf(static_buffer, 4095, format, varg); + va_end(varg); + + return String(static_buffer); +} +String String::operator + (const char *_ptr) const +{ + String _s = *this; + _s += _ptr; + return _s; +} +String String::operator + (const String &s) const +{ + String _s = *this; + _s += s.c_str(); + return _s; +} +void String::operator += (const char *_ptr) +{ + if (!_ptr) + return; + + if (_p.IsNull()) + *this = _ptr; + + else + { + size_t in_len = strlen(_ptr), total_len = Len() + in_len; + + if ((total_len + 1) <= _p.GetCount()) + { + memcpy(&_p[Len()], _ptr, in_len); + _p[(int)total_len] = 0; + Touch(); + } + else + { + Array n_p(total_len + 1, Alloc::StringBuffer); + + if (n_p.IsValid()) + { + memcpy(&n_p[0], c_str(), Len()); + memcpy(&n_p[Len()], _ptr, in_len); + n_p[(int)total_len] = 0; + + _p.Transfer(n_p); + Touch(); + } + else + Clear(); + } + } +} +void String::operator += (float v) +{ + char tmp[32]; + _snprintf(tmp, 31, "%.4f", v); + *this += tmp; +} +void String::operator += (double v) +{ + char tmp[32]; + _snprintf(tmp, 31, "%.4f", v); + *this += tmp; +} +void String::operator += (int v) +{ + char tmp[32]; + _snprintf(tmp, 31, "%d", v); + *this += tmp; +} +void String::operator += (uint v) +{ + char tmp[32]; + _snprintf(tmp, 31, "%d", (int)v); + *this += tmp; +} +void String::operator += (bool v) +{ *this += v ? "true" : "false"; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String &String::operator = (const String &b) +{ + if (b.IsEmpty()) + Clear(); + else + { + Set(b.c_str(), b.c_str() + b.Len()); + hash = b.hash; + len = b.len; + } + return *this; +} +String &String::operator = (const char *s) +{ + Set(s); + return *this; +} +void String::Set(const char *s, const char *e) +{ + // TODO properly handle copying one part of a string to itself. + if (s == _p) + return; + + size_t new_len = s ? (e ? e - s : strlen(s)) : 0; + + if (new_len > 0) + { + if ((new_len + 1) > _p.GetCount()) + { + Clear(); + _p.Allocate(new_len + 8); // Note: +8 to help reduce allocator pressure on string concatenation. + } + + if (_p.IsValid()) + { + memcpy(_p, s, new_len); + _p[(int)new_len] = 0; + Touch(); + } + else + Clear(); + } + else + Clear(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String &String::operator << (const String &v) +{ *this += v; return *this; } +String &String::operator << (const char *v) +{ *this += v; return *this; } +String &String::operator << (float v) +{ *this += v; return *this; } +String &String::operator << (double v) +{ *this += v; return *this; } +String &String::operator << (int v) +{ *this += v; return *this; } +String &String::operator << (uint v) +{ *this += v; return *this; } +String &String::operator << (bool v) +{ *this += v ? "true" : "false"; return *this; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int String::atoh(const char *_sr) +{ + ushort p = 0, s = 0; + int v = 0; + char str[32]; + + strncpy(str, _sr, 8); + str[8] = 0; + + strlwr(str); + + while (str[p]) + { + if ((str[p] == 'x') || (str[p] == 'h')) + { + s = (ushort)(p + 1); + break; + } + p++; + } + while (str[s]) + { + v *= 16; + if ((str[s] >= '0') && (str[s] <= '9')) + v += str[s] - '0'; + else if ((str[s] >= 'a') && (str[s] <= 'f')) + v += str[s] - 'a' + 10; + s++; + } + return v; +} +int String::atoi(const char *p) +{ + char sign = 1; + if (p[0] == '-') + { + sign = -1; + p++; + } + int integer = 0; + while ((p[0] >= '0') && (p[0] <= '9')) + { + integer *= 10; + integer += *p++ - '0'; + } + return (integer * sign); +} +float String::atof(const char *s, const char *e, bool support_comma) +{ + if (!s) + return 0.f; + if (!e) + e = s + strlen(s); + + float sign = 1; + if (s == e) + return 0.f; + if (s[0] == '-') + { + sign = -1; + s++; + } + if (s == e) + return -0.f; + + float tt = 1.f; + float real = 0.f; + float integer = 0.f; + + while ((s < e) && (s[0] != '.') && ((s[0] != ',') || !support_comma)) + { + if (s[0] == 'e') + goto exponent; + if ((s[0] < '0') || (s[0] > '9')) + return (float)(integer * sign); + + integer *= 10.f; + integer += *s++ - '0'; + } + if (s == e) + return (float)(integer * sign); + + s++; + while ((s < e) && (s[0] != 'e')) + { + if ((s[0] != '-') && ((s[0] < '0') || (s[0] > '9'))) + return sign * (integer + (float)real / tt); + real *= 10.f; + real += *s++ - '0'; + tt *= 10.f; + } + if (s == e) + return sign * (integer + real / tt); + +exponent:; + + s++; + if (s == e) + return (float)(integer * sign); + + int expsign = (*s++ == '-') ? -1 : 1; + + if (s == e) + return (float)(integer * sign); + + uint exp = 0; + float mulexp = 1; + + while ((s < e) && (s[0] >= '0') && (s[0] <= '9')) + { + exp *= 10; + exp += *s++ - '0'; + } + for (uint expc = 0; expc < exp; expc++) + mulexp *= 10.f; + + if (expsign == -1) + return (float)(sign * (integer + (float)real / tt)) / mulexp; + return (float)(sign * (integer + (float)real / tt)) * mulexp; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::FileCleanName() +{ + if (!_p) + return false; + + char *f = _p; + Array n(Len() + 1, Alloc::StringBuffer); + if (n.IsNull()) + return false; + + // Remove drive letter case under the Windows platform. +#if __PLATFORM_WINDOWS__ + if ((Len() > 2) && (f[1] == ':')) + if ((f[0] >= 'A') && (f[0] <= 'Z')) + f[0] += 'a' - 'A'; +#endif + + // Convert directory separator from backslash to forward slash. + char *c = n; + for (; f[0]; ++f) + if (f[0] == '\\') + f[0] = '/'; + + // Remove redundant forward slashes. + f = _p; + while (f[0]) + { + if (f[0] == '/') + { + f++; + while (f[0] && (f[0] == '/')) + f++; + *c++ = '/'; + } + else + *c++ = *f++; + } + c[0] = 0; + + // Replace illegal characters. + f = n; +#if __PLATFORM_WINDOWS__ + if (!strcmp(f, "file:/")) + f += 6; +#endif + + if (f[0] == '@') // Allow internal mount points. + f++; + + for (int i = 0; f[i]; ) + { + uint char_size = GetUtf8CharSize((const uchar *)&f[i]); + + if (char_size == 1) + if ( + // Allowed ranges. + !((f[i] >= 'a') && (f[i] <= 'z')) && + !((f[i] >= 'A') && (f[i] <= 'Z')) && + !((f[i] >= '0') && (f[i] <= '9')) && + + // Allowed characters. + (f[i] != ' ') && (f[i] != '.') && (f[i] != '_') && (f[i] != '/') && + (f[i] != '-') && (f[i] != '!') && (f[i] != '+') && (f[i] != '(') && + (f[i] != ')') && (f[i] != '#') && (f[i] != '\'') && (f[i] != '&') + + // Windows drive letter. +#if __PLATFORM_WINDOWS__ + && !((f[i] == ':') && (i == 1)) +#endif + ) + f[i] = '_'; + + i += char_size; + } + + // Now commit. + Clear(); + _p = n; + Touch(); + return true; +} +String String::FileGetExtension(const char *path) +{ + if (!path) + return ""; + + int n = (int)strlen(path); + while (path[n] != '.' && (n >= 0)) + n--; + + return n < 0 ? "" : &path[n + 1]; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +size_t String::strlen(const char *s) +{ + size_t n = 0; + if (s) + for ( ; s[n]; ++n); + return n; +} +bool String::strccmp(const char *sa, const char *sb) +{ + if (!sa || !sb) + return false; + + while (sa[0] && sb[0]) + if (*sa++ != *sb++) + return true; + + return false; +} +char *String::strfindchar(const char *f, const char c, const char *t) +{ + if (t) + while (f[0] && (f[0] != c) && (f < t)) + f++; + else + while (f[0] && (f[0] != c)) + f++; + + return const_cast (f); +} +void String::rmname(char *s) +{ + if (!s) + return; + int n = (int)strlen(s) - 1; + while ((n >= 0) && (s[n] != ':') && (s[n] != '\\') && (s[n] != '/')) + n--; + if (n < 0) + s[0] = 0; + else + if (s[n + 1]) + s[n + 1] = 0; +} + +void String::rmpath(char *s) +{ + String tmp(s); + + int n = (int)tmp.Len(); + const char *p = tmp.c_str(); + if (!p) + return; + + while ((n >= 0) && (p[n] != '\\') && (p[n] != '/')) + n--; + if (n < 0) + return; + + strcpy(s, &p[n+1]); +} +void String::rmext(char *s) +{ + if (!s) + return; + + int n = (int)strlen(s) - 1; + while ((n >= 0) && (s[n] != '.')) + { + if ((s[n] == '\\') || (s[n] == '/') || (s[n] == ':')) + break; + n--; + } + if (n < 0) + return; + s[n] = 0; +} +void String::rmpathext(char *s) +{ + rmpath(s); + rmext(s); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::Allocate(uint size) +{ + Touch(); + if (!_p.Allocate(size + 1)) + return false; + + Memory::Set(_p.c_ptr(), 0, _p.GetSize()); + return true; +} +void String::Touch() +{ + len = -1; + hash = 0; +} +void String::Clear() +{ + _p.Free(); + Touch(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::equals(const char *s, const uint hash) const +{ + if (hash && (hash != Hash())) + return false; + if (_p == s) + return true; + return (_p && !strcmp(s, _p)) ? true : false; +} +bool String::operator == (const String &b) const +{ return b.IsEmpty() ? IsEmpty() : equals(b, b.Hash()); } +bool String::operator == (const char *s) const +{ return s ? equals(s) : IsEmpty(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool String::operator != (const String &b) const +{ return !(*this == b); } +bool String::operator != (const char *s) const +{ return !(*this == s); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void String::operator += (const String &b) +{ + if (!b.IsEmpty()) + *this += b.c_str(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint String::strhash(const char *s) +{ + uint hash = 0; + + if (s) + while (s[0]) + { + hash = hash * 37 + s[0]; + s++; + } + + hash |= 1; + return hash; +} +uint String::Hash() const +{ + if (hash == 0) + hash = strhash(_p); + return hash; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void String::FileCutPath() +{ rmpath(_p); Touch(); } +void String::FileSwapExtension(const char *ext) +{ rmext(_p); Touch(); *this += ext; } +void String::FileCutExtension() +{ rmext(_p); Touch(); } +void String::FileCutPathAndExtension() +{ rmpathext(_p); Touch(); } +void String::FileCutName() +{ rmname(_p); Touch(); } +//------------------------------------------------------------------------------ diff --git a/include/platform/platform.cpp b/include/platform/platform.cpp new file mode 100644 index 0000000..a7c3278 --- /dev/null +++ b/include/platform/platform.cpp @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "platform.h" + #include "async/job.h" + #include "filesystem/filesystem.h" + #include "filesystem/io_base.h" + #include "input/input_system.h" + #include "licensing/licensing.h" + #include "analytics/analytics.h" + #include "billing/billing.h" + #include "log/file_log.h" + #include "log/log.h" + + using namespace GS; + + #define __ENABLE_PLATFORM_TRACE 0 + + template<> Platform *Singleton ::i = NULL; + String Platform::app_dir; + +static int g_start_clock = 0; +static Time g_start_time; + + +//------------------------------------------------------------------------------ +void Platform::Trace(const char *trace, const char *source, int line) +{ +#if __ENABLE_PLATFORM_TRACE + static FileLog platform_trace("c:/platform_trace.log"); + platform_trace << trace << "(" << source << "@" << line << ")\n"; +#endif +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +String Platform::GetAppPluginPath(const char *plugin) const +{ return ((app_dir + "/") + plugin).CleanFilePath(); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +uint Types::getPOT(uint v) +{ uint n = 1; for (; n < v; n *= 2) {} return n; } +bool Types::isPOT(uint v) +{ return ((v != 0) && ((v & (~v + 1)) == v)); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int Platform::GetStartClock() const +{ return g_start_clock; } +Time Platform::GetStartTime() const +{ return g_start_time; } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Platform::Initialize() +{ + if (initialized) + return; + + g_start_clock = GetClock(); + g_start_time = GetTime(); + + job_manager->CreateJobThreadPool(Types::Max(GetSystemCoreCount() - 1, 1)); // keep 1 core for the master thread + + initialized = true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Platform::Platform() : initialized(false) +{ + io = new IO::Filesystem; + job_manager = new ASync::JobManager; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/rand/rand.cpp b/include/platform/rand/rand.cpp new file mode 100644 index 0000000..a67fea9 --- /dev/null +++ b/include/platform/rand/rand.cpp @@ -0,0 +1,69 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "rand/rand.h" + + using namespace GS; + + +#define __USE_CUSTOM_RAND 1 + +static uint high = 0xDEADBEEF, low = high ^ 0x49616E42; +static uint _rg_pn = 0; + +//------------------------------------------------------------------------------ +void Random::Seed(uint s) +{ +#if __USE_CUSTOM_RAND + high = 0xDEADBEEF; + low = high ^ 0x49616E42; + for (uint n = 0; n < (s & 0x1fff); ++n) + Rand(1); +#else + srand(s); +#endif +} +uint Random::Rand(uint r) +{ + if (!r) + return 0; +#if __USE_CUSTOM_RAND + high = (high << 16) + (high >> 16); + high += low; + low += high; + return high % r; +#else + return rand() % r; +#endif +} +float Random::FRand(float r) +{ + return (float)Rand(65536) * r / 65536.0f;; +} +float Random::FRRand(float lo, float hi) +{ + const float v = (float)(Rand(65536)) / 65536.0f; + return v * (hi - lo) + lo; +} +uint Random::CRand(uint r) +{ + uint it; + uint _rg_cn = 0; + + if (!r) + return 0; + + it = 4; + while (it--) + { + _rg_cn = Rand(r); + if (_rg_cn != _rg_pn) + break; + } + _rg_pn = _rg_cn; + return _rg_cn; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/readme.txt b/include/platform/readme.txt new file mode 100644 index 0000000..1d59e96 --- /dev/null +++ b/include/platform/readme.txt @@ -0,0 +1,2 @@ +GS framework core source files. +This project compiles with no other dependency than stdlib. \ No newline at end of file diff --git a/include/platform/reflection/nenum_string.cpp b/include/platform/reflection/nenum_string.cpp new file mode 100644 index 0000000..d307ee9 --- /dev/null +++ b/include/platform/reflection/nenum_string.cpp @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "reflection/nenum_string.h" + #include "nstring/nstring.h" + + using namespace GS::Reflection; + + +//------------------------------------------------------------------------------ +const char *Enum::toString(int v, Dict *dict) +{ + for (int n = 0; dict[n].string_v; ++n) + if (dict[n].enum_v == v) + return dict[n].string_v; + return 0; +} +int Enum::fromString(const char *s, Dict *dict) +{ + GS::String string_v(s); + for (int n = 0; dict[n].string_v; ++n) + if (string_v == dict[n].string_v) + return dict[n].enum_v; + return -1; +} +//------------------------------------------------------------------------------ diff --git a/include/platform/social/social.cpp b/include/platform/social/social.cpp new file mode 100644 index 0000000..e69de29 diff --git a/include/platform/thread/atomic_value.cpp b/include/platform/thread/atomic_value.cpp new file mode 100644 index 0000000..90cd304 --- /dev/null +++ b/include/platform/thread/atomic_value.cpp @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "thread/atomic_value.h" + #include "assert/nassert.h" + + +#if __PLATFORM_WINDOWS__ + + #include + +namespace GS { + namespace Threading { + +//------------------------------------------------------------------------------ +int Atomic32::Inc() +{ return (int)InterlockedIncrement((LONG volatile *)v); } +int Atomic32::Dec() +{ return (int)InterlockedDecrement((LONG volatile *)v); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int Atomic32::Get() const +{ return *((int volatile *)v); } +int Atomic32::Set(int _v) +{ return InterlockedExchange((LONG volatile *)v, _v); } +int Atomic32::Cas(int cmp, int _v) +{ return InterlockedCompareExchange((LONG volatile *)v, _v, cmp); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Atomic32::Atomic32(int _v) +{ + v = _aligned_malloc(sizeof(LONG), 4); + __ASSERT__(v != NULL); + Set(_v); +} +Atomic32::~Atomic32() +{ _aligned_free(v); } +//------------------------------------------------------------------------------ + + } +} + +#elif (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 1)) // use >GCC4.1 builtins + + #include + +namespace GS { + namespace Threading { + +//------------------------------------------------------------------------------ +int Atomic32::Inc() +{ return __sync_fetch_and_add((long volatile *)v, 1) + 1; } +int Atomic32::Dec() +{ return __sync_fetch_and_add((long volatile *)v, -1) - 1; } +int Atomic32::Get() const +{ return *((int volatile *)v); } +int Atomic32::Set(int _v) +{ return __sync_lock_test_and_set((long volatile *)v, _v); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int Atomic32::Cas(int cmp, int _v) +{ return __sync_val_compare_and_swap((long volatile *)v, cmp, _v); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Atomic32::Atomic32(int _v) +{ + v = memalign(4, sizeof(long)); + __ASSERT__(v != NULL); + *(long *)v = _v; +} +Atomic32::~Atomic32() +{ free(v); } +//------------------------------------------------------------------------------ + + } +} + +#else + +namespace GS { + namespace Threading { + +//------------------------------------------------------------------------------ +int Atomic32::Get() const +{ __ASSERT(true); } +int Atomic32::Set(int _v) +{ __ASSERT(true); } +int Atomic32::Cas(int cmp, int _v) +{ __ASSERT(true); } +//------------------------------------------------------------------------------ + + } +} + +#endif diff --git a/include/platform/thread/mutex.cpp b/include/platform/thread/mutex.cpp new file mode 100644 index 0000000..a911c17 --- /dev/null +++ b/include/platform/thread/mutex.cpp @@ -0,0 +1,90 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "thread/mutex.h" + #include "alloc/ialloc.h" + + using namespace GS::Threading; + + +#if __PLATFORM_WINDOWS__ + + #define WIN32_LEAN_AND_MEAN + #include + +//------------------------------------------------------------------------------ +bool Mutex::TryLock() +{ return asbool(TryEnterCriticalSection((LPCRITICAL_SECTION)mutex)); } +void Mutex::Lock() +{ + if (mutex) + EnterCriticalSection((LPCRITICAL_SECTION)mutex); +} +void Mutex::Unlock() +{ + if (mutex) + LeaveCriticalSection((LPCRITICAL_SECTION)mutex); +} +Mutex::Mutex() +{ + mutex = new CRITICAL_SECTION; + InitializeCriticalSection((LPCRITICAL_SECTION)mutex); +} +Mutex::~Mutex() +{ + DeleteCriticalSection((LPCRITICAL_SECTION)mutex); + _safe_delete(mutex); +} +//------------------------------------------------------------------------------ + +#elif __PLATFORM_POSIX__ + + #include + +//------------------------------------------------------------------------------ +bool Mutex::TryLock() +{ return pthread_mutex_trylock(&mutex) != EBUSY ? true : false; } +void Mutex::Lock() +{ pthread_mutex_lock(&mutex); } +void Mutex::Unlock() +{ pthread_mutex_unlock(&mutex); } +Mutex::Mutex() +{ pthread_mutex_init(&mutex, NULL); } +Mutex::~Mutex() +{ pthread_mutex_destroy(&mutex); } +//------------------------------------------------------------------------------ + +#elif __PLATFORM_NINTENDO_WII__ + +//------------------------------------------------------------------------------ +bool Mutex::TryLock() +{ return OSTryLockMutex(&mutex); } +void Mutex::Lock() +{ OSLockMutex(&mutex); } +void Mutex::Unlock() +{ OSUnlockMutex(&mutex); } +Mutex::Mutex() +{ OSInitMutex(&mutex); } +Mutex::~Mutex() +{} +//------------------------------------------------------------------------------ + +#else + +//------------------------------------------------------------------------------ +bool Mutex::TryLock() +{ return true; } +void Mutex::Lock() +{} +void Mutex::Unlock() +{} +Mutex::Mutex() +{} +Mutex::~Mutex() +{} +//------------------------------------------------------------------------------ + +#endif diff --git a/include/platform/thread/thread.cpp b/include/platform/thread/thread.cpp new file mode 100644 index 0000000..3e5d4fb --- /dev/null +++ b/include/platform/thread/thread.cpp @@ -0,0 +1,230 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #if __PLATFORM_WINDOWS__ + #define WIN32_LEAN_AND_MEAN + #include + #include + #elif __PLATFORM_POSIX__ + #include + #endif + #include + #include "thread/thread.h" + #include "assert/nassert.h" + #include "log/log.h" + #include + #include + + +#if __PLATFORM_WINDOWS__ + +namespace GS { + namespace Threading { + +//------------------------------------------------------------------------------ +static unsigned __stdcall win32_thread_entrypoint(void *parm) +{ + Thread *t = (Thread *)parm; + __ASSERT__(t != NULL); + t->Execute(); + return 1; +} +void Thread::Join() +{ + if (handle != 0) + { + WaitForSingleObject((HANDLE)handle, INFINITE); + + CloseHandle((HANDLE)handle); + handle = 0; + } +} +bool Thread::Start() +{ + handle = (void *)_beginthreadex(NULL, 0, &win32_thread_entrypoint, (void *)this, 0, NULL); + return handle != 0; +} +bool Thread::SetPriority(int) +{ + return false; +} +void Thread::Kill() +{ + if (handle != 0) + { + CloseHandle((HANDLE)handle); + handle = 0; + } +} +void Thread::SetName(const char *name) +{ + if (name == nullptr) + return; + + // Conversion UTF-8 (ou ANSI selon votre projet) vers UTF-16 + int length = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0); + if (length == 0) + return; + + std::wstring wname(length, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, name, -1, &wname[0], length); + + SetThreadDescription(GetCurrentThread(), wname.c_str()); +} +void Thread::Switch() +{ SwitchToThread(); } + +Thread::Thread() +{ handle = 0; } +Thread::~Thread() +{ Kill(); } + + } +} +//------------------------------------------------------------------------------ + +#elif __PLATFORM_EMSCRIPTEN__ + +namespace GS { + namespace Threading { + +//------------------------------------------------------------------------------ +void *pthread_execute(void *parm) +{ return NULL; } +void Thread::Join() +{} +bool Thread::Start() +{ return false; } +bool Thread::SetPriority(int priority) +{ return false; } +void Thread::Kill() +{} +void Thread::SetName(const char *) +{} +void Thread::Switch() +{} +Thread::Thread() +{} +Thread::~Thread() +{} + + } +} +//------------------------------------------------------------------------------ + +#elif __PLATFORM_POSIX__ + +namespace GS { + namespace Threading { + +//------------------------------------------------------------------------------ +void *pthread_execute(void *parm) +{ + Thread *t = (Thread * const)parm; + t->Execute(); + return NULL; +} +void Thread::Join() +{ + pthread_join(*((pthread_t *)handle), NULL); +} +bool Thread::Start() +{ + if (!(handle = (void *)new pthread_t)) + return false; + return pthread_create((pthread_t *)handle, NULL, pthread_execute, this) == 0; +} +bool Thread::SetPriority(int priority) +{ +#ifdef EMSCRIPTEN + return false; +#else + if (!handle) + return false; + + sched_param param; + memset(¶m, 0, sizeof(param)); + param.sched_priority = priority; + + return asbool(pthread_setschedparam(*((pthread_t *)handle), SCHED_OTHER, ¶m) == 0); +#endif +} +void Thread::Kill() +{ +#if __PLATFORM_ANDROID_NDK__ + __ASSERT_MSG__(true, "Android NDK cannot kill a thread."); +#else + if (handle) + pthread_cancel(*((pthread_t *)handle)); + + delete (pthread_t *)handle; + handle = NULL; +#endif +} +void Thread::SetName(const char *) +{} +void Thread::Switch() +{ sched_yield(); } +Thread::Thread() +{ handle = NULL; } +Thread::~Thread() +{ delete (pthread_t *)handle; } + + } +} +//------------------------------------------------------------------------------ + +#elif __PLATFORM_NINTENDO_WII__ + +namespace GS { + namespace Threading { + +//------------------------------------------------------------------------------ +void *__OSthread_wii_execute(void *parm) +{ + nThread *t = (nThread * const)parm; + t->alive.Set(1); + return (void *)(t->Execute() ? 1 : 0); +} +void Thread::Join() +{ + void *rv; + if (alive.Get()) + OSJoinThread(&thread, &rv); + alive.Set(0); +} +void Thread::Resume() +{ + if (alive.Get()) + OSResumeThread(&thread); +} +void Thread::Suspend() +{ + if (alive.Get()) + OSSuspendThread(&thread); +} +bool Thread::Start() +{ return OSCreateThread(&thread, &__OSthread_wii_execute, this, thread_stack + 32768, 32768, 20, 0); } +bool Thread::SetPriority(int priority) +{ return alive.Get() ? OSSetThreadPriority(&thread, priority) : false; } +void Thread::Kill() +{ + if (alive.Get()) + OSCancelThread(&thread); + alive.Set(0); +} +void Thread::SetName(const char *) +{} +Thread::Thread() +{} +Thread::~Thread() +{ Kill(); } +//------------------------------------------------------------------------------ + + } +} + +#endif diff --git a/include/platform/thread/thread_event.cpp b/include/platform/thread/thread_event.cpp new file mode 100644 index 0000000..d81c90a --- /dev/null +++ b/include/platform/thread/thread_event.cpp @@ -0,0 +1,120 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "thread/thread_event.h" + #include "time/ntime.h" + + using namespace GS; + using namespace GS::Threading; + + +#if __PLATFORM_WINDOWS__ + + #define WIN32_LEAN_AND_MEAN + #include + +//------------------------------------------------------------------------------ +void Event::Wait(Time *t) +{ WaitForSingleObject((HANDLE)event, t ? DWORD(t->toMs()) : INFINITE); } +void Event::Trigger() +{ SetEvent((HANDLE)event); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Event::Event() +{ event = (void *)CreateEvent(NULL, false, false, NULL); } +Event::~Event() +{ if (event) CloseHandle(event); } +//------------------------------------------------------------------------------ + +#elif __PLATFORM_EMSCRIPTEN__ + +//------------------------------------------------------------------------------ +void Event::Wait(Time *t) +{} +void Event::Trigger() +{} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Event::Event() +{} +Event::~Event() +{} +//------------------------------------------------------------------------------ + +#elif __PLATFORM_POSIX__ + + #include + #include + #include + #include + +struct pthread_event +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + bool triggered; +}; + +//------------------------------------------------------------------------------ +void Event::Wait(Time *t) +{ + pthread_event *ev = (pthread_event *)event; + + timespec time; + + if (t) + { + timeval ctime; + gettimeofday(&ctime, NULL); + time.tv_sec = t->getSec() + ctime.tv_sec; + time.tv_nsec = t->getNanoSec() + ctime.tv_usec * 1000; + } + + pthread_mutex_lock(&ev->mutex); + while (!ev->triggered) + { + if (!t) + pthread_cond_wait(&ev->cond, &ev->mutex); + else + if (pthread_cond_timedwait(&ev->cond, &ev->mutex, &time) == ETIMEDOUT) + break; + } + ev->triggered = false; + pthread_mutex_unlock(&ev->mutex); +} +void Event::Trigger() +{ + pthread_event *ev = (pthread_event *)event; + + pthread_mutex_lock(&ev->mutex); + ev->triggered = true; + pthread_cond_signal(&ev->cond); + pthread_mutex_unlock(&ev->mutex); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Event::Event() +{ + pthread_event *ev = new pthread_event; + event = (void *)ev; + + pthread_mutex_init(&ev->mutex, 0); + pthread_cond_init(&ev->cond, 0); + ev->triggered = false; +} +Event::~Event() +{ + pthread_event *ev = (pthread_event *)event; + pthread_mutex_destroy(&ev->mutex); + pthread_cond_destroy(&ev->cond); + delete ev; +} +//------------------------------------------------------------------------------ + +#endif diff --git a/include/platform/time/ntime.cpp b/include/platform/time/ntime.cpp new file mode 100644 index 0000000..2cc1ce7 --- /dev/null +++ b/include/platform/time/ntime.cpp @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include + #include + #include "time/ntime.h" + + using namespace GS; + + Time Time::Inf(std::numeric_limits ::max()); + + +//------------------------------------------------------------------------------ +void Time::operator += (const Time &b) +{ + sec += b.sec; + nsec += b.nsec; + Normalize(); +} +void Time::operator -= (const Time &b) +{ + sec -= b.sec; + nsec -= b.nsec; + Normalize(); +} +Time Time::operator + (const Time &b) const +{ return Time(sec + b.sec, nsec + b.nsec); } +Time Time::operator - (const Time &b) const +{ return Time(sec - b.sec, nsec - b.nsec); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +bool Time::operator == (const Time &b) const +{ return (sec == b.sec) && (nsec == b.nsec); } +bool Time::operator != (const Time &b) const +{ return (sec != b.sec) || (nsec != b.nsec); } +bool Time::operator > (const Time &b) const +{ return (sec > b.sec) || ((sec == b.sec) && (nsec > b.nsec)); } +bool Time::operator < (const Time &b) const +{ return (sec < b.sec) || ((sec == b.sec) && (nsec < b.nsec)); } +bool Time::operator >= (const Time &b) const +{ return (*this > b) || (*this == b); } +bool Time::operator <= (const Time &b) const +{ return (*this < b) || (*this == b); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +float Time::toDay() const +{ return toHour() / 24.f; } +float Time::toHour() const +{ return toMin() / 60.f; } +float Time::toMin() const +{ return toSec() / 60.f; } +float Time::toSec() const +{ return sec + nsec / 1000000000.f; } +float Time::toMs() const +{ return sec * 1000.f + nsec / 1000000.f; } +float Time::toNs() const +{ return sec * 1000000000.f + nsec; } +String Time::toString() const +{ return String::Format("%02d:%02d:%02d:%03d", int(toHour()) % 60, int(toMin()) % 60, int(toSec()) % 60, int(toMs()) % 1000); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Time::setSec(int s) +{ sec = s; nsec = 0; } +void Time::setSec(float s) +{ + double integral, fractional = modf(s, &integral); + sec = int(integral); nsec = int(fractional * 1000000000.0); + Normalize(); +} +void Time::setMs(int m) +{ + sec = m / 1000; nsec = (m - sec * 1000) * 1000000; +} +void Time::setNs(int n) +{ + sec = 0; nsec = n; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Time Time::fromSec(float s) +{ + double integral, fractional = modf(s, &integral); + return Time(int(integral), int(fractional * 1000000000.0)); +} +Time Time::fromSec(int s) +{ return Time(s); } +Time Time::fromMs(int m) +{ return Time(0, m * 1000000); } +Time Time::fromNs(int n) +{ return Time(0, n); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +Time Time::Abs() const +{ return Time(Types::Abs(sec), nsec); } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void Time::Normalize() +{ + for (; nsec >= 1000000000; nsec -= 1000000000) + sec++; + for (; nsec < 0; nsec += 1000000000) + sec--; +} +Time Time::Normalized() const +{ return Time(sec, nsec); } +//------------------------------------------------------------------------------ + +Time::Time(int s, int n) +{ + sec = s; nsec = n; + Normalize(); +} +Time::Time(float s) +{ setSec(s); } +Time::Time(int s) +{ sec = s; nsec = 0; } diff --git a/include/platform/unit/nunit.cpp b/include/platform/unit/nunit.cpp new file mode 100644 index 0000000..f3b5e83 --- /dev/null +++ b/include/platform/unit/nunit.cpp @@ -0,0 +1,15 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +----------------------------------------------------------------------------- */ + + + #include "unit/nunit.h" + + +//------------------------------------------------------------------------------ +size_t GS::Units::KB(const size_t v) +{ return v * 1024; } +size_t GS::Units::MB(const size_t v) +{ return v * 1024 * 1024; } +//------------------------------------------------------------------------------ diff --git a/include/platform/video/video_mode.cpp b/include/platform/video/video_mode.cpp new file mode 100644 index 0000000..d4fb384 --- /dev/null +++ b/include/platform/video/video_mode.cpp @@ -0,0 +1,62 @@ +/* ----------------------------------------------------------------------------- + GSFramework + Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. +------------------------------------------------------------------------------*/ + + + #include "video/video_mode.h" + + using namespace nVideoMode; + + +//------------------------------------------------------------------------------ +Mode nVideoMode::mode_desc[NameLast] = +{ + { "CGA", 320, 200, 32, true }, + { "QVGA", 320, 240, 32, true }, + { "WQVGA", 480, 272, 32, true }, + { "VGA", 640, 480, 32, true }, + { "SVGA", 800, 600, 32, true }, + + { "XGA", 1024, 768, 32, true }, + { "XGAPlus", 1152, 864, 32, true }, + + { "HD", 1366, 768, 32, true }, + { "WXGA_922K", 1280, 720, 32, false }, + { "WXGA_1024K", 1280, 800, 32, true }, + { "HDPlus", 1600, 900, 32, true }, + { "SXGA", 1280, 1024, 32, true }, + { "WXGAPlus", 1440, 900, 32, true }, + + { "UXGA", 1600, 1200, 32, true }, + { "WSXGAPlus", 1680, 1050, 32, true }, + { "FullHD", 1920, 1080, 32, false }, + { "WUXGA", 1920, 1200, 32, true }, + + { "QXGA", 2048, 1536, 32, true }, + { "QWXGA", 2048, 1152, 32, true }, + { "WQHD", 2560, 1440, 32, true }, + { "WQXGA", 2560, 1600, 32, true } +}; +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +AspectRatio nVideoMode::GetModeAspectRatio(const Mode &mode) +{ + if (((mode.width * 3) / 4) == mode.height) + return AR_4_3; + if (((mode.width * 9) / 16) == mode.height) + return AR_16_9; + if (((mode.width * 10) / 16) == mode.height) + return AR_16_10; + + return AR_Unknown; +} +Mode *nVideoMode::GetMode(uint w, uint h) +{ + for (uint n = 0; n < NameLast; ++n) + if ((mode_desc[n].width == w) && (mode_desc[n].height == h)) + return &mode_desc[n]; + return NULL; +} +//------------------------------------------------------------------------------ diff --git a/lib/engine.lib b/lib/engine.lib index d5756f8..9233fc6 100644 Binary files a/lib/engine.lib and b/lib/engine.lib differ diff --git a/lib/extern.lib b/lib/extern.lib index af8b30f..9c818f6 100644 Binary files a/lib/extern.lib and b/lib/extern.lib differ diff --git a/lib/framework.lib b/lib/framework.lib index 51adb58..80beada 100644 Binary files a/lib/framework.lib and b/lib/framework.lib differ diff --git a/lib/modules.lib b/lib/modules.lib index 500eacb..a78c621 100644 Binary files a/lib/modules.lib and b/lib/modules.lib differ diff --git a/lib/opencv_ts300.lib b/lib/opencv_ts300.lib deleted file mode 100644 index e27f46c..0000000 Binary files a/lib/opencv_ts300.lib and /dev/null differ diff --git a/lib/opencv_world300.lib b/lib/opencv_world300.lib deleted file mode 100644 index c3368cd..0000000 Binary files a/lib/opencv_world300.lib and /dev/null differ diff --git a/lib/opencv_world345.lib b/lib/opencv_world345.lib new file mode 100644 index 0000000..4ce311f Binary files /dev/null and b/lib/opencv_world345.lib differ diff --git a/lib/platform.lib b/lib/platform.lib index 20f839f..41b0650 100644 Binary files a/lib/platform.lib and b/lib/platform.lib differ diff --git a/source/webcam.cpp b/source/webcam.cpp index 2ce430e..4c97e3b 100644 --- a/source/webcam.cpp +++ b/source/webcam.cpp @@ -188,8 +188,10 @@ std::vector DisplayDeviceInformation(IEnumMoniker *pEnum) pPropBag->Release(); pMoniker->Release(); ++counter_device; - } + __LOG_CAM__<<"counter_device "< id_devices; HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + bool mustUninitialize = true; + __LOG_CAM__ << "A\n"; + + if (hr == RPC_E_CHANGED_MODE){ + hr = S_OK; + mustUninitialize = false; + } + if (SUCCEEDED(hr)) { + __LOG_CAM__ << "B\n"; IEnumMoniker *pEnum; hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum); if (SUCCEEDED(hr)) { + __LOG_CAM__ << "C\n"; id_devices = DisplayDeviceInformation(pEnum); pEnum->Release(); } - CoUninitialize(); + if(mustUninitialize) + CoUninitialize(); } + __LOG_CAM__ << "id_devices size: "<open(id_devices[i]); + __LOG_CAM__<<"E\n"; + InputVideo->open(id_devices[i],CAP_DSHOW); + __LOG_CAM__<<"F\n"; if(InputVideo->isOpened()){ + __LOG_CAM__<<"G\n"; device_id = id_devices[i]; break; } diff --git a/source/webcam_binding.cpp b/source/webcam_binding.cpp index bfc12dd..8f371ec 100644 --- a/source/webcam_binding.cpp +++ b/source/webcam_binding.cpp @@ -34,7 +34,7 @@ SQInteger WebcamSetFrame(HSQUIRRELVM vm) __SQ_GETSTRING(path) __SQ_GETEND - __SQ_RETURNINT((int)(w->SetFrame(c,path))) + __SQ_RETURNINT((SQInteger)(w->SetFrame(c,path))) } //----------------------------------------------