/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. 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 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. 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 0 A.D. If not, see .
*/
/*
* Axis-aligned bounding box
*/
#include "precompiled.h"
#include "BoundingBoxAligned.h"
#include "lib/ogl.h"
#include
#include "graphics/Frustum.h"
#include "graphics/ShaderProgram.h"
#include "maths/BoundingBoxOriented.h"
#include "maths/Brush.h"
#include "maths/Matrix3D.h"
const CBoundingBoxAligned CBoundingBoxAligned::EMPTY = CBoundingBoxAligned(); // initializes to an empty bound
///////////////////////////////////////////////////////////////////////////////
// RayIntersect: intersect ray with this bound; return true
// if ray hits (and store entry and exit times), or false
// otherwise
// note: incoming ray direction must be normalised
bool CBoundingBoxAligned::RayIntersect(const CVector3D& origin,const CVector3D& dir,
float& tmin,float& tmax) const
{
float t1,t2;
float tnear,tfar;
if (dir[0]==0) {
if (origin[0]m_Data[1][0])
return false;
else {
tnear=(float) -FLT_MAX;
tfar=(float) FLT_MAX;
}
} else {
t1=(m_Data[0][0]-origin[0])/dir[0];
t2=(m_Data[1][0]-origin[0])/dir[0];
if (dir[0]<0) {
tnear = t2;
tfar = t1;
} else {
tnear = t1;
tfar = t2;
}
if (tfar<0)
return false;
}
if (dir[1]==0 && (origin[1]m_Data[1][1]))
return false;
else {
t1=(m_Data[0][1]-origin[1])/dir[1];
t2=(m_Data[1][1]-origin[1])/dir[1];
if (dir[1]<0) {
if (t2>tnear)
tnear = t2;
if (t1tnear)
tnear = t1;
if (t2tfar || tfar<0)
return false;
}
if (dir[2]==0 && (origin[2]m_Data[1][2]))
return false;
else {
t1=(m_Data[0][2]-origin[2])/dir[2];
t2=(m_Data[1][2]-origin[2])/dir[2];
if (dir[2]<0) {
if (t2>tnear)
tnear = t2;
if (t1tnear)
tnear = t1;
if (t2tfar || tfar<0)
return false;
}
tmin=tnear;
tmax=tfar;
return true;
}
///////////////////////////////////////////////////////////////////////////////
// SetEmpty: initialise this bound as empty
void CBoundingBoxAligned::SetEmpty()
{
m_Data[0]=CVector3D( FLT_MAX, FLT_MAX, FLT_MAX);
m_Data[1]=CVector3D(-FLT_MAX,-FLT_MAX,-FLT_MAX);
}
///////////////////////////////////////////////////////////////////////////////
// IsEmpty: tests whether this bound is empty
bool CBoundingBoxAligned::IsEmpty() const
{
return (m_Data[0].X == FLT_MAX && m_Data[0].Y == FLT_MAX && m_Data[0].Z == FLT_MAX
&& m_Data[1].X == -FLT_MAX && m_Data[1].Y == -FLT_MAX && m_Data[1].Z == -FLT_MAX);
}
///////////////////////////////////////////////////////////////////////////////
// Transform: transform this bound by given matrix; return transformed bound
// in 'result' parameter - slightly modified version of code in Graphic Gems
// (can't remember which one it was, though)
void CBoundingBoxAligned::Transform(const CMatrix3D& m, CBoundingBoxAligned& result) const
{
ENSURE(this!=&result);
for (int i=0;i<3;++i) {
// handle translation
result[0][i]=result[1][i]=m(i,3);
// Now find the extreme points by considering the product of the
// min and max with each component of matrix
for(int j=0;j<3;j++) {
float a=m(i,j)*m_Data[0][j];
float b=m(i,j)*m_Data[1][j];
if (a data;
#define ADD_FACE(x, y, z) \
ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \
ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z);
#define ADD_PT(u_, v_, x, y, z) \
STMT(int u = u_; int v = v_; \
data.push_back(u); \
data.push_back(v); \
data.push_back(m_Data[x].X); \
data.push_back(m_Data[y].Y); \
data.push_back(m_Data[z].Z); \
)
ADD_FACE(u, v, 0);
ADD_FACE(0, u, v);
ADD_FACE(u, 0, 1-v);
ADD_FACE(u, 1-v, 1);
ADD_FACE(1, u, 1-v);
ADD_FACE(u, 1, v);
#undef ADD_FACE
shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]);
shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]);
shader->AssertPointersBound();
glDrawArrays(GL_TRIANGLES, 0, 6*6);
}
void CBoundingBoxAligned::RenderOutline(CShaderProgramPtr& shader) const
{
std::vector data;
#define ADD_FACE(x, y, z) \
ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); \
ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \
ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); \
ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z);
#define ADD_PT(u_, v_, x, y, z) \
STMT(int u = u_; int v = v_; \
data.push_back(u); \
data.push_back(v); \
data.push_back(m_Data[x].X); \
data.push_back(m_Data[y].Y); \
data.push_back(m_Data[z].Z); \
)
ADD_FACE(u, v, 0);
ADD_FACE(0, u, v);
ADD_FACE(u, 0, 1-v);
ADD_FACE(u, 1-v, 1);
ADD_FACE(1, u, 1-v);
ADD_FACE(u, 1, v);
#undef ADD_FACE
shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]);
shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]);
shader->AssertPointersBound();
glDrawArrays(GL_LINES, 0, 6*8);
}