Files
OpenSceneGraph/src/osgPlugins/lwo/Lwo2Layer.cpp

443 lines
13 KiB
C++

/*
* Lightwave Object version 2 loader for Open Scene Graph
* Version 2 introduced in Lightwave v6.0
*
* Copyright (C) 2002 Pavel Moloshtan <pasha@moloshtan.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
* real-time rendering of large 3D photo-realistic models.
* The OSG homepage is http://www.openscenegraph.org/
*/
#include "Lwo2Layer.h"
Lwo2Layer::Lwo2Layer():
_number(0),
_flags(0),
_parent(0)
{
}
Lwo2Layer::~Lwo2Layer()
{
}
void
Lwo2Layer::notify(NotifySeverity severity)
{
osg::notify(severity) << "Current layer: " << _number << endl;
osg::notify(severity) << " flags \t" << _flags << endl;
osg::notify(severity) << " pivot \t" << _pivot << endl;
osg::notify(severity) << " name: \t'" << _name.c_str() << "'" << endl;
osg::notify(severity) << " parent:\t" << _parent << endl;
// points
osg::notify(severity) << " points:\t" << _points.size() << endl;
osg::notify(severity) << "\tcoord\t\t\t\ttexcoord" << endl;
osg::notify(severity) << "\t=====\t\t\t\t========" << endl;
IteratorPoint itr;
for (itr = _points.begin(); itr != _points.end(); itr++)
{
osg::notify(severity) << " \t" << (*itr).coord << "\t\t" << (*itr).texcoord << endl;
}
// polygons
osg::notify(severity) << " polygons:\t" << _polygons.size() << endl;
osg::notify(severity) << "\tcoord\t\t\t\ttexcoord" << endl;
osg::notify(severity) << "\t=====\t\t\t\t========" << endl;
IteratorPolygonsList polygon_iterator;
int polygon_index = 0;
for (polygon_iterator = _polygons.begin(); polygon_iterator != _polygons.end(); polygon_iterator++, polygon_index++)
{
osg::notify(severity) << " \t" << polygon_index << " ("<< (*polygon_iterator).size() << " vertexes" << "):" << endl;
for (itr = (*polygon_iterator).begin(); itr != (*polygon_iterator).end(); itr++)
{
osg::notify(severity) << " \t" << (*itr).coord << "\t\t" << (*itr).texcoord << endl;
}
osg::notify(severity) << endl;
}
// polygons tags
osg::notify(severity) << " polygons tags:\t" << _polygons_tag.size() << endl;
IteratorShort short_itr;
for (short_itr = _polygons_tag.begin(); short_itr != _polygons_tag.end(); short_itr++)
{
osg::notify(severity) << "\t" << (*short_itr) << endl;
}
}
void
Lwo2Layer::GenerateGeode( Geode& geode, short tags_count, DrawableToTagMapping& tag_mapping)
{
notify(DEBUG_INFO);
// variable used to track using textures
bool have_texture_coords;
// create diffirent geomerty for each tag
for (short current_tag = 0; current_tag < tags_count; current_tag++)
{
have_texture_coords = false;
// new geometry
ref_ptr<Geometry> geometry = osgNew Geometry;
// create coords array
ref_ptr<Vec3Array> coords = osgNew Vec3Array;
// create texture array
ref_ptr<Vec2Array> texcoords = osgNew Vec2Array;
// selecting polygons for current layer only
int polygon_index = 0;
PolygonsList polygons;
for (IteratorPolygonsList polygon_iterator = _polygons.begin(); polygon_iterator != _polygons.end(); polygon_iterator++, polygon_index++)
{
// *polygon_iterator it's a PolygonsList
// polygons of current tag only
if (_polygons_tag[polygon_index] == current_tag)
{
// reset point_index member for later comparing poins data
PointsList points_list = *polygon_iterator;
for (unsigned int i = 0; i < points_list.size(); i++)
{
points_list[i].point_index = 0;
}
polygons.push_back(*polygon_iterator);
}
}
// find and compose triangle fans
PolygonsList triangle_fans;
_find_triangle_fans(polygons, triangle_fans);
// find and compose triangle strips
PolygonsList triangle_strips;
_find_triangle_strips(polygons, triangle_strips);
// polygons of current layer
polygon_index = 0;
for (IteratorPolygonsList polygon_iterator = polygons.begin(); polygon_iterator != polygons.end(); polygon_iterator++, polygon_index++)
{
if ((*polygon_iterator)[0].point_index != -1)
{
// all points of polygon
for (IteratorPoint itr = (*polygon_iterator).begin(); itr != (*polygon_iterator).end(); itr++)
{
// *itr - it's a PointData
// polygons data
(*coords).push_back((*itr).coord);
(*texcoords).push_back((*itr).texcoord);
if ((*itr).texcoord.x() != -1.0f || (*itr).texcoord.y() != -1.0f)
{
have_texture_coords = true;
}
}
unsigned int points_start = (*coords).size() - (*polygon_iterator).size();
unsigned int points_count = (*polygon_iterator).size();
if (points_count == 3)
{
geometry->addPrimitiveSet(osgNew DrawArrays(PrimitiveSet::TRIANGLES, points_start, points_count));
}
else if (points_count == 4)
{
geometry->addPrimitiveSet(osgNew DrawArrays(PrimitiveSet::QUADS, points_start, points_count));
}
else
{
geometry->addPrimitiveSet(osgNew DrawArrays(PrimitiveSet::POLYGON, points_start, points_count));
}
}
}
// triangle fans of current layer
polygon_index = 0;
for (IteratorPolygonsList polygon_iterator = triangle_fans.begin(); polygon_iterator != triangle_fans.end(); polygon_iterator++, polygon_index++)
{
// all points of polygon
for (IteratorPoint itr = (*polygon_iterator).begin(); itr != (*polygon_iterator).end(); itr++)
{
// *itr - it's a PointData
// polygons data
(*coords).push_back((*itr).coord);
(*texcoords).push_back((*itr).texcoord);
if ((*itr).texcoord.x() != -1.0f || (*itr).texcoord.y() != -1.0f)
{
have_texture_coords = true;
}
}
unsigned int points_start = (*coords).size() - (*polygon_iterator).size();
unsigned int points_count = (*polygon_iterator).size();
geometry->addPrimitiveSet(osgNew DrawArrays(PrimitiveSet::TRIANGLE_FAN, points_start, points_count));
}
// triangle strips of current layer
polygon_index = 0;
for (IteratorPolygonsList polygon_iterator = triangle_strips.begin(); polygon_iterator != triangle_strips.end(); polygon_iterator++, polygon_index++)
{
// all points of polygon
for (IteratorPoint itr = (*polygon_iterator).begin(); itr != (*polygon_iterator).end(); itr++)
{
// *itr - it's a PointData
// polygons data
(*coords).push_back((*itr).coord);
(*texcoords).push_back((*itr).texcoord);
if ((*itr).texcoord.x() != -1.0f || (*itr).texcoord.y() != -1.0f)
{
have_texture_coords = true;
}
}
unsigned int points_start = (*coords).size() - (*polygon_iterator).size();
unsigned int points_count = (*polygon_iterator).size();
geometry->addPrimitiveSet(osgNew DrawArrays(PrimitiveSet::TRIANGLE_STRIP, points_start, points_count));
}
// add geometry if it contains any points
if (coords->size() != 0)
{
geometry->setVertexArray(coords.get());
// assign texture array
if (have_texture_coords)
{
geometry->setTexCoordArray(0, texcoords.get());
}
// generate normals
osgUtil::SmoothingVisitor smoother;
smoother.smooth(*(geometry.get()));
geode.addDrawable(geometry.get());
osg::notify(DEBUG_INFO) << " inserting tag " << geode.getNumDrawables() - 1 << ":" << current_tag << std::endl;
tag_mapping.insert(PairDrawableToTag(geode.getNumDrawables() - 1, current_tag));
}
}
}
bool
Lwo2Layer::_find_triangle_fans(PolygonsList& polygons, PolygonsList& triangle_fans)
{
bool found = false;
while (_find_triangle_fan(polygons, triangle_fans))
{
found = true;
}
if (triangle_fans.size() > 0)
{
osg::notify(INFO) << "LWO2 loader, optimizing: found " << triangle_fans.size() << " triangle fans" << endl;
}
return found;
}
bool
Lwo2Layer::_find_triangle_strips(PolygonsList& polygons, PolygonsList& triangle_strips)
{
bool found = false;
while (_find_triangle_strip(polygons, triangle_strips))
{
found = true;
}
if (triangle_strips.size() > 0)
{
osg::notify(INFO) << "LWO2 loader, optimizing: found " << triangle_strips.size() << " triangle strips" << endl;
}
return found;
}
bool
Lwo2Layer::_find_triangle_fan(PolygonsList& polygons, PolygonsList& triangle_fans)
{
bool found = false;
IteratorPolygonsList polygon_iterator = polygons.begin();
while (polygon_iterator != polygons.end())
{
PointsList& points_list = *polygon_iterator;
if (points_list.size() == 3 && points_list[0].point_index != -1)
{
PointData a = points_list[0];
PointData b = points_list[1];
PointData c = points_list[2];
int next_polygon_index = _find_triangle_begins_with(polygons, a, c);
while (next_polygon_index >= 0)
{
found = true;
PointData d = polygons[next_polygon_index][2];
PointsList point_list;
point_list.push_back(a);
point_list.push_back(b);
point_list.push_back(c);
point_list.push_back(d);
// delete second triangle (mark as deleted)
(*(polygons.begin() + next_polygon_index))[0].point_index = -1;
// delete current (first) triangle (mark as deleted)
(*polygon_iterator)[0].point_index = -1;
c = d;
while ((next_polygon_index = _find_triangle_begins_with(polygons, a, c)) >= 0)
{
PointData d = polygons[next_polygon_index][2];
point_list.push_back(d);
// delete next triangle (mark as deleted)
(*(polygons.begin() + next_polygon_index))[0].point_index = -1;
c = d;
}
triangle_fans.push_back(point_list);
}
}
polygon_iterator++;
}
return found;
}
bool
Lwo2Layer::_find_triangle_strip(PolygonsList& polygons, PolygonsList& triangle_strips)
{
bool found = false;
IteratorPolygonsList polygon_iterator = polygons.begin();
int polygon_index = 0;
while (polygon_iterator != polygons.end())
{
PointsList& points_list = *polygon_iterator;
if (points_list.size() == 3 && points_list[0].point_index != -1)
{
PointData a = points_list[0];
PointData b = points_list[1];
PointData c = points_list[2];
int next_polygon_index = _find_triangle_begins_with(polygons, c, b);
while (next_polygon_index >= 0)
{
found = true;
PointData d = polygons[next_polygon_index][2];
PointsList point_list;
point_list.push_back(a);
point_list.push_back(b);
point_list.push_back(c);
point_list.push_back(d);
// delete second triangle (mark as deleted)
(*(polygons.begin() + next_polygon_index))[0].point_index = -1;
// delete current (first) triangle (mark as deleted)
(*polygon_iterator)[0].point_index = -1;
PointData strip_a = c;
PointData strip_b = d;
bool current_strip_a = true;
while ((next_polygon_index = _find_triangle_begins_with(polygons, strip_a, strip_b)) >= 0)
{
PointData d = polygons[next_polygon_index][2];
point_list.push_back(d);
if (current_strip_a)
{
strip_a = d;
}
else
{
strip_b = d;
}
current_strip_a = !current_strip_a;
// delete next triangle (mark as deleted)
(*(polygons.begin() + next_polygon_index))[0].point_index = -1;
}
triangle_strips.push_back(point_list);
}
}
polygon_iterator++;
polygon_index++;
}
return found;
}
int
Lwo2Layer::_find_triangle_begins_with(PolygonsList& polygons, PointData& a, PointData& b)
{
int result = -1;
int polygon_index = 0;
for (IteratorPolygonsList polygon_iterator = polygons.begin(); polygon_iterator != polygons.end(); polygon_iterator++, polygon_index++)
{
PointsList& points_list = *polygon_iterator;
if (points_list.size() == 3 && points_list[0].point_index != -1)
{
if (points_list[0] == a && points_list[1] == b)
{
result = polygon_index;
break;
}
else if (points_list[1] == a && points_list[2] == b)
{
// shift points
PointData temp = points_list[0];
points_list[0] = points_list[1];
points_list[1] = points_list[2];
points_list[2] = temp;
result = polygon_index;
break;
}
else if (points_list[2] == a && points_list[0] == b)
{
// shift points
PointData temp = points_list[2];
points_list[2] = points_list[1];
points_list[1] = points_list[0];
points_list[0] = temp;
result = polygon_index;
break;
}
}
}
return result;
}