788 lines
21 KiB
C++
788 lines
21 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 <osg/Notify>
|
|
#include <osg/Geode>
|
|
#include <osg/Group>
|
|
#include <osg/Texture2D>
|
|
#include <osg/Material>
|
|
#include <osg/CullFace>
|
|
#include <osg/BlendFunc>
|
|
#include <osg/io_utils>
|
|
|
|
#include <osgDB/Registry>
|
|
#include <osgDB/ReadFile>
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#include "old_Lwo2.h"
|
|
#include "old_Lwo2Layer.h"
|
|
|
|
Lwo2::Lwo2():
|
|
_current_layer(0),
|
|
_successfully_read(false)
|
|
{
|
|
}
|
|
|
|
Lwo2::~Lwo2()
|
|
{
|
|
// delete all layers
|
|
for (IteratorLayers itr = _layers.begin(); itr != _layers.end(); itr++)
|
|
{
|
|
delete (*itr).second;
|
|
}
|
|
|
|
// delete all surfaces
|
|
for (IteratorSurfaces itr_surf = _surfaces.begin(); itr_surf != _surfaces.end(); itr_surf++)
|
|
{
|
|
delete (*itr_surf).second;
|
|
}
|
|
};
|
|
|
|
bool
|
|
Lwo2::ReadFile( const string& filename )
|
|
{
|
|
notify(INFO) << "Opening file: " << filename << std::endl;
|
|
|
|
_fin.open(filename.c_str(), ios::in | ios::binary );
|
|
if (!_fin.is_open())
|
|
{
|
|
notify(INFO) << "Can't open file '" << filename << "'" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// checking EA-IFF85 format
|
|
// http://www.lightwave3d.com/developer/75lwsdk/docs/filefmts/eaiff85.html
|
|
if (_read_long() != tag_FORM)
|
|
{
|
|
notify(INFO) << "File '" << filename << "' is not IFF format file." << std::endl;
|
|
_fin.close();
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
notify(INFO) << "Detected EA-IFF85 format" << std::endl;
|
|
}
|
|
|
|
unsigned long form_size = _read_long();
|
|
notify(INFO) << "Form size: " << form_size << std::endl;
|
|
|
|
// checking LWO2 format
|
|
// http://www.lightwave3d.com/developer/75lwsdk/docs/filefmts/lwo2.html
|
|
if (_read_long() != tag_LWO2)
|
|
{
|
|
unsigned long make_id(const char*);
|
|
notify(INFO) << "File '" << filename << "' is not LWO2 format file." << std::endl;
|
|
_fin.close();
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
notify(INFO) << "Detected LWO2 format" << std::endl;
|
|
}
|
|
|
|
unsigned long read_bytes = 4;
|
|
unsigned long current_tag_name;
|
|
unsigned long current_tag_size;
|
|
|
|
// main loop for reading tags
|
|
while (read_bytes < form_size && !_fin.eof())
|
|
{
|
|
current_tag_name = _read_long();
|
|
current_tag_size = _read_long();
|
|
read_bytes += 8 + current_tag_size + current_tag_size % 2;
|
|
|
|
_print_tag(current_tag_name, current_tag_size);
|
|
|
|
if (current_tag_name == tag_TAGS)
|
|
{
|
|
_read_tag_strings(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_LAYR)
|
|
{
|
|
_read_layer(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_PNTS)
|
|
{
|
|
_read_points(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_VMAP)
|
|
{
|
|
_read_vertex_mapping(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_VMAD)
|
|
{
|
|
_read_polygons_mapping(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_POLS)
|
|
{
|
|
_read_polygons(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_PTAG)
|
|
{
|
|
_read_polygon_tag_mapping(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_CLIP)
|
|
{
|
|
_read_image_definition(current_tag_size);
|
|
}
|
|
else if (current_tag_name == tag_SURF)
|
|
{
|
|
_read_surface(current_tag_size);
|
|
}
|
|
else
|
|
{
|
|
_fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
|
|
}
|
|
}
|
|
|
|
_fin.close();
|
|
|
|
return _successfully_read = true;
|
|
}
|
|
|
|
unsigned char
|
|
Lwo2::_read_char()
|
|
{
|
|
char c = 0;
|
|
if (_fin.is_open())
|
|
{
|
|
_fin.read(&c, 1);
|
|
}
|
|
return static_cast<unsigned char>(c);
|
|
}
|
|
|
|
unsigned long
|
|
Lwo2::_read_long()
|
|
{
|
|
return
|
|
(_read_char() << 24) |
|
|
(_read_char() << 16) |
|
|
(_read_char() << 8) |
|
|
_read_char();
|
|
}
|
|
|
|
unsigned short
|
|
Lwo2::_read_short()
|
|
{
|
|
return
|
|
(_read_char() << 8) |
|
|
_read_char();
|
|
}
|
|
|
|
float
|
|
Lwo2::_read_float()
|
|
{
|
|
unsigned long x = _read_long();
|
|
return *(float*)&x;
|
|
}
|
|
|
|
// read null terminated string
|
|
|
|
string&
|
|
Lwo2::_read_string(string& str)
|
|
{
|
|
char c;
|
|
do {
|
|
c = _read_char();
|
|
str += c;
|
|
} while (c != 0);
|
|
|
|
// if length of string (including \0) is odd skip another byte
|
|
if (str.length() % 2) {
|
|
_read_char();
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
// print 4-char tag to debug out
|
|
|
|
void
|
|
Lwo2::_print_tag(unsigned int tag, unsigned int size) {
|
|
notify(DEBUG_INFO) << "Found tag "
|
|
<< char(tag >> 24)
|
|
<< char(tag >> 16)
|
|
<< char(tag >> 8)
|
|
<< char(tag)
|
|
<< " size " << size << " bytes"
|
|
<< std::endl;
|
|
}
|
|
|
|
// print 4-char type
|
|
void
|
|
Lwo2::_print_type(unsigned int type) {
|
|
notify(DEBUG_INFO) << " type \t"
|
|
<< char(type >> 24)
|
|
<< char(type >> 16)
|
|
<< char(type >> 8)
|
|
<< char(type)
|
|
<< std::endl;
|
|
}
|
|
|
|
// read TAGS info
|
|
|
|
void
|
|
Lwo2::_read_tag_strings(unsigned long size)
|
|
{
|
|
while (size > 0)
|
|
{
|
|
string name;
|
|
_read_string(name);
|
|
size -= name.length() + name.length() % 2;
|
|
_tags.push_back(name);
|
|
|
|
notify(DEBUG_INFO) << " name \t'" << name.c_str() << "'" << std::endl;
|
|
}
|
|
}
|
|
|
|
// read LAYR info
|
|
|
|
void Lwo2::_read_layer(unsigned long size)
|
|
{
|
|
unsigned short number = _read_short();
|
|
size -= 2;
|
|
|
|
Lwo2Layer* layer = new Lwo2Layer();
|
|
_layers[number] = layer;
|
|
_current_layer = layer;
|
|
layer->_number = number;
|
|
|
|
layer->_flags = _read_short();
|
|
size -= 2;
|
|
|
|
float x = _read_float();
|
|
float y = _read_float();
|
|
float z = _read_float();
|
|
layer->_pivot.set(x, y, z);
|
|
size -= 4 * 3;
|
|
|
|
_read_string(layer->_name);
|
|
size -= layer->_name.length() + layer->_name.length() % 2;
|
|
|
|
if (size > 2)
|
|
{
|
|
layer->_parent = _read_short();
|
|
size -= 2;
|
|
}
|
|
|
|
_fin.seekg(size + size % 2, ios::cur);
|
|
}
|
|
|
|
// read PNTS info
|
|
|
|
void Lwo2::_read_points(unsigned long size)
|
|
{
|
|
int count = size / 12;
|
|
notify(DEBUG_INFO) << " count \t" << count << std::endl;
|
|
|
|
while (count--)
|
|
{
|
|
PointData point;
|
|
|
|
float x = _read_float();
|
|
float y = _read_float();
|
|
float z = _read_float();
|
|
point.coord = Vec3(x, y, z);
|
|
_current_layer->_points.push_back(point);
|
|
}
|
|
}
|
|
|
|
// read VMAP info
|
|
|
|
void Lwo2::_read_vertex_mapping(unsigned long size)
|
|
{
|
|
unsigned int type = _read_long();
|
|
size -= 4;
|
|
|
|
_print_type(type);
|
|
|
|
short dimension = _read_short();
|
|
size -= 2;
|
|
|
|
notify(DEBUG_INFO) << " dimension \t" << dimension << std::endl;
|
|
|
|
string name;
|
|
_read_string(name);
|
|
size -= name.length() + name.length() % 2;
|
|
notify(DEBUG_INFO) << " name \t'" << name.c_str() << "'" << std::endl;
|
|
|
|
if (type == tag_TXUV && dimension == 2)
|
|
{
|
|
int count = size / 10;
|
|
unsigned short n;
|
|
float u;
|
|
float v;
|
|
while (count--)
|
|
{
|
|
n = _read_short();
|
|
u = _read_float();
|
|
v = _read_float();
|
|
|
|
// point coords must be read previously
|
|
if (n < _current_layer->_points.size())
|
|
{
|
|
_current_layer->_points[n].texcoord = Vec2(u, v);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// not recognized yet
|
|
notify(DEBUG_INFO) << " skipping..." << std::endl;
|
|
_fin.seekg(size + size % 2, ios::cur);
|
|
}
|
|
}
|
|
|
|
// read POLS info
|
|
|
|
void
|
|
Lwo2::_read_polygons(unsigned long size)
|
|
{
|
|
unsigned int type = _read_long();
|
|
size -= 4;
|
|
|
|
_print_type(type);
|
|
|
|
if (type == tag_FACE)
|
|
{
|
|
unsigned short vertex_count;
|
|
|
|
while (size > 0)
|
|
{
|
|
PointData point;
|
|
vertex_count = _read_short() & 0x03FF;
|
|
size -= 2;
|
|
|
|
PointsList points_list;
|
|
|
|
while (vertex_count--)
|
|
{
|
|
unsigned short point_index = _read_short();
|
|
|
|
point = _current_layer->_points[point_index];
|
|
point.point_index = point_index;
|
|
|
|
points_list.push_back(point);
|
|
size -= 2;
|
|
}
|
|
|
|
_current_layer->_polygons.push_back(points_list);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// not recognized yet
|
|
notify(DEBUG_INFO) << " skipping..." << std::endl;
|
|
_fin.seekg(size + size % 2, ios::cur);
|
|
}
|
|
}
|
|
|
|
// read PTAG info
|
|
|
|
void Lwo2::_read_polygon_tag_mapping(unsigned long size)
|
|
{
|
|
unsigned int type = _read_long();
|
|
size -= 4;
|
|
|
|
_print_type(type);
|
|
|
|
if (type == tag_SURF)
|
|
{
|
|
int count = size / 4;
|
|
_current_layer->_polygons_tag.resize(count);
|
|
|
|
short polygon_index;
|
|
short tag_index;
|
|
|
|
while (count--)
|
|
{
|
|
polygon_index = _read_short();
|
|
tag_index = _read_short();
|
|
_current_layer->_polygons_tag[polygon_index] = tag_index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// not recognized yet
|
|
notify(DEBUG_INFO) << " skipping..." << std::endl;
|
|
_fin.seekg(size + size % 2, ios::cur);
|
|
}
|
|
}
|
|
|
|
// read VMAD info
|
|
|
|
void Lwo2::_read_polygons_mapping(unsigned long size)
|
|
{
|
|
unsigned int type = _read_long();
|
|
size -= 4;
|
|
|
|
_print_type(type);
|
|
|
|
short dimension = _read_short();
|
|
size -= 2;
|
|
|
|
notify(DEBUG_INFO) << " dimension \t" << dimension << std::endl;
|
|
|
|
string name;
|
|
_read_string(name);
|
|
size -= name.length() + name.length() % 2;
|
|
notify(DEBUG_INFO) << " name \t'" << name.c_str() << "'" << std::endl;
|
|
|
|
if (type == tag_TXUV && dimension == 2)
|
|
{
|
|
notify(DEBUG_INFO) << " polygons mappings:" << endl;
|
|
notify(DEBUG_INFO) << "\tpoint\tpolygon\ttexcoord" << endl;
|
|
notify(DEBUG_INFO) << "\t=====\t=======\t========" << endl;
|
|
|
|
int count = size / 12;
|
|
|
|
short point_index;
|
|
short polygon_index;
|
|
float u;
|
|
float v;
|
|
while (count--)
|
|
{
|
|
point_index = _read_short();
|
|
polygon_index = _read_short();
|
|
u = _read_float();
|
|
v = _read_float();
|
|
|
|
notify(DEBUG_INFO) << " \t" << point_index << "\t" << polygon_index << "\t" << Vec2(u, v) << endl;
|
|
|
|
// apply texture coordinates
|
|
PointsList& points_list = _current_layer->_polygons[polygon_index];
|
|
for (unsigned int i = 0; i < points_list.size(); i++)
|
|
{
|
|
if (points_list[i].point_index == point_index)
|
|
{
|
|
points_list[i].texcoord = Vec2(u, v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// not recognized yet
|
|
notify(DEBUG_INFO) << " skipping..." << std::endl;
|
|
_fin.seekg(size + size % 2, ios::cur);
|
|
}
|
|
|
|
}
|
|
|
|
// read CLIP info
|
|
|
|
void
|
|
Lwo2::_read_image_definition(unsigned long size)
|
|
{
|
|
unsigned int index = _read_long();
|
|
size -= 4;
|
|
notify(DEBUG_INFO) << " index \t" << index << std::endl;
|
|
|
|
unsigned int type;
|
|
while (size > 0)
|
|
{
|
|
type = _read_long();
|
|
size -= 4;
|
|
|
|
_print_type(type);
|
|
|
|
// size of name
|
|
// not included in specification ??
|
|
_read_short();
|
|
size -= 2;
|
|
|
|
string name;
|
|
_read_string(name);
|
|
size -= name.length() + name.length() % 2;
|
|
|
|
if (index + 1 > _images.size())
|
|
{
|
|
_images.resize(index + 1);
|
|
}
|
|
|
|
_images[index] = name.c_str();
|
|
|
|
notify(DEBUG_INFO) << " name \t'" << name.c_str() << "'" << std::endl;
|
|
}
|
|
}
|
|
|
|
// read SURF info
|
|
|
|
void Lwo2::_read_surface(unsigned long size)
|
|
{
|
|
Lwo2Surface* surface = new Lwo2Surface();
|
|
surface->image_index = -1;
|
|
surface->state_set = NULL;
|
|
|
|
_read_string(surface->name);
|
|
size -= surface->name.length() + surface->name.length() % 2;
|
|
notify(DEBUG_INFO) << " name \t'" << surface->name.c_str() << "'" << std::endl;
|
|
|
|
string source;
|
|
_read_string(source);
|
|
size -= source.length() + source.length() % 2;
|
|
notify(DEBUG_INFO) << " source \t'" << source.c_str() << "'" << std::endl;
|
|
|
|
unsigned long current_tag_name;
|
|
unsigned short current_tag_size;
|
|
|
|
while (size > 0 && !_fin.eof())
|
|
{
|
|
current_tag_name = _read_long();
|
|
size -= 4;
|
|
current_tag_size = _read_short();
|
|
size -= 2;
|
|
|
|
_print_tag(current_tag_name, current_tag_size);
|
|
|
|
if (current_tag_name == tag_BLOK)
|
|
{
|
|
|
|
// BLOK
|
|
int blok_size = current_tag_size;
|
|
size -= blok_size;
|
|
while (blok_size > 0)
|
|
{
|
|
current_tag_name = _read_long();
|
|
blok_size -= 4;
|
|
current_tag_size = _read_short();
|
|
blok_size -= 2;
|
|
notify(DEBUG_INFO) << " ";
|
|
_print_tag(current_tag_name, current_tag_size);
|
|
|
|
if (current_tag_name == tag_IMAG)
|
|
{
|
|
surface->image_index = _read_short();
|
|
notify(DEBUG_INFO) << " image index\t" << surface->image_index << std::endl;
|
|
blok_size -= 2;
|
|
}
|
|
else if (current_tag_name == tag_IMAP)
|
|
{
|
|
|
|
// IMAP
|
|
int imap_size = current_tag_size;
|
|
blok_size -= imap_size;
|
|
|
|
string ordinal;
|
|
_read_string(ordinal);
|
|
imap_size -= ordinal.length() + ordinal.length() % 2;
|
|
notify(DEBUG_INFO) << " ordinal \t'" << ordinal.c_str() << "'" << std::endl;
|
|
|
|
while(imap_size > 0)
|
|
{
|
|
current_tag_name = _read_long();
|
|
imap_size -= 4;
|
|
current_tag_size = _read_short();
|
|
imap_size -= 2;
|
|
notify(DEBUG_INFO) << " ";
|
|
_print_tag(current_tag_name, current_tag_size);
|
|
|
|
_fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
|
|
imap_size -= current_tag_size + current_tag_size % 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
|
|
blok_size -= current_tag_size + current_tag_size % 2;
|
|
}
|
|
}
|
|
}
|
|
else if (current_tag_name == tag_COLR)
|
|
{
|
|
float r = _read_float();
|
|
float g = _read_float();
|
|
float b = _read_float();
|
|
surface->color.set(r,g,b);
|
|
notify(DEBUG_INFO) << " color \t" << surface->color << std::endl;
|
|
current_tag_size -= 12;
|
|
size -= 12;
|
|
|
|
// skip ununderstooded envelope
|
|
_fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
|
|
size -= current_tag_size + current_tag_size % 2;
|
|
}
|
|
else
|
|
{
|
|
_fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
|
|
size -= current_tag_size + current_tag_size % 2;
|
|
}
|
|
}
|
|
|
|
_surfaces[surface->name] = surface;
|
|
}
|
|
|
|
// Generation OSG Geode object from parsed LWO2 file
|
|
|
|
bool
|
|
Lwo2::GenerateGroup( Group& group )
|
|
{
|
|
if (!_successfully_read) return false;
|
|
|
|
// generate StateSets for each surface
|
|
_generate_statesets_from_surfaces();
|
|
|
|
// create geometry from all layers
|
|
for (IteratorLayers itr = _layers.begin(); itr != _layers.end(); itr++)
|
|
{
|
|
osg::Geode* geode = new osg::Geode();
|
|
|
|
notify(DEBUG_INFO) << "Generate geode for layer " << (*itr).first << std::endl;
|
|
DrawableToTagMapping tag_mapping;
|
|
(*itr).second->GenerateGeode(*geode, _tags.size(), tag_mapping);
|
|
|
|
// assign StateSet for each PTAG group
|
|
for (unsigned int i = 0; i < geode->getNumDrawables(); i++)
|
|
{
|
|
notify(DEBUG_INFO) << " Assigning surface " << _tags[tag_mapping[i]] << " to drawable " << i << std::endl;
|
|
geode->getDrawable(i)->setStateSet(_surfaces[_tags[tag_mapping[i]]]->state_set);
|
|
|
|
// copy material color to color array of geometry
|
|
// because when lighting off color not applyed
|
|
Geometry* geometry = geode->getDrawable(i)->asGeometry();
|
|
if (geometry)
|
|
{
|
|
Material* material = dynamic_cast<Material*>(_surfaces[_tags[tag_mapping[i]]]->state_set->getAttribute(StateAttribute::MATERIAL));
|
|
if (material) {
|
|
Vec4Array* colors = new Vec4Array();
|
|
colors->push_back(material->getDiffuse(Material::FRONT_AND_BACK));
|
|
geometry->setColorBinding(Geometry::BIND_OVERALL);
|
|
geometry->setColorArray(colors);
|
|
}
|
|
}
|
|
}
|
|
|
|
group.addChild(geode);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// generate StateSets for each surface
|
|
void
|
|
Lwo2::_generate_statesets_from_surfaces()
|
|
{
|
|
ref_ptr<BlendFunc> blending = new BlendFunc();
|
|
blending->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
ref_ptr<CullFace> culling = new CullFace();
|
|
culling->setMode(CullFace::BACK);
|
|
|
|
for (IteratorSurfaces itr_surf = _surfaces.begin(); itr_surf != _surfaces.end(); itr_surf++)
|
|
{
|
|
Lwo2Surface* surface = (*itr_surf).second;
|
|
StateSet* state_set = new osg::StateSet;
|
|
bool use_blending = false;
|
|
|
|
notify(DEBUG_INFO) << "\tcreating surface " << (*itr_surf).first << std::endl;
|
|
|
|
// check if exist texture image for this surface
|
|
if (surface->image_index >= 0)
|
|
{
|
|
Image* image = osgDB::readImageFile(_images[surface->image_index]);
|
|
notify(DEBUG_INFO) << "\tloaded image '" << _images[surface->image_index] << "'" << std::endl;
|
|
notify(DEBUG_INFO) << "\tresult - " << image << std::endl;
|
|
if (image)
|
|
{
|
|
// create texture
|
|
Texture2D* texture = new osg::Texture2D;
|
|
texture->setImage(image);
|
|
state_set->setTextureAttributeAndModes(0, texture, StateAttribute::ON);
|
|
|
|
// setup texture wrapping
|
|
texture->setWrap(Texture::WRAP_S, Texture::REPEAT);
|
|
texture->setWrap(Texture::WRAP_T, Texture::REPEAT);
|
|
|
|
// detect blending
|
|
if (image->getPixelSizeInBits() == 32)
|
|
{
|
|
for (int i = 0; i < image->s(); i++)
|
|
{
|
|
for (int j = 0; j < image->t(); j++)
|
|
{
|
|
unsigned char* data = image->data(i, j);
|
|
data++; // skip r
|
|
data++; // skip g
|
|
data++; // skip b
|
|
|
|
// check alpha
|
|
if (*data < 255)
|
|
{
|
|
use_blending = true;
|
|
break;
|
|
}
|
|
}
|
|
if (use_blending) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// set color
|
|
Material* material = new Material();
|
|
material->setDiffuse(Material::FRONT_AND_BACK, Vec4(surface->color, 1.0f));
|
|
state_set->setAttribute(material);
|
|
|
|
state_set->setMode(GL_NORMALIZE, StateAttribute::ON);
|
|
|
|
if (use_blending)
|
|
{
|
|
// setup blending
|
|
state_set->setAttribute(blending.get());
|
|
state_set->setMode(GL_BLEND, StateAttribute::ON);
|
|
|
|
// setup depth sorting
|
|
state_set->setRenderingHint(StateSet::TRANSPARENT_BIN);
|
|
}
|
|
else
|
|
{
|
|
// setup culling
|
|
state_set->setAttribute(culling.get());
|
|
state_set->setMode(GL_CULL_FACE, StateAttribute::ON);
|
|
}
|
|
|
|
surface->state_set = state_set;
|
|
}
|
|
}
|
|
|
|
// makes 4-byte integer tag from four chars
|
|
// used in IFF standard
|
|
|
|
unsigned long make_id(const char* tag)
|
|
{
|
|
unsigned long result = 0;
|
|
for (unsigned int i = 0; i < strlen(tag) && i < 4; i++)
|
|
{
|
|
result <<= 8;
|
|
result += int(tag[i]);
|
|
}
|
|
return result;
|
|
}
|