Panda3D
 All Classes Functions Variables Enumerations
vrmlNodeType.cxx
00001 /**************************************************
00002  * VRML 2.0 Parser
00003  * Copyright (C) 1996 Silicon Graphics, Inc.
00004  *
00005  * Author(s)    : Gavin Bell
00006  *                Daniel Woods (first port)
00007  **************************************************
00008  */
00009 
00010 //
00011 // The VrmlNodeType class is responsible for storing information about node
00012 // or prototype types.
00013 //
00014 
00015 #include "vrmlNodeType.h"
00016 #include "vrmlNode.h"
00017 #include "vrmlParser.h"
00018 #include "pnotify.h"
00019 #include "indent.h"
00020 
00021 #include <stdio.h>  // for sprintf()
00022 
00023 
00024 //
00025 // Static list of node types.
00026 //
00027 plist<VrmlNodeType*> VrmlNodeType::typeList;
00028 
00029 static ostream &
00030 output_array(ostream &out, const MFArray *mf,
00031              int type, int indent_level, int items_per_row) {
00032   if (mf->empty()) {
00033     out << "[ ]";
00034   } else {
00035     out << "[";
00036     MFArray::const_iterator mi;
00037     int col = 0;
00038     for (mi = mf->begin(); mi != mf->end(); ++mi) {
00039       if (col == 0) {
00040         out << "\n";
00041         indent(out, indent_level + 2);
00042       }      
00043       output_value(out, (*mi), type, indent_level + 2);
00044       if (++col >= items_per_row) {
00045         col = 0;
00046       } else {
00047         out << " ";
00048       }
00049     }
00050     out << "\n";
00051     indent(out, indent_level) << "]";
00052   }
00053   return out;
00054 }
00055 
00056 ostream & 
00057 output_value(ostream &out, const VrmlFieldValue &value, int type,
00058              int indent) {
00059   switch (type) {
00060   case SFBOOL:
00061     return out << (value._sfbool ? "TRUE" : "FALSE");
00062 
00063   case SFFLOAT:
00064   case SFTIME:
00065     return out << value._sffloat;
00066 
00067   case SFINT32:
00068     return out << value._sfint32;
00069 
00070   case SFSTRING:
00071     {
00072       out << '"';
00073       for (const char *p = value._sfstring; *p != '\0'; p++) {
00074         if (*p == '"') {
00075           out << "\\\"";
00076         } else {
00077           out << *p;
00078         }
00079       }
00080       return out << '"';
00081     }
00082 
00083   case SFVEC2F:
00084     return out << value._sfvec[0] << " " << value._sfvec[1];
00085 
00086   case SFCOLOR:
00087   case SFVEC3F:
00088     return out << value._sfvec[0] << " " << value._sfvec[1] << " "
00089                << value._sfvec[2];
00090 
00091   case SFROTATION:
00092     return out << value._sfvec[0] << " " << value._sfvec[1] << " "
00093                << value._sfvec[2] << " " << value._sfvec[3];
00094 
00095   case SFNODE:
00096     switch (value._sfnode._type) {
00097     case SFNodeRef::T_null:
00098       return out << "NULL";
00099 
00100     case SFNodeRef::T_unnamed:
00101       nassertr(value._sfnode._p != NULL, out);
00102       value._sfnode._p->output(out, indent);
00103       return out;
00104 
00105     case SFNodeRef::T_def:
00106       out << "DEF " << value._sfnode._name << " ";
00107       value._sfnode._p->output(out, indent);
00108       return out;
00109 
00110     case SFNodeRef::T_use:
00111       return out << "USE " << value._sfnode._name;
00112     }
00113     return out << "(invalid)";
00114 
00115   case SFIMAGE:
00116     return out << "(image)";
00117 
00118   case MFCOLOR:
00119     return output_array(out, value._mf, SFCOLOR, indent, 1);
00120 
00121   case MFFLOAT:
00122     return output_array(out, value._mf, SFFLOAT, indent, 5);
00123 
00124   case MFINT32:
00125     return output_array(out, value._mf, SFINT32, indent, 10);
00126 
00127   case MFROTATION:
00128     return output_array(out, value._mf, SFROTATION, indent, 1);
00129 
00130   case MFSTRING:
00131     return output_array(out, value._mf, SFSTRING, indent, 1);
00132 
00133   case MFVEC2F:
00134     return output_array(out, value._mf, SFVEC2F, indent, 1);
00135 
00136   case MFVEC3F:
00137     return output_array(out, value._mf, SFVEC3F, indent, 1);
00138 
00139   case MFNODE:
00140     return output_array(out, value._mf, SFNODE, indent, 1);
00141   }
00142 
00143   return out << "(unknown)";
00144 }
00145 
00146 VrmlNodeType::VrmlNodeType(const char *nm)
00147 {
00148     nassertv(nm != NULL);
00149     name = strdup(nm);
00150 }
00151 
00152 VrmlNodeType::~VrmlNodeType()
00153 {
00154     free(name);
00155 
00156     // Free strings duplicated when fields/eventIns/eventOuts added:
00157     plist<NameTypeRec*>::iterator i;
00158 
00159     for (i = eventIns.begin(); i != eventIns.end(); i++) {
00160         NameTypeRec *r = *i;
00161         free(r->name);
00162         delete r;
00163     }
00164     for (i = eventOuts.begin(); i != eventOuts.end(); i++) {
00165         NameTypeRec *r = *i;
00166         free(r->name);
00167         delete r;
00168     }
00169     for (i = fields.begin(); i != fields.end(); i++) {
00170         NameTypeRec *r = *i;
00171         free(r->name);
00172         delete r;
00173     }
00174 }
00175 
00176 void
00177 VrmlNodeType::addToNameSpace(VrmlNodeType *_type)
00178 {
00179     if (find(_type->getName()) != NULL) {
00180         cerr << "PROTO " << _type->getName() << " already defined\n";
00181         return;
00182     }
00183     typeList.push_front(_type);
00184 }
00185 
00186 //
00187 // One list is used to store all the node types.  Nested namespaces are
00188 // separated by NULL elements.
00189 // This isn't terribly efficient, but it is nice and simple.
00190 //
00191 void
00192 VrmlNodeType::pushNameSpace()
00193 {
00194     typeList.push_front(NULL);
00195 }
00196 
00197 void
00198 VrmlNodeType::popNameSpace()
00199 {
00200     // Remove everything up to and including the next NULL marker:
00201     plist<VrmlNodeType*>::iterator i;
00202     for (i = typeList.begin(); i != typeList.end();) {
00203         VrmlNodeType *nodeType = *i;
00204         ++i;
00205         typeList.pop_front();
00206 
00207         if (nodeType == NULL) {
00208             break;
00209         }
00210         else {
00211             // NOTE:  Instead of just deleting the VrmlNodeTypes, you will
00212             // probably want to reference count or garbage collect them, since
00213             // any nodes created as part of the PROTO implementation will
00214             // probably point back to their VrmlNodeType structure.
00215             delete nodeType;
00216         }
00217     }
00218 }
00219 
00220 const VrmlNodeType *
00221 VrmlNodeType::find(const char *_name)
00222 {
00223     // Look through the type stack:
00224     plist<VrmlNodeType*>::iterator i;
00225     for (i = typeList.begin(); i != typeList.end(); i++) {
00226         const VrmlNodeType *nt = *i;
00227         if (nt != NULL && strcmp(nt->getName(),_name) == 0) {
00228             return nt;
00229         }
00230     }
00231     return NULL;
00232 }
00233 
00234 void
00235 VrmlNodeType::addEventIn(const char *name, int type,
00236                          const VrmlFieldValue *dflt)
00237 {
00238     add(eventIns, name, type, dflt);
00239 };
00240 void
00241 VrmlNodeType::addEventOut(const char *name, int type,
00242                           const VrmlFieldValue *dflt)
00243 {
00244     add(eventOuts, name, type, dflt);
00245 };
00246 void
00247 VrmlNodeType::addField(const char *name, int type,
00248                        const VrmlFieldValue *dflt)
00249 {
00250     add(fields, name, type, dflt);
00251 };
00252 void
00253 VrmlNodeType::addExposedField(const char *name, int type,
00254                               const VrmlFieldValue *dflt)
00255 {
00256     char tmp[1000];
00257     add(fields, name, type, dflt);
00258     sprintf(tmp, "set_%s", name);
00259     add(eventIns, tmp, type, dflt);
00260     sprintf(tmp, "%s_changed", name);
00261     add(eventOuts, tmp, type, dflt);
00262 };
00263 
00264 void
00265 VrmlNodeType::add(plist<NameTypeRec*> &recs, const char *name, int type,
00266                   const VrmlFieldValue *dflt)
00267 {
00268     NameTypeRec *r = new NameTypeRec;
00269     r->name = strdup(name);
00270     r->type = type;
00271     if (dflt != NULL) {
00272       r->dflt = *dflt;
00273     } else {
00274       memset(&r->dflt, 0, sizeof(r->dflt));
00275     }
00276     recs.push_front(r);
00277 }
00278 
00279 const VrmlNodeType::NameTypeRec *
00280 VrmlNodeType::hasEventIn(const char *name) const
00281 {
00282     return has(eventIns, name);
00283 }
00284 
00285 const VrmlNodeType::NameTypeRec *
00286 VrmlNodeType::hasEventOut(const char *name) const
00287 {
00288     return has(eventOuts, name);
00289 }
00290 
00291 const VrmlNodeType::NameTypeRec *
00292 VrmlNodeType::hasField(const char *name) const
00293 {
00294     return has(fields, name);
00295 }
00296 
00297 const VrmlNodeType::NameTypeRec *
00298 VrmlNodeType::hasExposedField(const char *name) const
00299 {
00300     // Must have field "name", eventIn "set_name", and eventOut
00301     // "name_changed", all with same type:
00302     char tmp[1000];
00303     const NameTypeRec *base, *set_name, *name_changed;
00304 
00305     base = has(fields, name);
00306 
00307     sprintf(tmp, "set_%s\n", name);
00308     nassertr(strlen(tmp) < 1000, NULL);
00309     set_name = has(eventIns, tmp);
00310 
00311     sprintf(tmp, "%s_changed\n", name);
00312     nassertr(strlen(tmp) < 1000, NULL);
00313     name_changed = has(eventOuts, tmp);
00314 
00315     if (base == NULL || set_name == NULL || name_changed == NULL) {
00316       return NULL;
00317     }
00318 
00319     if (base->type != set_name->type || base->type != name_changed->type) {
00320       return NULL;
00321     }
00322 
00323     return base;
00324 }
00325 
00326 const VrmlNodeType::NameTypeRec *
00327 VrmlNodeType::has(const plist<NameTypeRec*> &recs, const char *name) const
00328 {
00329     plist<NameTypeRec*>::const_iterator i;
00330     for (i = recs.begin(); i != recs.end(); i++) {
00331         if (strcmp((*i)->name, name) == 0)
00332             return (*i);
00333     }
00334     return NULL;
00335 }
00336 
 All Classes Functions Variables Enumerations