vrmlNodeType.cxx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /**************************************************
  2. * VRML 2.0 Parser
  3. * Copyright (C) 1996 Silicon Graphics, Inc.
  4. *
  5. * Author(s) : Gavin Bell
  6. * Daniel Woods (first port)
  7. **************************************************
  8. */
  9. //
  10. // The VrmlNodeType class is responsible for storing information about node
  11. // or prototype types.
  12. //
  13. #include "vrmlNodeType.h"
  14. #include "vrmlNode.h"
  15. #include "vrmlParser.h"
  16. #include "pnotify.h"
  17. #include "indent.h"
  18. #include <stdio.h> // for sprintf()
  19. using std::ostream;
  20. //
  21. // Static list of node types.
  22. //
  23. plist<VrmlNodeType*> VrmlNodeType::typeList;
  24. static ostream &
  25. output_array(ostream &out, const MFArray *mf,
  26. int type, int indent_level, int items_per_row) {
  27. if (mf->empty()) {
  28. out << "[ ]";
  29. } else {
  30. out << "[";
  31. MFArray::const_iterator mi;
  32. int col = 0;
  33. for (mi = mf->begin(); mi != mf->end(); ++mi) {
  34. if (col == 0) {
  35. out << "\n";
  36. indent(out, indent_level + 2);
  37. }
  38. output_value(out, (*mi), type, indent_level + 2);
  39. if (++col >= items_per_row) {
  40. col = 0;
  41. } else {
  42. out << " ";
  43. }
  44. }
  45. out << "\n";
  46. indent(out, indent_level) << "]";
  47. }
  48. return out;
  49. }
  50. ostream &
  51. output_value(ostream &out, const VrmlFieldValue &value, int type,
  52. int indent) {
  53. switch (type) {
  54. case SFBOOL:
  55. return out << (value._sfbool ? "TRUE" : "FALSE");
  56. case SFFLOAT:
  57. case SFTIME:
  58. return out << value._sffloat;
  59. case SFINT32:
  60. return out << value._sfint32;
  61. case SFSTRING:
  62. {
  63. out << '"';
  64. for (const char *p = value._sfstring; *p != '\0'; p++) {
  65. if (*p == '"') {
  66. out << "\\\"";
  67. } else {
  68. out << *p;
  69. }
  70. }
  71. return out << '"';
  72. }
  73. case SFVEC2F:
  74. return out << value._sfvec[0] << " " << value._sfvec[1];
  75. case SFCOLOR:
  76. case SFVEC3F:
  77. return out << value._sfvec[0] << " " << value._sfvec[1] << " "
  78. << value._sfvec[2];
  79. case SFROTATION:
  80. return out << value._sfvec[0] << " " << value._sfvec[1] << " "
  81. << value._sfvec[2] << " " << value._sfvec[3];
  82. case SFNODE:
  83. switch (value._sfnode._type) {
  84. case SFNodeRef::T_null:
  85. return out << "NULL";
  86. case SFNodeRef::T_unnamed:
  87. nassertr(value._sfnode._p != nullptr, out);
  88. value._sfnode._p->output(out, indent);
  89. return out;
  90. case SFNodeRef::T_def:
  91. out << "DEF " << value._sfnode._name << " ";
  92. value._sfnode._p->output(out, indent);
  93. return out;
  94. case SFNodeRef::T_use:
  95. return out << "USE " << value._sfnode._name;
  96. }
  97. return out << "(invalid)";
  98. case SFIMAGE:
  99. return out << "(image)";
  100. case MFCOLOR:
  101. return output_array(out, value._mf, SFCOLOR, indent, 1);
  102. case MFFLOAT:
  103. return output_array(out, value._mf, SFFLOAT, indent, 5);
  104. case MFINT32:
  105. return output_array(out, value._mf, SFINT32, indent, 10);
  106. case MFROTATION:
  107. return output_array(out, value._mf, SFROTATION, indent, 1);
  108. case MFSTRING:
  109. return output_array(out, value._mf, SFSTRING, indent, 1);
  110. case MFVEC2F:
  111. return output_array(out, value._mf, SFVEC2F, indent, 1);
  112. case MFVEC3F:
  113. return output_array(out, value._mf, SFVEC3F, indent, 1);
  114. case MFNODE:
  115. return output_array(out, value._mf, SFNODE, indent, 1);
  116. }
  117. return out << "(unknown)";
  118. }
  119. VrmlNodeType::VrmlNodeType(const char *nm)
  120. {
  121. nassertv(nm != nullptr);
  122. name = strdup(nm);
  123. }
  124. VrmlNodeType::~VrmlNodeType()
  125. {
  126. free(name);
  127. // Free strings duplicated when fields/eventIns/eventOuts added:
  128. plist<NameTypeRec*>::iterator i;
  129. for (i = eventIns.begin(); i != eventIns.end(); i++) {
  130. NameTypeRec *r = *i;
  131. free(r->name);
  132. delete r;
  133. }
  134. for (i = eventOuts.begin(); i != eventOuts.end(); i++) {
  135. NameTypeRec *r = *i;
  136. free(r->name);
  137. delete r;
  138. }
  139. for (i = fields.begin(); i != fields.end(); i++) {
  140. NameTypeRec *r = *i;
  141. free(r->name);
  142. delete r;
  143. }
  144. }
  145. void
  146. VrmlNodeType::addToNameSpace(VrmlNodeType *_type)
  147. {
  148. if (find(_type->getName()) != nullptr) {
  149. std::cerr << "PROTO " << _type->getName() << " already defined\n";
  150. return;
  151. }
  152. typeList.push_front(_type);
  153. }
  154. //
  155. // One list is used to store all the node types. Nested namespaces are
  156. // separated by NULL elements.
  157. // This isn't terribly efficient, but it is nice and simple.
  158. //
  159. void
  160. VrmlNodeType::pushNameSpace()
  161. {
  162. typeList.push_front(nullptr);
  163. }
  164. void
  165. VrmlNodeType::popNameSpace()
  166. {
  167. // Remove everything up to and including the next NULL marker:
  168. plist<VrmlNodeType*>::iterator i;
  169. for (i = typeList.begin(); i != typeList.end();) {
  170. VrmlNodeType *nodeType = *i;
  171. ++i;
  172. typeList.pop_front();
  173. if (nodeType == nullptr) {
  174. break;
  175. }
  176. else {
  177. // NOTE: Instead of just deleting the VrmlNodeTypes, you will
  178. // probably want to reference count or garbage collect them, since
  179. // any nodes created as part of the PROTO implementation will
  180. // probably point back to their VrmlNodeType structure.
  181. delete nodeType;
  182. }
  183. }
  184. }
  185. const VrmlNodeType *
  186. VrmlNodeType::find(const char *_name)
  187. {
  188. // Look through the type stack:
  189. plist<VrmlNodeType*>::iterator i;
  190. for (i = typeList.begin(); i != typeList.end(); i++) {
  191. const VrmlNodeType *nt = *i;
  192. if (nt != nullptr && strcmp(nt->getName(),_name) == 0) {
  193. return nt;
  194. }
  195. }
  196. return nullptr;
  197. }
  198. void
  199. VrmlNodeType::addEventIn(const char *name, int type,
  200. const VrmlFieldValue *dflt)
  201. {
  202. add(eventIns, name, type, dflt);
  203. };
  204. void
  205. VrmlNodeType::addEventOut(const char *name, int type,
  206. const VrmlFieldValue *dflt)
  207. {
  208. add(eventOuts, name, type, dflt);
  209. };
  210. void
  211. VrmlNodeType::addField(const char *name, int type,
  212. const VrmlFieldValue *dflt)
  213. {
  214. add(fields, name, type, dflt);
  215. };
  216. void
  217. VrmlNodeType::addExposedField(const char *name, int type,
  218. const VrmlFieldValue *dflt)
  219. {
  220. char tmp[1000];
  221. add(fields, name, type, dflt);
  222. sprintf(tmp, "set_%s", name);
  223. add(eventIns, tmp, type, dflt);
  224. sprintf(tmp, "%s_changed", name);
  225. add(eventOuts, tmp, type, dflt);
  226. };
  227. void
  228. VrmlNodeType::add(plist<NameTypeRec*> &recs, const char *name, int type,
  229. const VrmlFieldValue *dflt)
  230. {
  231. NameTypeRec *r = new NameTypeRec;
  232. r->name = strdup(name);
  233. r->type = type;
  234. if (dflt != nullptr) {
  235. r->dflt = *dflt;
  236. } else {
  237. memset(&r->dflt, 0, sizeof(r->dflt));
  238. }
  239. recs.push_front(r);
  240. }
  241. const VrmlNodeType::NameTypeRec *
  242. VrmlNodeType::hasEventIn(const char *name) const
  243. {
  244. return has(eventIns, name);
  245. }
  246. const VrmlNodeType::NameTypeRec *
  247. VrmlNodeType::hasEventOut(const char *name) const
  248. {
  249. return has(eventOuts, name);
  250. }
  251. const VrmlNodeType::NameTypeRec *
  252. VrmlNodeType::hasField(const char *name) const
  253. {
  254. return has(fields, name);
  255. }
  256. const VrmlNodeType::NameTypeRec *
  257. VrmlNodeType::hasExposedField(const char *name) const
  258. {
  259. // Must have field "name", eventIn "set_name", and eventOut
  260. // "name_changed", all with same type:
  261. char tmp[1000];
  262. const NameTypeRec *base, *set_name, *name_changed;
  263. base = has(fields, name);
  264. sprintf(tmp, "set_%s\n", name);
  265. nassertr(strlen(tmp) < 1000, nullptr);
  266. set_name = has(eventIns, tmp);
  267. sprintf(tmp, "%s_changed\n", name);
  268. nassertr(strlen(tmp) < 1000, nullptr);
  269. name_changed = has(eventOuts, tmp);
  270. if (base == nullptr || set_name == nullptr || name_changed == nullptr) {
  271. return nullptr;
  272. }
  273. if (base->type != set_name->type || base->type != name_changed->type) {
  274. return nullptr;
  275. }
  276. return base;
  277. }
  278. const VrmlNodeType::NameTypeRec *
  279. VrmlNodeType::has(const plist<NameTypeRec*> &recs, const char *name) const
  280. {
  281. plist<NameTypeRec*>::const_iterator i;
  282. for (i = recs.begin(); i != recs.end(); i++) {
  283. if (strcmp((*i)->name, name) == 0)
  284. return (*i);
  285. }
  286. return nullptr;
  287. }