diff --git a/pandatool/src/lwo/Sources.pp b/pandatool/src/lwo/Sources.pp index cf2e9f1772..2aecb168bc 100644 --- a/pandatool/src/lwo/Sources.pp +++ b/pandatool/src/lwo/Sources.pp @@ -38,6 +38,7 @@ lwoSurfaceBlockRepeat.h lwoSurfaceBlockRepeat.cxx \ lwoSurfaceBlockTMap.h lwoSurfaceBlockTMap.cxx \ lwoSurfaceBlockTransform.h lwoSurfaceBlockTransform.cxx \ + lwoSurfaceBlockVMapName.h lwoSurfaceBlockVMapName.cxx \ lwoSurfaceBlockWrap.h lwoSurfaceBlockWrap.cxx \ lwoSurfaceColor.h lwoSurfaceColor.cxx \ lwoSurfaceParameter.h lwoSurfaceParameter.cxx \ @@ -75,6 +76,7 @@ lwoSurfaceBlockRepeat.h \ lwoSurfaceBlockTMap.h \ lwoSurfaceBlockTransform.h \ + lwoSurfaceBlockVMapName.h \ lwoSurfaceBlockWrap.h \ lwoSurfaceColor.h \ lwoSurfaceParameter.h \ diff --git a/pandatool/src/lwo/config_lwo.cxx b/pandatool/src/lwo/config_lwo.cxx index 916d5dc488..6e1353d54d 100644 --- a/pandatool/src/lwo/config_lwo.cxx +++ b/pandatool/src/lwo/config_lwo.cxx @@ -33,6 +33,7 @@ #include "lwoSurfaceBlockRepeat.h" #include "lwoSurfaceBlockTMap.h" #include "lwoSurfaceBlockTransform.h" +#include "lwoSurfaceBlockVMapName.h" #include "lwoSurfaceBlockWrap.h" #include "lwoSurfaceColor.h" #include "lwoSurfaceParameter.h" @@ -95,6 +96,7 @@ init_liblwo() { LwoSurfaceBlockRepeat::init_type(); LwoSurfaceBlockTMap::init_type(); LwoSurfaceBlockTransform::init_type(); + LwoSurfaceBlockVMapName::init_type(); LwoSurfaceBlockWrap::init_type(); LwoSurfaceColor::init_type(); LwoSurfaceParameter::init_type(); diff --git a/pandatool/src/lwo/lwoSurfaceBlock.cxx b/pandatool/src/lwo/lwoSurfaceBlock.cxx index a9c6d88efc..7da61ad177 100644 --- a/pandatool/src/lwo/lwoSurfaceBlock.cxx +++ b/pandatool/src/lwo/lwoSurfaceBlock.cxx @@ -12,6 +12,7 @@ #include "lwoSurfaceBlockRepeat.h" #include "lwoSurfaceBlockTMap.h" #include "lwoSurfaceBlockWrap.h" +#include "lwoSurfaceBlockVMapName.h" #include @@ -94,6 +95,9 @@ make_new_chunk(IffInputFile *in, IffId id) { id == IffId("WRPW")) { return new LwoSurfaceBlockRepeat; + } else if (id == IffId("VMAP")) { + return new LwoSurfaceBlockVMapName; + } else { return IffChunk::make_new_chunk(in, id); } diff --git a/pandatool/src/lwo/lwoSurfaceBlock.h b/pandatool/src/lwo/lwoSurfaceBlock.h index aeebafdf4d..f405e41735 100644 --- a/pandatool/src/lwo/lwoSurfaceBlock.h +++ b/pandatool/src/lwo/lwoSurfaceBlock.h @@ -17,8 +17,6 @@ // chunk. //////////////////////////////////////////////////////////////////// class LwoSurfaceBlock : public LwoGroupChunk { -public: - public: virtual bool read_iff(IffInputFile *in, size_t stop_at); virtual void write(ostream &out, int indent_level = 0) const; diff --git a/pandatool/src/lwo/lwoSurfaceBlockVMapName.cxx b/pandatool/src/lwo/lwoSurfaceBlockVMapName.cxx new file mode 100644 index 0000000000..bd8c336e36 --- /dev/null +++ b/pandatool/src/lwo/lwoSurfaceBlockVMapName.cxx @@ -0,0 +1,41 @@ +// Filename: lwoSurfaceBlockVMapName.cxx +// Created by: drose (30Apr01) +// +//////////////////////////////////////////////////////////////////// + +#include "lwoSurfaceBlockVMapName.h" +#include "lwoInputFile.h" + +#include + +TypeHandle LwoSurfaceBlockVMapName::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: LwoSurfaceBlockVMapName::read_iff +// Access: Public, Virtual +// Description: Reads the data of the chunk in from the given input +// file, if possible. The ID and length of the chunk +// have already been read. stop_at is the byte position +// of the file to stop at (based on the current position +// at in->get_bytes_read()). Returns true on success, +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool LwoSurfaceBlockVMapName:: +read_iff(IffInputFile *in, size_t stop_at) { + LwoInputFile *lin = DCAST(LwoInputFile, in); + + _name = lin->get_string(); + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: LwoSurfaceBlockVMapName::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void LwoSurfaceBlockVMapName:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << get_id() << " { name = \"" << _name << "\" }\n"; +} diff --git a/pandatool/src/lwo/lwoSurfaceBlockVMapName.h b/pandatool/src/lwo/lwoSurfaceBlockVMapName.h new file mode 100644 index 0000000000..1dce1a5738 --- /dev/null +++ b/pandatool/src/lwo/lwoSurfaceBlockVMapName.h @@ -0,0 +1,46 @@ +// Filename: lwoSurfaceBlockVMapName.h +// Created by: drose (30Apr01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef LWOSURFACEBLOCKVMAPNAME_H +#define LWOSURFACEBLOCKVMAPNAME_H + +#include + +#include "lwoChunk.h" + +//////////////////////////////////////////////////////////////////// +// Class : LwoSurfaceBlockVMapName +// Description : Specifies the name of a set of UV's defined on the +// polygons that use this model. +//////////////////////////////////////////////////////////////////// +class LwoSurfaceBlockVMapName : public LwoChunk { +public: + string _name; + +public: + virtual bool read_iff(IffInputFile *in, size_t stop_at); + virtual void write(ostream &out, int indent_level = 0) const; + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + LwoChunk::init_type(); + register_type(_type_handle, "LwoSurfaceBlockVMapName", + LwoChunk::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#endif + + diff --git a/pandatool/src/lwoegg/cLwoPoints.cxx b/pandatool/src/lwoegg/cLwoPoints.cxx index 4fc9bc90a7..764cc38a00 100644 --- a/pandatool/src/lwoegg/cLwoPoints.cxx +++ b/pandatool/src/lwoegg/cLwoPoints.cxx @@ -19,14 +19,59 @@ //////////////////////////////////////////////////////////////////// void CLwoPoints:: add_vmap(const LwoVertexMap *lwo_vmap) { - VMapNames &names = _vmap[lwo_vmap->_map_type]; - bool inserted = names.insert(VMapNames::value_type(lwo_vmap->_name, lwo_vmap)).second; + IffId map_type = lwo_vmap->_map_type; + const string &name = lwo_vmap->_name; + + bool inserted; + if (map_type == IffId("TXUV")) { + inserted = + _txuv.insert(VMap::value_type(name, lwo_vmap)).second; + + } else if (map_type == IffId("PICK")) { + inserted = + _pick.insert(VMap::value_type(name, lwo_vmap)).second; + + } else { + return; + } + if (!inserted) { nout << "Multiple vertex maps on the same points of type " - << lwo_vmap->_map_type << " named " << lwo_vmap->_name << "\n"; + << map_type << " named " << name << "\n"; } } +//////////////////////////////////////////////////////////////////// +// Function: CLwoPoints::get_uv +// Access: Public +// Description: Returns true if there is a UV of the indicated name +// associated with the given vertex, false otherwise. +// If true, fills in uv with the value. +//////////////////////////////////////////////////////////////////// +bool CLwoPoints:: +get_uv(const string &uv_name, int n, LPoint2f &uv) const { + VMap::const_iterator ni = _txuv.find(uv_name); + if (ni == _txuv.end()) { + return false; + } + + const LwoVertexMap *vmap = (*ni).second; + if (vmap->_dimension != 2) { + nout << "Unexpected dimension of " << vmap->_dimension + << " for UV map " << uv_name << "\n"; + return false; + } + + if (!vmap->has_value(n)) { + return false; + } + + PTA_float value = vmap->get_value(n); + + uv.set(value[0], value[1]); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: CLwoPoints::make_egg // Access: Public diff --git a/pandatool/src/lwoegg/cLwoPoints.h b/pandatool/src/lwoegg/cLwoPoints.h index b163413fa3..67d1997d82 100644 --- a/pandatool/src/lwoegg/cLwoPoints.h +++ b/pandatool/src/lwoegg/cLwoPoints.h @@ -30,6 +30,7 @@ public: CLwoLayer *layer); void add_vmap(const LwoVertexMap *lwo_vmap); + bool get_uv(const string &uv_name, int n, LPoint2f &uv) const; void make_egg(); void connect_egg(); @@ -39,11 +40,11 @@ public: CLwoLayer *_layer; PT(EggVertexPool) _egg_vpool; - // A number of vertex maps may be associated, by type and then by - // name. - typedef map VMapNames; - typedef map VmapTypes; - VmapTypes _vmap; + // A number of vertex maps of different types may be associated, but + // we only care about some of the types here. + typedef map VMap; + VMap _txuv; + VMap _pick; }; #include "cLwoPoints.I" diff --git a/pandatool/src/lwoegg/cLwoPolygons.cxx b/pandatool/src/lwoegg/cLwoPolygons.cxx index 8601d6f9fc..9a18f7567e 100644 --- a/pandatool/src/lwoegg/cLwoPolygons.cxx +++ b/pandatool/src/lwoegg/cLwoPolygons.cxx @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -45,6 +46,34 @@ add_ptags(const LwoPolygonTags *lwo_ptags, const LwoTags *tags) { } } +//////////////////////////////////////////////////////////////////// +// Function: CLwoPolygons::add_vmad +// Access: Public +// Description: Associates the indicated DiscontinousVertexMap with +// the polygons. This can be used in conjunction with +// (or in place of) the VertexMap associated with the +// points set, to define per-polygon UV's etc. +//////////////////////////////////////////////////////////////////// +void CLwoPolygons:: +add_vmad(const LwoDiscontinuousVertexMap *lwo_vmad) { + IffId map_type = lwo_vmad->_map_type; + const string &name = lwo_vmad->_name; + + bool inserted; + if (map_type == IffId("TXUV")) { + inserted = + _txuv.insert(VMad::value_type(name, lwo_vmad)).second; + + } else { + return; + } + + if (!inserted) { + nout << "Multiple discontinous vertex maps on the same polygons of type " + << map_type << " named " << name << "\n"; + } +} + //////////////////////////////////////////////////////////////////// // Function: CLwoPolygons::get_surface // Access: Public @@ -83,6 +112,45 @@ get_surface(int polygon_index) const { return surface; } +//////////////////////////////////////////////////////////////////// +// Function: CLwoPolygons::get_uv +// Access: Public +// Description: Returns true if there is a UV of the indicated name +// associated with the given vertex of the indicated +// polygon, false otherwise. If true, fills in uv with +// the value. +// +// This performs a lookup in the optional +// "discontinuous" vertex mapping, which provides the +// ability to map different UV's per each polygon for +// the same vertex. If the UV is not defined here, it +// may also be defined in the standard vertex map, which +// is associated with the points themselves. +//////////////////////////////////////////////////////////////////// +bool CLwoPolygons:: +get_uv(const string &uv_name, int pi, int vi, LPoint2f &uv) const { + VMad::const_iterator ni = _txuv.find(uv_name); + if (ni == _txuv.end()) { + return false; + } + + const LwoDiscontinuousVertexMap *vmad = (*ni).second; + if (vmad->_dimension != 2) { + nout << "Unexpected dimension of " << vmad->_dimension + << " for discontinuous UV map " << uv_name << "\n"; + return false; + } + + if (!vmad->has_value(pi, vi)) { + return false; + } + + PTA_float value = vmad->get_value(pi, vi); + + uv.set(value[0], value[1]); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: CLwoPolygons::make_egg // Access: Public @@ -162,8 +230,6 @@ make_faces() { egg_prim = new EggPolygon; } - surface->check_texture(); - // First, we have to create a temporary vector of vertices for the // polygon, so we can possibly adjust the properties of these // vertices (like the UV's) in the shader before we create them. @@ -180,6 +246,22 @@ make_faces() { LPoint3d pos = LCAST(double, points->get_point(vindex)); egg_vertex->set_pos(pos); + // Does the vertex used named UV's? + if (surface->has_named_uvs()) { + string uv_name = surface->get_uv_name(); + LPoint2f uv; + if (get_uv(uv_name, pindex, vindex, uv)) { + // This UV is defined in a "discontinuous" map, that + // associated a particular UV per each polygon. + egg_vertex->set_uv(LCAST(double, uv)); + + } else if (_points->get_uv(uv_name, vindex, uv)) { + // The UV does not appear in a discontinuous map, but it + // is defined in the points set. + egg_vertex->set_uv(LCAST(double, uv)); + } + } + egg_vertices.push_back(egg_vertex); } } diff --git a/pandatool/src/lwoegg/cLwoPolygons.h b/pandatool/src/lwoegg/cLwoPolygons.h index 00563d35d8..10d02270d9 100644 --- a/pandatool/src/lwoegg/cLwoPolygons.h +++ b/pandatool/src/lwoegg/cLwoPolygons.h @@ -12,11 +12,14 @@ #include #include +#include + class LwoToEggConverter; class CLwoPoints; class CLwoSurface; class LwoTags; class LwoPolygonTags; +class LwoDiscontinuousVertexMap; //////////////////////////////////////////////////////////////////// // Class : CLwoPolygons @@ -31,8 +34,10 @@ public: CLwoPoints *points); void add_ptags(const LwoPolygonTags *lwo_ptags, const LwoTags *tags); + void add_vmad(const LwoDiscontinuousVertexMap *lwo_vmad); CLwoSurface *get_surface(int polygon_index) const; + bool get_uv(const string &uv_name, int pi, int vi, LPoint2f &uv) const; void make_egg(); void connect_egg(); @@ -48,6 +53,11 @@ public: const LwoPolygonTags *_surf_ptags; + // There might be named maps associated with the polygons to bring a + // per-polygon mapping to the UV's. + typedef map VMad; + VMad _txuv; + private: void make_faces(); }; diff --git a/pandatool/src/lwoegg/cLwoSurface.I b/pandatool/src/lwoegg/cLwoSurface.I index e3d9a3f489..d15599ee3e 100644 --- a/pandatool/src/lwoegg/cLwoSurface.I +++ b/pandatool/src/lwoegg/cLwoSurface.I @@ -16,14 +16,28 @@ get_name() const { } //////////////////////////////////////////////////////////////////// -// Function: CLwoSurface::has_uvs +// Function: CLwoSurface::has_named_uvs // Access: Public -// Description: Returns true if check_texture() has been called and -// the surface is known to have UV's available, either -// computed or stored. If this is true, get_uv() may be -// called to determine each UV coordinate. +// Description: Returns true if the surface is set up to reference +// UV's stored on the vertices, by name (as opposed to +// generated UV's, which is the more common Lightwave +// case). In this case, get_uv_name() can be called to +// return the name of the UV's. //////////////////////////////////////////////////////////////////// INLINE bool CLwoSurface:: -has_uvs() const { - return _has_uvs; +has_named_uvs() const { + return (_block != (CLwoSurfaceBlock *)NULL && + _block->_projection_mode == LwoSurfaceBlockProjection::M_uv); +} + +//////////////////////////////////////////////////////////////////// +// Function: CLwoSurface::get_uv_name +// Access: Public +// Description: Returns the name of the set of UV's that are +// associated with this surface, if has_named_uvs() is +// true. +//////////////////////////////////////////////////////////////////// +INLINE const string &CLwoSurface:: +get_uv_name() const { + return _block->_uv_name; } diff --git a/pandatool/src/lwoegg/cLwoSurface.cxx b/pandatool/src/lwoegg/cLwoSurface.cxx index bb190ca34a..9962ed4c9e 100644 --- a/pandatool/src/lwoegg/cLwoSurface.cxx +++ b/pandatool/src/lwoegg/cLwoSurface.cxx @@ -30,7 +30,6 @@ CLwoSurface(LwoToEggConverter *converter, const LwoSurface *surface) : { _flags = 0; _checked_texture = false; - _has_uvs = false; _map_uvs = NULL; _block = (CLwoSurfaceBlock *)NULL; @@ -208,7 +207,6 @@ check_texture() { } _checked_texture = true; _egg_texture = (EggTexture *)NULL; - _has_uvs = false; _map_uvs = NULL; if (_block == (CLwoSurfaceBlock *)NULL) { @@ -240,22 +238,18 @@ check_texture() { // Do we need to generate UV's? switch (_block->_projection_mode) { case LwoSurfaceBlockProjection::M_planar: - _has_uvs = true; _map_uvs = &CLwoSurface::map_planar; break; case LwoSurfaceBlockProjection::M_cylindrical: - _has_uvs = true; _map_uvs = &CLwoSurface::map_cylindrical; break; case LwoSurfaceBlockProjection::M_spherical: - _has_uvs = true; _map_uvs = &CLwoSurface::map_spherical; break; case LwoSurfaceBlockProjection::M_cubic: - _has_uvs = true; _map_uvs = &CLwoSurface::map_cubic; break; @@ -284,7 +278,9 @@ check_texture() { //////////////////////////////////////////////////////////////////// void CLwoSurface:: generate_uvs(vector_PT_EggVertex &egg_vertices) { - nassertv(_map_uvs != NULL); + if (_map_uvs == NULL) { + return; + } // To do this properly near seams and singularities (for instance, // the back seam and the poles of the spherical map), we will need diff --git a/pandatool/src/lwoegg/cLwoSurface.h b/pandatool/src/lwoegg/cLwoSurface.h index 5a19bce6dd..1263cd1c5a 100644 --- a/pandatool/src/lwoegg/cLwoSurface.h +++ b/pandatool/src/lwoegg/cLwoSurface.h @@ -8,6 +8,8 @@ #include +#include "cLwoSurfaceBlock.h" + #include #include #include @@ -15,7 +17,6 @@ #include -class CLwoSurfaceBlock; class LwoToEggConverter; class LwoSurfaceBlock; class EggPrimitive; @@ -38,7 +39,8 @@ public: float &smooth_angle); bool check_texture(); - INLINE bool has_uvs() const; + INLINE bool has_named_uvs() const; + INLINE const string &get_uv_name() const; enum Flags { F_color = 0x0001, @@ -68,7 +70,6 @@ public: bool _checked_texture; PT(EggTexture) _egg_texture; - bool _has_uvs; CLwoSurfaceBlock *_block; diff --git a/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx b/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx index 286741fcc3..a4905dc705 100644 --- a/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx +++ b/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx @@ -11,6 +11,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////////////// @@ -91,6 +92,10 @@ CLwoSurfaceBlock(LwoToEggConverter *converter, const LwoSurfaceBlock *block) : _w_wrap = wrap->_width; _h_wrap = wrap->_height; + } else if (chunk->is_of_type(LwoSurfaceBlockVMapName::get_class_type())) { + const LwoSurfaceBlockVMapName *vmap = DCAST(LwoSurfaceBlockVMapName, chunk); + _uv_name = vmap->_name; + } else if (chunk->is_of_type(LwoSurfaceBlockRepeat::get_class_type())) { const LwoSurfaceBlockRepeat *repeat = DCAST(LwoSurfaceBlockRepeat, chunk); if (repeat->get_id() == IffId("WRPW")) { diff --git a/pandatool/src/lwoegg/lwoToEggConverter.cxx b/pandatool/src/lwoegg/lwoToEggConverter.cxx index aee1477bda..6b6f924c12 100644 --- a/pandatool/src/lwoegg/lwoToEggConverter.cxx +++ b/pandatool/src/lwoegg/lwoToEggConverter.cxx @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -295,6 +296,14 @@ collect_lwo() { last_points->add_vmap(lwo_vmap); } + } else if (chunk->is_of_type(LwoDiscontinuousVertexMap::get_class_type())) { + if (last_polygons == (CLwoPolygons *)NULL) { + nout << "Discontinous vertex map chunk encountered without a preceding polygons chunk.\n"; + } else { + const LwoDiscontinuousVertexMap *lwo_vmad = DCAST(LwoDiscontinuousVertexMap, chunk); + last_polygons->add_vmad(lwo_vmad); + } + } else if (chunk->is_of_type(LwoTags::get_class_type())) { tags = DCAST(LwoTags, chunk);