// 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.
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <GL/gl.h>
#include "c3ga_util.h"
#include "model.h"
#include "mesh.h"
#include "ray.h"
#include "surface_point.h"
#include "../shared.src/string_util.h"
#include "../shared.src/fltk_stuff.h"
using namespace c3ga;
model::model() : locator(), m_mesh(NULL),
m_bumpyness(0.0),
m_shininess(1.0), m_direct_lighting_factor(0.0),
m_reflection_factor(0.0), m_refraction_factor(0.0),
m_refractive_index(1.0) {
set_default_material_colors();
}
model::model(const model &m) : locator(m), // call superclass constructor
m_mesh(m.m_mesh),
m_ambient_color(m.m_ambient_color),
m_diffuse_color(m.m_diffuse_color),
m_specular_color(m.m_specular_color),
m_ambient_texture(m.m_ambient_texture),
m_diffuse_texture(m.m_diffuse_texture),
m_specular_texture(m.m_specular_texture),
m_shininess_texture(m.m_shininess_texture),
m_bump_map_texture(m.m_bump_map_texture),
m_shininess(m.m_shininess), m_bumpyness(m.m_bumpyness),
m_direct_lighting_factor(m.m_direct_lighting_factor),
m_reflection_factor(m.m_reflection_factor), m_refraction_factor(m.m_refraction_factor),
m_refractive_index(m.m_refractive_index) {
}
model::~model() {
}
model &model::operator=(const model &m) {
if (this != &m) {
locator::operator=(m); // call superclass copy op
m_mesh = m.m_mesh; // no need to clone the mesh too
m_ambient_color = m.m_ambient_color;
m_diffuse_color = m.m_diffuse_color;
m_specular_color = m.m_specular_color;
m_ambient_texture = m.m_ambient_texture;
m_diffuse_texture = m.m_diffuse_texture;
m_specular_texture = m.m_specular_texture;
m_shininess_texture = m.m_shininess_texture;
m_bump_map_texture = m.m_bump_map_texture;
m_bumpyness = m.m_bumpyness;
m_shininess = m.m_shininess;
m_direct_lighting_factor = m.m_direct_lighting_factor;
m_reflection_factor = m.m_reflection_factor;
m_refraction_factor = m.m_refraction_factor;
m_refractive_index = m.m_refractive_index;
}
return *this;
}
void model::set_ambient_color(const color &c) {
m_ambient_color = c;
}
void model::set_diffuse_color(const color &c) {
m_diffuse_color = c;
}
void model::set_specular_color(const color &c) {
m_specular_color = c;
}
void model::set_color(const std::string colorname, const color &c) {
// printf("Set color %s\n", colorname.c_str());
if ((colorname[0] == 'a') || (colorname[0] == 'A'))
set_ambient_color(c);
else if ((colorname[0] == 'd') || (colorname[0] == 'D'))
set_diffuse_color(c);
else if ((colorname[0] == 's') || (colorname[0] == 'S'))
set_specular_color(c);
}
texture &model::get_texture(const std::string &texname) {
if ((texname[0] == 'a') || (texname[0] == 'A'))
return m_ambient_texture;
else if ((texname[0] == 'd') || (texname[0] == 'D'))
return m_diffuse_texture;
else if (((texname[0] == 's') || (texname[0] == 'S')) &&
((texname[1] == 'p') || (texname[1] == 'P')))
return m_specular_texture;
else if (((texname[0] == 's') || (texname[0] == 'S')) &&
((texname[1] == 'h') || (texname[1] == 'H')))
return m_shininess_texture;
else if ((texname[0] == 'b') || (texname[0] == 'B'))
return m_bump_map_texture;
else throw std::string("no texture " + texname);
}
const texture &model::get_texture(const std::string &texname) const {
return ((model*)this)->get_texture(texname);
}
bool model::set_texture(const std::string texname, const char *filename) {
// printf("Set texture %s -> %s\n", texname.c_str(), filename);
try {
texture &tex(get_texture(texname));
tex.load(filename);
tex.set_enabled(tex.valid());
return tex.valid();
}
catch (const std::string &) {
return false;
}
}
void model::set_texture_enabled(const std::string texname, bool e) {
// printf("Set texture %s enable -> %d\n", texname.c_str(), e);
try {
texture &tex(get_texture(texname));
tex.set_enabled(e);
}
catch (const std::string &) {
}
}
void model::set_shininess(mv::Float s) {
m_shininess = s;
}
void model::set_bumpyness(mv::Float b) {
m_bumpyness = b;
}
void model::set_direct_lighting_factor(mv::Float dlf) {
m_direct_lighting_factor = dlf;
}
void model::set_reflection_factor(mv::Float rf) {
m_reflection_factor = rf;
}
void model::set_refraction_factor(mv::Float rf) {
m_refraction_factor = rf;
}
void model::set_refractive_index(mv::Float ri) {
m_refractive_index = ri;
}
void model::set_mesh(const mesh *m) {
m_mesh = m;
}
void model::set_default_material_colors() {
m_ambient_color.set(0.5, 0.5, 0.5);
m_diffuse_color.set(0.5, 0.5, 0.5);
m_specular_color.set(0.5, 0.5, 0.5);
}
void model::to_OpenGL() const {
// multiply current GL matrix with transform
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
apply_transform_OpenGL();
// set material
get_ambient_color().glMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
get_diffuse_color().glMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
get_specular_color().glMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
color(0.0, 0.0, 0.0, 1.0).glMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat)get_shininess());
// get mesh:
const mesh *Mesh = get_mesh();
// draw all faces:
glBegin(GL_TRIANGLES);
for (int i = 0; i < Mesh->get_nb_faces(); i++) {
// get indices of the three faces:
for (int j = 0; j < 3; j++) {
// get index of vertex
int idx = Mesh->get_face(i).get_vtx_idx(j);
// call vertex to set normal and provide vertex:
Mesh->get_vertex(idx).glNormal();
Mesh->get_vertex(idx).glVertex();
}
}
glEnd();
// undo the transform:
glPopMatrix();
}
void model::set_ambient_texture(const std::string &filename) {
m_ambient_texture.load(filename);
}
void model::set_diffuse_texture(const std::string &filename) {
m_diffuse_texture.load(filename);
}
void model::set_specular_texture(const std::string &filename) {
m_specular_texture.load(filename);
}
void model::set_shininess_texture(const std::string &filename) {
m_shininess_texture.load(filename);
}
void model::set_bump_map_texture(const std::string &filename) {
m_bump_map_texture.load(filename);
}
std::string model::to_string(const std::string &basepath) const {
std::string result;
const int l = 1024;
char rel[l];
result += "model_begin\n";
// xf
result += "model_xf " + locator::to_string() + "\n";
// mesh
if (m_mesh) {
fl_filename_relative_to(rel, l, m_mesh->get_filename().c_str(), basepath.c_str());
result += std::string("mesh \"") + rel + "\"\n";
}
result += "model_ambient_color "+ m_ambient_color.to_string() + "\n";
result += "model_diffuse_color "+ m_diffuse_color.to_string() + "\n";
result += "model_specular_color "+ m_specular_color.to_string() + "\n";
result += "shininess " + ::to_string(get_shininess()) + "\n";
result += "bumpyness " + ::to_string(get_bumpyness()) + "\n";
const char *names[] = {
"ambient",
"diffuse",
"specular",
"shininess",
"bump_map",
NULL
};
for (int i = 0; names[i]; i++) {
if (get_texture(names[i]).get_filename().size()) {
fl_filename_relative_to(rel, l, get_texture(names[i]).get_filename().c_str(), basepath.c_str());
result += std::string(names[i]) + "_texture \"" + rel + "\"\n";
result += std::string(names[i]) + std::string("_texture_enabled ") + (get_texture(names[i]).enabled() ? "true" : "false") + "\n";
}
}
/*
// ambient
result += "ambient_texture \"" + m_ambient_texture.get_filename() + "\"\n";
result += std::string("ambient_texture_enabled ") + (m_ambient_texture.enabled() ? "true" : "false") + "\n";
// diffuse
result += "diffuse_texture \"" + m_diffuse_texture.get_filename() + "\"\n";
result += std::string("diffuse_texture_enabled ") + (m_diffuse_texture.enabled() ? "true" : "false") + "\n";
// specular
result += "specular_texture \"" + m_specular_texture.get_filename() + "\"\n";
result += std::string("specular_texture_enabled ") + (m_specular_texture.enabled() ? "true" : "false") + "\n";
// shininess
result += "shininess_texture \"" + m_shininess_texture.get_filename() + "\"\n";
result += std::string("shininess_texture_enabled ") + (m_shininess_texture.enabled() ? "true" : "false") + "\n";
// bumpmap
result += "bump_map_texture \"" + m_bump_map_texture.get_filename() + "\"\n";
result += std::string("bump_map_texture_enabled ") + (m_bump_map_texture.enabled() ? "true" : "false") + "\n";
*/
// factors & indices
result += "direct_lighting_factor " + ::to_string(m_direct_lighting_factor) + "\n";
result += "reflection_factor " + ::to_string(m_reflection_factor) + "\n";
result += "refraction_factor " + ::to_string(m_refraction_factor) + "\n";
result += "refractive_index " + ::to_string(m_refractive_index) + "\n";
result += "model_end\n";
return result;
}
sphere model::get_bounding_sphere() const {
return _sphere(-dual(get_xf() * get_mesh()->get_bounding_dual_sphere() * get_xfi()));
}
bool model::find_intersection(const ray &R, surface_point &spt, bool find_closest) const {
ray ray_local(_normalizedFlatPoint(apply_om(get_Mi(), R.get_position())),
_freeVector(apply_om(get_Mi(), R.get_direction())));
// transform global distance to local frame (apply xf twice, because distance is _squared_)
spt.set_distance_local(_Float(apply_om(get_Mi(), apply_om(get_Mi(), spt.get_distance() ^ ni)) & ni));
if (get_mesh()->find_intersection(ray_local, spt, find_closest)) {
spt.set_model(this);
// transform local distance to global frame (apply xf twice, because distance is _squared_)
spt.set_distance(_Float(apply_om(get_M(), apply_om(get_M(), (spt.get_distance_local() ^ ni))) & ni));
return true;
}
else return false;
}
void model::compute_surface_point_details(surface_point &spt) const {
// retrieve mesh, face, vertices
const mesh &m(*get_mesh());
const face &fc(m.get_face(spt.get_face_idx()));
// let the face compute what it can
fc.compute_surface_point_details(spt, *this); // NULL will later become pointer to bumpmap?
// ambient color / texture lookup
if (get_ambient_texture().enabled()) {
spt.set_ambient_color(get_ambient_color() * get_ambient_texture().get_color(spt.get_tex_pt()));
}
else spt.set_ambient_color(get_ambient_color());
// diffuse color / texture lookup
if (get_diffuse_texture().enabled())
spt.set_diffuse_color(get_diffuse_color() * get_diffuse_texture().get_color(spt.get_tex_pt()));
else spt.set_diffuse_color(get_diffuse_color());
// specular color / texture lookup
if (get_specular_texture().enabled())
spt.set_specular_color(get_specular_color() * get_specular_texture().get_color(spt.get_tex_pt()));
else spt.set_specular_color(get_specular_color());
if (get_shininess_texture().enabled()) {
spt.set_shininess(get_shininess() * get_shininess_texture().get_grayscale(spt.get_tex_pt()));
}
else spt.set_shininess(get_shininess());
// copy lighting factors
spt.set_direct_lighting_factor(get_direct_lighting_factor());
spt.set_reflection_factor(get_reflection_factor());
spt.set_refraction_factor(get_refraction_factor());
spt.set_refractive_index(get_refractive_index());
// transform intersection point and surface attitude into the global frame:
spt.set_pt(_normalizedFlatPoint(apply_om(get_M(), spt.get_pt_local())));
spt.set_att(_freeBivector(unit_e(apply_om(get_M(), spt.get_att_local()))));
}