// 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "face.h"
#include "mesh.h"
#include "c3ga_util.h"
#include "surface_point.h"
#include "texture.h"
#include "../shared.src/mt19937-2.h"
#include "../shared.src/constants.h"
using namespace c3ga;
face::face() : m_u2(0.0f), m_v2(0.0f), m_w2(0.0f),
m_uv(0.0f), m_vw(0.0f), m_wu(0.0f),
m_u_w2(0.0f)
{
for (int i = 0; i < 3; i++)
m_vtx_idx[i] = 0;
m_uv_dir[0][0] = m_uv_dir[0][1] =
m_uv_dir[1][0] = m_uv_dir[1][1] = 0.0;
}
face::face(const int vtx_idx[3]) : m_u2(0.0f), m_v2(0.0f), m_w2(0.0f),
m_uv(0.0f), m_vw(0.0f), m_wu(0.0f),
m_u_w2(0.0f)
{
for (int i = 0; i < 3; i++)
m_vtx_idx[i] = vtx_idx[i];
m_uv_dir[0][0] = m_uv_dir[0][1] =
m_uv_dir[1][0] = m_uv_dir[1][1] = 0.0;
}
face::face(const face &f) : m_u2(f.m_u2), m_v2(f.m_v2), m_w2(f.m_w2),
m_uv(f.m_uv), m_vw(f.m_vw), m_wu(f.m_wu),
m_u_w2(f.m_u_w2) , m_pl(f.m_pl)
{
for (int i = 0; i < 3; i++) {
m_vtx_idx[i] = f.m_vtx_idx[i];
m_edge_line[i] = f.m_edge_line[i];
}
m_uv_dir[0][0] = f.m_uv_dir[0][0];
m_uv_dir[0][1] = f.m_uv_dir[0][1];
m_uv_dir[1][0] = f.m_uv_dir[1][0];
m_uv_dir[1][1] = f.m_uv_dir[1][1];
}
face::~face() {
}
face &face::operator=(const face &f) {
if (this != &f) {
for (int i = 0; i < 3; i++) {
m_vtx_idx[i] = f.m_vtx_idx[i];
m_edge_line[i] = f.m_edge_line[i];
}
m_u2 = f.m_u2,
m_v2 = f.m_v2;
m_w2 = f.m_w2;
m_uv = f.m_uv;
m_vw = f.m_vw;
m_wu = f.m_wu;
m_u_w2 = f.m_u_w2;
m_uv_dir[0][0] = f.m_uv_dir[0][0];
m_uv_dir[0][1] = f.m_uv_dir[0][1];
m_uv_dir[1][0] = f.m_uv_dir[1][0];
m_uv_dir[1][1] = f.m_uv_dir[1][1];
m_pl = f.m_pl;
}
return *this;
}
void face::precompute_constants(const mesh &m) {
// compute lines along the edges of the face
for (int i = 0; i < 3; i++)
m_edge_line[i] = _line(get_vtx(i, m).get_pt() ^ get_vtx((i + 1) % 3, m).get_pt() ^ ni);
// don't make them unit, this will mess up the interpolation!
//m_edge_line[i] = unit_r(get_vtx(i, m).get_pt() ^ get_vtx((i + 1) % 3, m).get_pt() ^ c3ga::ni);
// compute the plane of the facew
m_pl = _plane(unit_r(get_vtx(0, m).get_pt() ^ get_vtx(1, m).get_pt() ^ get_vtx(2, m).get_pt() ^ ni));
/*
Compute the direction (dual plane through the origin) of each of the
three m_edge_line variables are lines along the face.
*/
vectorE3GA u = _vectorE3GA(nino << m_edge_line[0]);
vectorE3GA v = _vectorE3GA(nino << m_edge_line[1]);
vectorE3GA w = _vectorE3GA(nino << m_edge_line[2]);
// compute interpolation constants
m_u2 = _Float(u % u);
m_v2 = _Float(v % v);
m_w2 = _Float(w % w);
m_uv = _Float(u % v);
m_vw = _Float(v % w);
m_wu = _Float(w % u);
m_u_w2 = _Float((u^w) % (u^w));
}
bool face::uses_vtx_idx(int vtx_idx) const {
return ((vtx_idx == get_vtx_idx(0)) ||
(vtx_idx == get_vtx_idx(1)) ||
(vtx_idx == get_vtx_idx(2)));
}
// todo: make better use of GA in this problem . . . !!!!
void face::compute_local_texture_basis(const mesh &m) {
// Compute 'a' and 'b', Euclidean vectors in
// texture space along two of the edges of the polygon
vectorE2GA a = _vectorE2GA(no << (m.get_vertex(m_vtx_idx[1]).get_tex_pt() - m.get_vertex(m_vtx_idx[0]).get_tex_pt()));
vectorE2GA b = _vectorE2GA(no << (m.get_vertex(m_vtx_idx[2]).get_tex_pt() - m.get_vertex(m_vtx_idx[0]).get_tex_pt()));
mv::Float a1 = _Float(a & e1);
mv::Float a2 = _Float(a & e2);
mv::Float b1 = _Float(b & e1);
mv::Float b2 = _Float(b & e2);
mv::Float alpha1, beta1, alpha2, beta2;
if ((b2 * a1 - b1 * a2) == 0.0f) { // degenerate triangle; spans no area in texture space
alpha1 = alpha2 = beta1 = beta2 = 0.0;
}
else {
// invert matrix . . .
beta1 = a2 / (b1 * a2 - b2 * a1);
alpha1 = (a2 == 0.0f) ? 1.0f / a1 : -beta1 * b2 / a2;
beta2 = a1 / (b2 * a1 - b1 * a2);
alpha2 = (a1 == 0.0f) ? 1.0f / a2 : -beta2 * b1 / a1;
}
m_uv_dir[0][0] = alpha1;
m_uv_dir[0][1] = beta1;
m_uv_dir[1][0] = alpha2;
m_uv_dir[1][1] = beta2;
}
bool face::find_intersection(const dualPlane &ray_dual_plane, const dualLine &ray_dual_line, surface_point &spt, bool find_closest) const {
// check if line intersects triangle:
mv::Float side1 = _Float(no % (ray_dual_line << get_edge_line(0)));
mv::Float side2 = _Float(no % (ray_dual_line << get_edge_line(1)));
mv::Float side3 = _Float(no % (ray_dual_line << get_edge_line(2)));
int sd;
// check if face was intersected, and if so, from what side did the ray come:
if ((side1 > 0.0) && (side2 > 0.0) && (side3 > 0.0)) {
sd = 1; // front side
}
else if ((side1 < 0.0) && (side2 < 0.0) && (side3 < 0.0)) {
sd = -1; // back side
}
else if ((side1 >= 0.0) && (side2 >= 0.0) && (side3 >= 0.0)) {
sd = 1; // front side (barely touching)
}
else return false;
// compute the intersection point & distance to ray start
normalizedFlatPoint I = _normalizedFlatPoint((ray_dual_line << get_pl()) *
(1.0f / _float((ray_dual_line << get_pl()) % (noni))));
mv::Float d = -_Float((ray_dual_plane << I) % no);
if (d < RAY_INTERSECTION_MIN_DISTANCE) return false;
// if no precise info required, we're done:
if (!find_closest) {
spt.set_valid(true);
spt.set_distance_local(d);
return true;
}
else {
if ((!spt.get_valid()) ||
(spt.get_valid() && (d < spt.get_distance_local()))) {
spt.set_valid(true);
spt.set_distance_local(d);
spt.set_pt_local(I);
spt.set_side(sd);
return true;
}
else return false;
}
}
void face::compute_interpolation_weights(const normalizedFlatPoint &pt, mv::Float iw[3], const vertex &vtx0) const {
mv::Float u_d, v_d, w_d;
// compute u, v, w as Euclidean vectors:
vectorE3GA u = _vectorE3GA(noni << get_edge_line(0));
vectorE3GA v = _vectorE3GA(noni << get_edge_line(1));
vectorE3GA w = _vectorE3GA(noni << get_edge_line(2));
// compute local position of point 'pt', as a Euclidean vector
vectorE3GA d = _vectorE3GA(no<<(pt - (vtx0.get_pt() ^ ni)));
// compute inner product of d with each edge direction
u_d = _float(u & d);
v_d = _float(v & d);
w_d = _float(w & d);
// compute the weights for the three vertices :
iw[0] = -(m_v2 * u_d - m_uv * v_d) / m_u_w2 + 1.0f;
iw[1] = -(m_w2 * v_d - m_vw * w_d) / m_u_w2;
iw[2] = -(m_u2 * w_d - m_wu * u_d) / m_u_w2;
}
void face::compute_surface_point_details(surface_point &spt, const model &m) const {
// get the three vertices of this face
const vertex &vtx0(get_vtx(0, *m.get_mesh()));
const vertex &vtx1(get_vtx(1, *m.get_mesh()));
const vertex &vtx2(get_vtx(2, *m.get_mesh()));
// compute the interpolation weights
mv::Float iw[3]; // iw = interpolation weights
compute_interpolation_weights(spt.get_pt_local(), iw, vtx0);
// compute the interpolated texture point
spt.set_tex_pt(_normalizedFlatPoint2D(iw[0] * vtx0.get_tex_pt() + iw[1] * vtx1.get_tex_pt() + iw[2] * vtx2.get_tex_pt()));
// compute interpolated, normalized surface normal
freeBivector att = _freeBivector(unit_e(iw[0] * vtx0.get_att() + iw[1] * vtx1.get_att() + iw[2] * vtx2.get_att()));
// apply bumpmap if it is enabled:
// todo: clean up GA usage in here . . .
if (m.get_bump_map_texture().enabled()) {
float bump[3];
m.get_bump_map_texture().get_bump_map_value(spt.get_tex_pt(), bump);
// construct attitudes for from the edge lines 0 & 2
freeBivector att_edge_0 = _freeBivector(dual(get_edge_line(0)) ^ ni);
freeBivector att_edge_2 = _freeBivector(dual(get_edge_line(2)) ^ ni);
// transform bumpmap from the 2D 'bumpmap frame' to the local 3D frame
freeBivector bump_att = _freeBivector(m.get_bumpyness() *
((m_uv_dir[0][1] * bump[0] + m_uv_dir[1][1] * bump[1]) * att_edge_2 -
(m_uv_dir[0][0] * bump[0] + m_uv_dir[1][0] * bump[1]) * att_edge_0));
// set surface attitude in model frame, with bump added
spt.set_att_local(_freeBivector(unit_e(att + bump_att)));
}
else {
// set surface attitude in model frame
spt.set_att_local(att);
}
}
// leave this comment for online browsing anchors