Files
OpenSceneGraph/src/osgPlugins/lwo/Unit.cpp
2004-01-03 15:20:33 +00:00

243 lines
6.9 KiB
C++

/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Unit.h"
using namespace lwosg;
Unit::Unit()
: points_(new osg::Vec3Array),
normals_(new VertexMap),
weight_maps_(new VertexMap_map),
subpatch_weight_maps_(new VertexMap_map),
texture_maps_(new VertexMap_map),
rgb_maps_(new VertexMap_map),
rgba_maps_(new VertexMap_map),
displacement_maps_(new VertexMap_map),
spot_maps_(new VertexMap_map)
{
}
float Unit::angle_between_polygons(const Polygon &p1, const Polygon &p2) const
{
float a = p1.face_normal(points_.get()) * p2.face_normal(points_.get());
if (a > 1) return 0;
if (a < -1) return osg::PI;
return acosf(a);
}
void Unit::find_shared_polygons(int vertex_index, std::vector<int> &poly_indices)
{
int k = 0;
for (Polygon_list::const_iterator i=polygons_.begin(); i!=polygons_.end(); ++i, ++k) {
for (Polygon::Index_list::const_iterator j=i->indices().begin(); j!=i->indices().end(); ++j) {
if (*j == vertex_index) {
poly_indices.push_back(k);
break;
}
}
}
}
void Unit::generate_normals()
{
// create smoothed normals
for (Polygon_list::iterator i=polygons_.begin(); i!=polygons_.end(); ++i) {
osg::Vec4 N = osg::Vec4(i->face_normal(points_.get()), 0);
for (Polygon::Index_list::iterator j=i->indices().begin(); j!=i->indices().end(); ++j) {
(*normals_.get())[*j] += N;
}
}
// normalize smoothed normals
for (VertexMap::iterator ni=normals_->begin(); ni!=normals_->end(); ++ni) {
float l = ni->second.length();
if (l != 0) ni->second /= l;
}
// compute per-polygon normals
int pn = 0;
for (Polygon_list::iterator pi=polygons_.begin(); pi!=polygons_.end(); ++pi, ++pn) {
Polygon &poly = *pi;
float max_smoothing_angle = 0;
if (poly.has_surface()) {
max_smoothing_angle = poly.get_surface()->get_max_smoothing_angle();
}
for (Polygon::Index_list::const_iterator j=poly.indices().begin(); j!=poly.indices().end(); ++j) {
osg::Vec4 N(poly.face_normal(points_.get()), 0);
unsigned num_smoothed = 1;
const Index_list &shared_polys = shares_.at(*j);
for (unsigned k=0; k<shared_polys.size(); ++k) {
if (shared_polys[k] != pn) {
const Polygon &shared_poly = polygons_.at(shared_polys[k]);
float angle = angle_between_polygons(poly, shared_poly);
if (angle <= max_smoothing_angle && (poly.get_smoothing_group() == shared_poly.get_smoothing_group())) {
N += osg::Vec4(shared_poly.face_normal(points_.get()), 0);
++num_smoothed;
}
}
}
if (num_smoothed != shared_polys.size()) {
float l = N.length();
if (l != 0) N /= l;
(*poly.local_normals())[*j] = N;
}
}
}
}
void Unit::flatten_maps()
{
for (Polygon_list::iterator i=polygons().begin(); i!=polygons().end(); ++i) {
// flatten normal map
flatten_map(*i, i->local_normals(), normals_.get());
i->local_normals()->clear();
VertexMap_map::const_iterator j;
// flatten weight maps
while (!i->weight_maps()->empty()) {
VertexMap_map::iterator j = i->weight_maps()->begin();
flatten_map(*i, j->second.get(), weight_maps_->getOrCreate(j->first));
i->weight_maps()->erase(j);
}
// flatten texture maps
while (!i->texture_maps()->empty()) {
VertexMap_map::iterator j = i->texture_maps()->begin();
flatten_map(*i, j->second.get(), texture_maps_->getOrCreate(j->first));
i->texture_maps()->erase(j);
}
// flatten rgb maps
while (!i->rgb_maps()->empty()) {
VertexMap_map::iterator j = i->rgb_maps()->begin();
flatten_map(*i, j->second.get(), rgb_maps_->getOrCreate(j->first));
i->rgb_maps()->erase(j);
}
// flatten rgba maps
while (!i->rgba_maps()->empty()) {
VertexMap_map::iterator j = i->rgba_maps()->begin();
flatten_map(*i, j->second.get(), rgba_maps_->getOrCreate(j->first));
i->rgba_maps()->erase(j);
}
}
}
void Unit::flatten_map(Polygon &poly, const VertexMap *local_map, VertexMap *global_map)
{
int j = 0;
for (Polygon::Index_list::iterator i=poly.indices().begin(); i!=poly.indices().end(); ++i, ++j) {
// try original vertex index
VertexMap::const_iterator k = local_map->find(*i);
// try duplicated vertex index
if (k == local_map->end()) {
k = local_map->find(poly.dup_vertices()[j]);
}
if (k != local_map->end()) {
// duplication may be needed!
if (poly.dup_vertices()[j] == 0) {
// duplicate point
points_->push_back(points_->at(*i));
int new_index = static_cast<int>(points_->size())-1;
// duplicate normal
(*normals_.get())[new_index] = (*normals_.get())[*i];
// duplicate share
shares_.push_back(shares_.at(*i));
VertexMap_map::iterator vm;
// duplicate weights
for (vm=weight_maps()->begin(); vm!=weight_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate subpatch weights
for (vm=subpatch_weight_maps()->begin(); vm!=subpatch_weight_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate texture UVs
for (vm=texture_maps()->begin(); vm!=texture_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate RGBs
for (vm=rgb_maps()->begin(); vm!=rgb_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate RGBAs
for (vm=rgba_maps()->begin(); vm!=rgba_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate displacements
for (vm=displacement_maps()->begin(); vm!=displacement_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate spots
for (vm=spot_maps()->begin(); vm!=spot_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// update vertex index
poly.dup_vertices()[j] = *i;
*i = new_index;
}
(*global_map)[*i] = k->second;
}
}
}
void Unit::compute_vertex_remapping(const Surface *surf, Index_list &remap) const
{
remap.assign(points_->size(), -1);
for (Polygon_list::const_iterator i=polygons_.begin(); i!=polygons_.end(); ++i) {
if (i->get_surface() == surf) {
for (Polygon::Index_list::const_iterator j=i->indices().begin(); j!=i->indices().end(); ++j) {
remap[*j] = *j;
}
}
}
int offset = 0;
for (Index_list::iterator j=remap.begin(); j!=remap.end(); ++j) {
if (*j == -1) {
++offset;
} else {
*j -= offset;
}
}
}