Files
vimix/GlmToolkit.cpp

268 lines
7.3 KiB
C++

/*
* This file is part of vimix - video live mixer
*
* **Copyright** (C) 2020-2021 Bruno Herbelin <bruno.herbelin@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
**/
#include <chrono>
#include <ctime>
#include <glm/gtc/matrix_access.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <glm/gtc/random.hpp>
#include "GlmToolkit.h"
glm::mat4 GlmToolkit::transform(glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale)
{
glm::mat4 View = glm::translate(glm::identity<glm::mat4>(), translation);
View = glm::rotate(View, rotation.x, glm::vec3(1.f, 0.f, 0.f));
View = glm::rotate(View, rotation.y, glm::vec3(0.f, 1.f, 0.f));
View = glm::rotate(View, rotation.z, glm::vec3(0.f, 0.f, 1.f));
glm::mat4 Model = glm::scale(glm::identity<glm::mat4>(), scale);
return View * Model;
}
void GlmToolkit::inverse_transform(glm::mat4 M, glm::vec3 &translation, glm::vec3 &rotation, glm::vec3 &scale)
{
// extract rotation from modelview
glm::mat4 ctm;
glm::vec3 rot(0.f);
glm::vec4 vec = M * glm::vec4(1.f, 0.f, 0.f, 0.f);
rot.z = glm::orientedAngle( glm::vec3(1.f, 0.f, 0.f), glm::normalize(glm::vec3(vec)), glm::vec3(0.f, 0.f, 1.f) );
rotation = rot;
// extract scaling
ctm = glm::rotate(glm::identity<glm::mat4>(), -rot.z, glm::vec3(0.f, 0.f, 1.f)) * M ;
vec = ctm * glm::vec4(1.f, 1.f, 0.f, 0.f);
scale = glm::vec3(vec.x, vec.y, 1.f);
// extract translation
vec = M * glm::vec4(0.f, 0.f, 0.f, 1.f);
translation = glm::vec3(vec);
}
//float rewrapAngleRestricted(float angle)
//// This function takes an angle in the range [-3*pi, 3*pi] and
//// wraps it to the range [-pi, pi].
//{
// if (angle > glm::pi<float>() )
// return angle - glm::two_pi<float>();
// else if (angle < - glm::pi<float>())
// return angle + glm::two_pi<float>();
// else
// return angle;
//}
// Freely inspired from https://github.com/alter-rokuz/glm-aabb.git
GlmToolkit::AxisAlignedBoundingBox::AxisAlignedBoundingBox() :
mMin(glm::vec3(1.f)), mMax(glm::vec3(-1.f))
{
}
GlmToolkit::AxisAlignedBoundingBox::AxisAlignedBoundingBox(const GlmToolkit::AxisAlignedBoundingBox &D) :
mMin(D.mMin), mMax(D.mMax)
{
}
void GlmToolkit::AxisAlignedBoundingBox::operator = (const GlmToolkit::AxisAlignedBoundingBox &D ) {
mMin = D.mMin;
mMax = D.mMax;
}
void GlmToolkit::AxisAlignedBoundingBox::extend(const glm::vec3& point)
{
if (isNull()) {
mMin = point;
mMax = point;
}
// general case
else {
mMin = glm::min(point, mMin);
mMax = glm::max(point, mMax);
}
}
void GlmToolkit::AxisAlignedBoundingBox::extend(std::vector<glm::vec3> points)
{
for (auto p = points.begin(); p != points.end(); ++p)
extend(*p);
}
void GlmToolkit::AxisAlignedBoundingBox::extend(const AxisAlignedBoundingBox& bb)
{
if (bb.isNull())
return;
if (isNull()) {
mMin = bb.mMin;
mMax = bb.mMax;
}
// general case
else {
mMin = glm::min(bb.mMin, mMin);
mMax = glm::max(bb.mMax, mMax);
}
}
glm::vec3 GlmToolkit::AxisAlignedBoundingBox::center(bool ignore_z) const
{
glm::vec3 ret = glm::vec3(0.f);
if (!isNull())
{
glm::vec3 d = mMax - mMin;
ret = mMin + (d * 0.5f);
}
if (ignore_z)
ret.z = 0.f;
return ret;
}
glm::vec3 GlmToolkit::AxisAlignedBoundingBox::scale(bool ignore_z) const
{
glm::vec3 ret = glm::vec3(1.f);
if (!isNull())
{
glm::vec3 d = mMax - mMin;
ret = d * 0.5f;
}
if (ignore_z)
ret.z = 1.f;
return ret;
}
bool GlmToolkit::AxisAlignedBoundingBox::intersect(const AxisAlignedBoundingBox& bb, bool ignore_z) const
{
if (isNull() || bb.isNull())
return false;
if ( (mMax.x < bb.mMin.x) || (mMin.x > bb.mMax.x) ||
(mMax.y < bb.mMin.y) || (mMin.y > bb.mMax.y) ||
( !ignore_z && ((mMax.z < bb.mMin.z) || (mMin.z > bb.mMax.z)) ) )
{
return false;
}
return true;
}
bool GlmToolkit::AxisAlignedBoundingBox::contains(const AxisAlignedBoundingBox& bb, bool ignore_z) const
{
if ( !intersect(bb, ignore_z))
return false;
if ( (mMin.x < bb.mMin.x) && (mMax.x > bb.mMax.x) &&
(mMin.y < bb.mMin.y) && (mMax.y > bb.mMax.y)
&& ( ignore_z || ((mMin.z < bb.mMin.z) && (mMax.z > bb.mMax.z)) )
)
{
return true;
}
return false;
}
bool GlmToolkit::AxisAlignedBoundingBox::contains(glm::vec3 point, bool ignore_z) const
{
if ( (mMax.x < point.x) || (mMin.x > point.x) ||
(mMax.y < point.y) || (mMin.y > point.y) ||
( !ignore_z && ((mMax.z < point.z) || (mMin.z > point.z)) ) )
return false;
return true;
}
GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::translated(glm::vec3 t) const
{
GlmToolkit::AxisAlignedBoundingBox bb;
bb = *this;
bb.mMin += t;
bb.mMax += t;
return bb;
}
GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::scaled(glm::vec3 s) const
{
GlmToolkit::AxisAlignedBoundingBox bb;
glm::vec3 vec;
// Apply scaling to min & max corners (can be inverted) and update bbox accordingly
vec = mMin * s;
bb.extend(vec);
vec = mMax * s;
bb.extend(vec);
return bb;
}
GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::transformed(glm::mat4 m) const
{
GlmToolkit::AxisAlignedBoundingBox bb;
glm::vec4 vec;
// Apply transform to all four corners (can be rotated) and update bbox accordingly
vec = m * glm::vec4(mMin.x, mMin.y, 0.f, 1.f);
bb.extend(glm::vec3(vec));
vec = m * glm::vec4(mMax.x, mMax.y, 0.f, 1.f);
bb.extend(glm::vec3(vec));
vec = m * glm::vec4(mMin.x, mMax.y, 0.f, 1.f);
bb.extend(glm::vec3(vec));
vec = m * glm::vec4(mMax.x, mMin.y, 0.f, 1.f);
bb.extend(glm::vec3(vec));
return bb;
}
bool GlmToolkit::operator< (const GlmToolkit::AxisAlignedBoundingBox& A, const GlmToolkit::AxisAlignedBoundingBox& B )
{
if (A.isNull())
return true;
if (B.isNull())
return false;
return ( glm::length2(A.mMax-A.mMin) < glm::length2(B.mMax-B.mMin) );
}
glm::ivec2 GlmToolkit::resolutionFromDescription(int aspectratio, int height)
{
int ar = glm::clamp(aspectratio, 0, 5);
int h = glm::clamp(height, 0, 8);
static glm::vec2 aspect_ratio_size[6] = { glm::vec2(1.f,1.f), glm::vec2(4.f,3.f), glm::vec2(3.f,2.f), glm::vec2(16.f,10.f), glm::vec2(16.f,9.f), glm::vec2(21.f,9.f) };
static float resolution_height[10] = { 16.f, 64.f, 200.f, 320.f, 480.f, 576.f, 720.f, 1080.f, 1440.f, 2160.f };
float width = aspect_ratio_size[ar].x * resolution_height[h] / aspect_ratio_size[ar].y;
glm::ivec2 res = glm::ivec2( width, resolution_height[h]);
return res;
}