home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 5257 / source.7z / x_lwo.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2012-03-18  |  139.1 KB  |  4,172 lines

  1. #include "xentax.h"
  2. #include "x_lwo.h"
  3.  
  4. template<class T>
  5. inline uint32 GetVXBytes(T index)
  6. {
  7.  return ((index < 0xFF00) ? 2 : 4);
  8. }
  9.  
  10. void WriteVX(std::ofstream& ofile, uint32 index)
  11. {
  12.  if(index < 0xFF00)
  13.     BE_write_uint16(ofile, (uint16)index);
  14.  else {
  15.     reverse_byte_order(&index);
  16.     index |= 0x000000FF;
  17.     reverse_byte_order(&index);
  18.     BE_write_uint32(ofile, index);
  19.    }
  20. }
  21.  
  22. lwFileSaver::lwFileSaver()
  23. {
  24.  tags.chunksize = 0;
  25.  tags.currindex = 0;
  26. }
  27.  
  28. lwFileSaver::~lwFileSaver()
  29. {
  30. }
  31.  
  32. bool lwFileSaver::hasTxuv(const char* name)const
  33. {
  34.  for(std::map<uint16, lwLAYR>::const_iterator liter = layrs.begin(); liter != layrs.end(); liter++) {
  35.      const std::map<uint16, lwPNTS>& pntss = liter->second.pntss;
  36.      for(std::map<uint16, lwPNTS>::const_iterator piter = pntss.begin(); piter != pntss.end(); piter++) {
  37.          const std::map<std::string, lwTXUV>& uvmap = piter->second.txuv;
  38.          if(piter->second.txuv.find(name) != uvmap.end()) return true;
  39.         }
  40.     }
  41.  return false;
  42. }
  43.  
  44. bool lwFileSaver::insertClip(uint32 clipindex, const char* filename)
  45. {
  46.  if(!filename) return false;
  47.  if(!strlen(filename)) return false;
  48.  
  49.  // create CLIP
  50.  lwCLIP item;
  51.  item.chunksize = 0;
  52.  item.filename = filename;
  53.  
  54.  // compute chunksize
  55.  item.chunksize += 0x04; // clip index
  56.  item.chunksize += 0x04; // STIL
  57.  item.chunksize += 0x02; // STIL chunksize
  58.  item.chunksize += align02(item.filename.length() + 1); // string
  59.  item.chunksize += 0x04; // FLAG
  60.  item.chunksize += 0x02; // FLAG chunksize
  61.  item.chunksize += 0x02; // FLAG data
  62.  item.chunksize += 0x02; // FLAG data
  63.  
  64.  // add clip
  65.  clips.insert(std::map<uint32, lwCLIP>::value_type(clipindex, item));
  66.  return true;
  67. }
  68.  
  69. bool lwFileSaver::insertLayr(uint16 layer, const char* name)
  70. {
  71.  // validate
  72.  using namespace std;
  73.  if(!(layer < LWO_MAX_LAYERS)) return false;
  74.  
  75.  // create LAYR
  76.  lwLAYR item;
  77.  item.chunksize = 0;
  78.  item.flags = 0;
  79.  item.pivot_x = 0;
  80.  item.pivot_y = 0;
  81.  item.pivot_z = 0; 
  82.  item.name = (name ? name : "");
  83.  
  84.  // compute LAYR chunksize
  85.  item.chunksize += 0x02; // number
  86.  item.chunksize += 0x02; // flags
  87.  item.chunksize += 0x0C; // pivot
  88.  item.chunksize += align02(item.name.length() + 1); // name
  89.  
  90.  // add LAYR
  91.  layrs.insert(map<uint32, lwLAYR>::value_type(layer, item));
  92.  return true;
  93. }
  94.  
  95. bool lwFileSaver::insertPnts(uint16 layer, uint16 pointset, const boost::shared_array<lwVertex3D>& data, uint32 elem)
  96. {
  97.  // validate
  98.  using namespace std;
  99.  if(!(layer < LWO_MAX_LAYERS)) return error("lwFileSave: Invalid layer number.");
  100.  if(!data.get()) return error("lwFileSaver: Invalid pointer argument.");
  101.  if(!elem) return error("lwFileSaver: Invalid number of point elements.");
  102.  
  103.  // validate
  104.  map<uint16, lwLAYR>::iterator parent = layrs.find(layer);
  105.  if(layrs.find(layer) == layrs.end()) return error("lwFileSaver: Layer not found.");
  106.  
  107.  // create PNTS
  108.  lwPNTS item;
  109.  item.chunksize = 0;
  110.  item.data = data;
  111.  item.elem = elem;
  112.  
  113.  // compute PNTS chunksize
  114.  item.chunksize += elem*0x04; // x
  115.  item.chunksize += elem*0x04; // y
  116.  item.chunksize += elem*0x04; // z
  117.  
  118.  // pointset must not exist
  119.  map<uint16, lwPNTS>& pmap = parent->second.pntss;
  120.  if(pmap.find(pointset) != pmap.end()) return error("lwFileSaver: Point set already exists.");
  121.  
  122.  // add PNTS
  123.  typedef map<uint16, lwPNTS>::value_type value_type;
  124.  pmap.insert(value_type(pointset, item));
  125.  return true;
  126. }
  127.  
  128. bool lwFileSaver::insertTxuv(uint16 layer, uint16 pointset, const char* name, const boost::shared_array<lwRefVertex2D>& data, uint32 elem)
  129. {
  130.  // validate
  131.  using namespace std;
  132.  if(!(layer < LWO_MAX_LAYERS)) return error("lwFileSave: Invalid layer number.");
  133.  if(!data.get()) return error("lwFileSaver: Invalid pointer argument.");
  134.  if(!elem) return error("lwFileSaver: Invalid number of point elements.");
  135.  if(!strlen(name)) return error("lwFileSaver: UV maps must have a valid name.");
  136.  
  137.  // validate
  138.  map<uint16, lwLAYR>::iterator parent = layrs.find(layer);
  139.  if(layrs.find(layer) == layrs.end()) return error("lwFileSaver: Layer not found.");
  140.  
  141.  // create TXUV
  142.  lwTXUV item;
  143.  item.chunksize = 0;
  144.  item.data = data;
  145.  item.elem = elem;
  146.  
  147.  // compute TXUV chunksize
  148.  item.chunksize += 0x04; // TXUV
  149.  item.chunksize += 0x02; // dimension
  150.  item.chunksize += align02(strlen(name) + 1); // name
  151.  for(uint32 i = 0; i < elem; i++) item.chunksize += GetVXBytes(data[i].reference); // VX
  152.  item.chunksize += elem*0x04; // u
  153.  item.chunksize += elem*0x04; // v
  154.  
  155.  // pointset must exist
  156.  map<uint16, lwPNTS>::iterator pset = parent->second.pntss.find(pointset);
  157.  if(pset == parent->second.pntss.end()) return error("lwFileSaver: A point set must exist to add a UV map.");
  158.  
  159.  // validate references
  160.  for(uint32 i = 0; i < elem; i++)
  161.      if(!(data[i].reference < pset->second.elem))
  162.         return error("lwFileSaver: UV index out of range.");
  163.  
  164.  // add TXUV
  165.  typedef map<string, lwTXUV>::value_type value_type;
  166.  pset->second.txuv.insert(value_type(name, item));
  167.  return true;
  168. }
  169.  
  170. bool lwFileSaver::insertWght(uint16 layer, uint16 pointset, const char* name, const boost::shared_array<lwRefVertex1D>& data, uint32 elem)
  171. {
  172.  // validate
  173.  using namespace std;
  174.  if(!(layer < LWO_MAX_LAYERS)) return error("lwFileSave: Invalid layer number.");
  175.  if(!data.get()) return error("lwFileSaver: Invalid pointer argument.");
  176.  if(!elem) return error("lwFileSaver: Invalid number of point elements.");
  177.  if(!strlen(name)) return error("lwFileSaver: Weight maps must have a valid name.");
  178.  
  179.  // validate
  180.  map<uint16, lwLAYR>::iterator parent = layrs.find(layer);
  181.  if(layrs.find(layer) == layrs.end()) return error("lwFileSaver: Layer not found.");
  182.  
  183.  // create WGHT
  184.  lwWGHT item;
  185.  item.chunksize = 0;
  186.  item.data = data;
  187.  item.elem = elem;
  188.  
  189.  // compute WGHT chunksize
  190.  item.chunksize += 0x04; // WGHT
  191.  item.chunksize += 0x02; // dimension
  192.  item.chunksize += align02(strlen(name) + 1); // name
  193.  for(uint32 i = 0; i < elem; i++) item.chunksize += GetVXBytes(data[i].reference); // VX
  194.  item.chunksize += elem*0x04; // weight
  195.  
  196.  // pointset must exist
  197.  map<uint16, lwPNTS>::iterator pset = parent->second.pntss.find(pointset);
  198.  if(pset == parent->second.pntss.end()) return error("lwFileSaver: A point set must exist to add a weight map.");
  199.  
  200.  // validate references
  201.  for(uint32 i = 0; i < elem; i++)
  202.      if(!(data[i].reference < pset->second.elem))
  203.         return error("lwFileSaver: Weight index out of range.");
  204.  
  205.  // add WGHT
  206.  typedef map<string, lwWGHT>::value_type value_type;
  207.  pset->second.wght.insert(value_type(name, item));
  208.  return true;
  209. }
  210.  
  211. bool lwFileSaver::insertMorf(uint16 layer, uint16 pointset, const char* name, const boost::shared_array<lwRefVertex3D>& data, uint32 elem)
  212. {
  213.  // validate
  214.  using namespace std;
  215.  if(!(layer < LWO_MAX_LAYERS)) return error("lwFileSave: Invalid layer number.");
  216.  if(!data.get()) return error("lwFileSaver: Invalid pointer argument.");
  217.  if(!elem) return error("lwFileSaver: Invalid number of point elements.");
  218.  if(!strlen(name)) return error("lwFileSaver: Moph maps must have a valid name.");
  219.  
  220.  // validate
  221.  map<uint16, lwLAYR>::iterator parent = layrs.find(layer);
  222.  if(layrs.find(layer) == layrs.end()) return error("lwFileSaver: Layer not found.");
  223.  
  224.  // create MORF
  225.  lwMORF item;
  226.  item.chunksize = 0;
  227.  item.data = data;
  228.  item.elem = elem;
  229.  
  230.  // compute MORF chunksize
  231.  item.chunksize += 0x04; // MORF
  232.  item.chunksize += 0x02; // dimension
  233.  item.chunksize += align02(strlen(name) + 1); // name
  234.  for(uint32 i = 0; i < elem; i++) item.chunksize += GetVXBytes(data[i].reference); // VX
  235.  item.chunksize += elem*0x04; // x
  236.  item.chunksize += elem*0x04; // y
  237.  item.chunksize += elem*0x04; // z
  238.  
  239.  // pointset must exist
  240.  map<uint16, lwPNTS>::iterator pset = parent->second.pntss.find(pointset);
  241.  if(pset == parent->second.pntss.end()) return error("lwFileSaver: A point set must exist to add a morph map.");
  242.  
  243.  // validate references
  244.  for(uint32 i = 0; i < elem; i++)
  245.      if(!(data[i].reference < pset->second.elem))
  246.         return error("lwFileSaver: Morph index out of range.");
  247.  
  248.  // add TXUV
  249.  typedef map<string, lwMORF>::value_type value_type;
  250.  pset->second.morf.insert(value_type(name, item));
  251.  return true;
  252. }
  253.  
  254. bool lwFileSaver::insertPols(uint16 layer, uint16 pointset, const char* name, const boost::shared_array<lwTriangle>& data, uint32 elem)
  255. {
  256.  // validate
  257.  using namespace std;
  258.  if(!(layer < LWO_MAX_LAYERS)) return error("lwFileSave: Invalid layer number.");
  259.  if(!data.get()) return error("lwFileSaver: Invalid pointer argument.");
  260.  if(!elem) return error("lwFileSaver: Invalid number of triangle elements.");
  261.  
  262.  // layer must exist
  263.  map<uint16, lwLAYR>::iterator parent = layrs.find(layer);
  264.  if(layrs.find(layer) == layrs.end()) return error("lwFileSaver: Layer not found.");
  265.  
  266.  // pointset must exist
  267.  map<uint16, lwPNTS>::iterator pset = parent->second.pntss.find(pointset);
  268.  if(pset == parent->second.pntss.end()) return error("lwFileSaver: A point set must exist to add polygons.");
  269.  
  270.  // create POLS
  271.  lwPOLS item;
  272.  item.chunksize = 0;
  273.  item.name = (((name == nullptr) || !strlen(name)) ? "Default" : name);
  274.  item.data = data;
  275.  item.elem = elem;
  276.  
  277.  // compute POLS chunksize
  278.  item.chunksize += 0x04; // FACE
  279.  for(uint32 i = 0; i < elem; i++) {
  280.      item.chunksize += 0x02; // number of vertices
  281.      item.chunksize += GetVXBytes(data[i].a); // VX
  282.      item.chunksize += GetVXBytes(data[i].b); // VX
  283.      item.chunksize += GetVXBytes(data[i].c); // VX
  284.     }
  285.  
  286.  // validate references
  287.  for(uint32 i = 0; i < elem; i++) {
  288.      if(!(data[i].a < pset->second.elem)) return error("lwFileSaver: Face index out of range.");
  289.      if(!(data[i].b < pset->second.elem)) return error("lwFileSaver: Face index out of range.");
  290.      if(!(data[i].c < pset->second.elem)) return error("lwFileSaver: Face index out of range.");
  291.     }
  292.  
  293.  // create surface
  294.  if(!insertSurf(item.name.c_str()))
  295.     return false;
  296.  
  297.  // find surface TAGS index
  298.  typedef boost::bimap<uint16, std::string> bmap_t;
  299.  bmap_t::right_iterator tagiter = tags.surftags.right.find(item.name);
  300.  if(tagiter == tags.surftags.right.end()) return error("lwFileSaver: Could not find surface tag index.");
  301.  
  302.  // create PTAG
  303.  item.surf.chunksize = 0;    // PTAG chunksize
  304.  item.surf.type = LWO_SURF;  // PTAG type
  305.  
  306.  // compute PTAG chunksize
  307.  item.surf.chunksize += 0x04; // SURF
  308.  if(item.elem < 0xFF00) item.surf.chunksize += 0x02 * item.elem; // VX data
  309.  else item.surf.chunksize += (0x02 * 0xFF00) + (0x04 * (item.elem - 0xFF00)); // VX data
  310.  item.surf.chunksize += 0x02 * item.elem; // tag index data
  311.  
  312.  // compute PTAG data
  313.  for(uint32 i = 0; i < item.elem; i++) {
  314.      typedef map<uint32, uint16>::value_type value_type;
  315.      item.surf.tags.insert(value_type(i, tagiter->second));
  316.     }
  317.  
  318.  // set POLS
  319.  pset->second.face.push_back(item);
  320.  return true;
  321. }
  322.  
  323. bool lwFileSaver::insertJnts(uint16 layer, uint16 jointset, const boost::shared_array<lwVertex3D>& data, uint32 elem)
  324. {
  325.  // validate
  326.  using namespace std;
  327.  if(!(layer < LWO_MAX_LAYERS)) return error("Invalid layer number.");
  328.  if(!data.get()) return error("Invalid pointer argument.");
  329.  if(!elem) return error("Invalid number of joints.");
  330.  
  331.  // find layer
  332.  map<uint16, lwLAYR>::iterator parent = layrs.find(layer);
  333.  if(layrs.find(layer) == layrs.end()) return error("Layer not found.");
  334.  
  335.  // create JNTS
  336.  lwJNTS item;
  337.  item.chunksize = 0;
  338.  item.data = data;
  339.  item.elem = elem;
  340.  
  341.  // compute JNTS chunksize
  342.  item.chunksize += elem*0x04; // x
  343.  item.chunksize += elem*0x04; // y
  344.  item.chunksize += elem*0x04; // z
  345.  
  346.  // jointset must not exist
  347.  map<uint16, lwJNTS>& jmap = parent->second.jntss;
  348.  if(jmap.find(jointset) != jmap.end()) return error("Joint set already exists.");
  349.  
  350.  // add JNTS
  351.  typedef map<uint16, lwJNTS>::value_type value_type;
  352.  jmap.insert(value_type(jointset, item));
  353.  return true;
  354. }
  355.  
  356. bool lwFileSaver::insertSkel(uint16 layer, uint16 jointset, const char* name, const boost::shared_array<lwSkelegon>& data, uint32 elem)
  357. {
  358.  // validate
  359.  using namespace std;
  360.  if(!(layer < LWO_MAX_LAYERS)) return error("Invalid layer number.");
  361.  if(!name || !strlen(name)) return error("Invalid skeleton name.");
  362.  if(!data.get()) return error("Invalid pointer argument.");
  363.  if(!elem) return error("Invalid number of skelegon elements.");
  364.  
  365.  // layer must exist
  366.  map<uint16, lwLAYR>::iterator parent = layrs.find(layer);
  367.  if(layrs.find(layer) == layrs.end()) return error("Layer not found.");
  368.  
  369.  // jointset must exist
  370.  map<uint16, lwJNTS>::iterator jset = parent->second.jntss.find(jointset);
  371.  if(jset == parent->second.jntss.end()) return error("Jointset does not exist.");
  372.  
  373.  // create SKEL
  374.  lwSKEL item;
  375.  item.chunksize = 0;
  376.  item.name = name;
  377.  item.data = data;
  378.  item.elem = elem;
  379.  item.stag.chunksize = 0;
  380.  item.btag.chunksize = 0;
  381.  item.ptag.chunksize = 0;
  382.  item.utag.chunksize = 0;
  383.  
  384.  // compute SKEL chunksize
  385.  item.chunksize += 0x04; // BONE
  386.  for(uint32 i = 0; i < elem; i++) {
  387.      item.chunksize += 0x02; // number of vertices
  388.      item.chunksize += GetVXBytes(data[i].a); // VX
  389.      item.chunksize += GetVXBytes(data[i].b); // VX
  390.     }
  391.  
  392.  // validate joint references
  393.  for(uint32 i = 0; i < elem; i++) {
  394.      if(!(data[i].a < jset->second.elem)) return error("Joint index out of range.");
  395.      if(!(data[i].b < jset->second.elem)) return error("Joint index out of range.");
  396.     }
  397.  
  398.  // create surface
  399.  if(!insertSurf(name))
  400.     return false;
  401.  
  402.  // find surface TAGS index
  403.  typedef boost::bimap<uint16, std::string> bmap_t;
  404.  bmap_t::right_iterator tagiter = tags.surftags.right.find(item.name);
  405.  if(tagiter == tags.surftags.right.end()) return error("Could not find surface tag index.");
  406.  
  407.  // create PTAG:SURF
  408.  item.stag.chunksize = 0;   // PTAG chunksize
  409.  item.stag.type = LWO_SURF; // PTAG type
  410.  
  411.  // compute PTAG:SURF chunksize
  412.  item.stag.chunksize += 0x04; // SURF
  413.  if(item.elem < 0xFF00) item.stag.chunksize += 0x02 * item.elem; // VX data
  414.  else item.stag.chunksize += (0x02 * 0xFF00) + (0x04 * (item.elem - 0xFF00)); // VX data
  415.  item.stag.chunksize += 0x02 * item.elem; // tag index data
  416.  
  417.  // compute PTAG:SURF data
  418.  for(uint32 i = 0; i < item.elem; i++) {
  419.      typedef map<uint32, uint16>::value_type value_type;
  420.      item.stag.tags.insert(value_type(i, tagiter->second));
  421.     }
  422.  
  423.  // create bones and parts
  424.  for(uint32 i = 0; i < item.elem; i++) {
  425.      if(!insertBone(data[i].name.c_str())) return false;
  426.      if(!insertPart(data[i].name.c_str())) return false;
  427.     }
  428.  
  429.  // create PTAG:BONE
  430.  item.btag.chunksize = 0;
  431.  item.btag.type = LWO_BONE;
  432.  
  433.  // compute PTAG:BONE chunksize
  434.  item.btag.chunksize += 0x04; // PART
  435.  if(item.elem < 0xFF00) item.btag.chunksize += 0x02 * item.elem; // VX data
  436.  else item.btag.chunksize += (0x02 * 0xFF00) + (0x04 * (item.elem - 0xFF00)); // VX data
  437.  item.btag.chunksize += 0x02 * item.elem; // tag index data
  438.  
  439.  // compute PTAG:BONE data
  440.  for(uint32 i = 0; i < item.elem; i++) {
  441.      bmap_t::right_iterator iter = tags.bonetags.right.find(data[i].name);
  442.      if(iter == tags.bonetags.right.end()) return error("Could not find bone tag index.");
  443.      typedef map<uint32, uint16>::value_type value_type;
  444.      item.btag.tags.insert(value_type(i, iter->second));
  445.     }
  446.  
  447.  // create PTAG:PART
  448.  item.ptag.chunksize = 0;
  449.  item.ptag.type = LWO_PART;
  450.  
  451.  // compute PTAG:PART chunksize
  452.  item.ptag.chunksize += 0x04; // PART
  453.  if(item.elem < 0xFF00) item.ptag.chunksize += 0x02 * item.elem; // VX data
  454.  else item.ptag.chunksize += (0x02 * 0xFF00) + (0x04 * (item.elem - 0xFF00)); // VX data
  455.  item.ptag.chunksize += 0x02 * item.elem; // tag index data
  456.  
  457.  // compute PTAG:PART data
  458.  for(uint32 i = 0; i < item.elem; i++) {
  459.      bmap_t::right_iterator iter = tags.parttags.right.find(data[i].name);
  460.      if(iter == tags.parttags.right.end()) return error("Could not find part tag index.");
  461.      typedef map<uint32, uint16>::value_type value_type;
  462.      item.ptag.tags.insert(value_type(i, iter->second));
  463.     }
  464.  
  465.  // set SKEL
  466.  jset->second.skel.push_back(item);
  467.  return true;
  468. }
  469.  
  470. bool lwFileSaver::insertBone(const char* name)
  471. {
  472.  // validate
  473.  using namespace std;
  474.  if(!name) return error("Invalid part name.");
  475.  if(!strlen(name)) return error("Invalid part name.");
  476.  
  477.  // BONE already exists
  478.  if(tags.bonetags.right.find(name) != tags.bonetags.right.end())
  479.     return error("Bone names must be unique.");
  480.  
  481.  // add BONE to TAGS
  482.  typedef boost::bimap<uint16, string>::value_type value_type;
  483.  tags.bonetags.insert(value_type(tags.currindex, name));
  484.  tags.chunksize += align02(strlen(name) + 1);
  485.  tags.currindex++;
  486.  
  487.  return true;
  488. }
  489.  
  490. bool lwFileSaver::insertPart(const char* name)
  491. {
  492.  // validate
  493.  using namespace std;
  494.  if(!name) return error("Invalid part name.");
  495.  if(!strlen(name)) return error("Invalid part name.");
  496.  
  497.  // PART already exists (OK, not an error)
  498.  if(tags.parttags.right.find(name) != tags.parttags.right.end())
  499.     return true;
  500.  
  501.  // add PART to TAGS
  502.  typedef boost::bimap<uint16, string>::value_type value_type;
  503.  tags.parttags.insert(value_type(tags.currindex, name));
  504.  tags.chunksize += align02(strlen(name) + 1);
  505.  tags.currindex++;
  506.  
  507.  return true;
  508. }
  509.  
  510. bool lwFileSaver::insertSurf(const char* name)
  511. {
  512.  // validate
  513.  using namespace std;
  514.  if(!name) return error("lwFileSaver: Invalid surface name.");
  515.  if(!strlen(name)) return error("lwFileSaver: Invalid surface name.");
  516.  
  517.  // surface already exists (OK, not an error)
  518.  if(surfs.find(name) != surfs.end())
  519.     return true;
  520.  
  521.  // create SURF
  522.  lwSURF item;
  523.  item.chunksize = 0;
  524.  item.flags = LWO_SURF_FLAGS_COLR | LWO_SURF_FLAGS_DIFF | LWO_SURF_FLAGS_SPEC | LWO_SURF_FLAGS_TRAN;
  525.  item.colr[0] = 0.7843137f;
  526.  item.colr[1] = 0.7843137f;
  527.  item.colr[2] = 0.7843137f;
  528.  item.diff = 1.0f;
  529.  item.spec = 0.0f;
  530.  item.tran = 0.0f;
  531.  item.colr_map.chunksize = 0;
  532.  item.diff_map.chunksize = 0;
  533.  item.spec_map.chunksize = 0;
  534.  item.tran_map.chunksize = 0;
  535.  
  536.  // compute SURF chunksize
  537.  item.chunksize += align02(strlen(name) + 1); // name
  538.  item.chunksize += 0x02; // source
  539.  item.chunksize += 0x04; // COLR
  540.  item.chunksize += 0x02; // COLOR sub-chunksize
  541.  item.chunksize += 0x04; // color
  542.  item.chunksize += 0x04; // color
  543.  item.chunksize += 0x04; // color
  544.  item.chunksize += 0x02; // envelope
  545.  item.chunksize += 0x04; // DIFF
  546.  item.chunksize += 0x02; // DIFF sub-chunksize
  547.  item.chunksize += 0x04; // intensity
  548.  item.chunksize += 0x02; // envelope
  549.  item.chunksize += 0x04; // SPEC
  550.  item.chunksize += 0x02; // SPEC sub-chunksize
  551.  item.chunksize += 0x04; // intensity
  552.  item.chunksize += 0x02; // envelope
  553.  item.chunksize += 0x04; // TRAN
  554.  item.chunksize += 0x02; // TRAN sub-chunksize
  555.  item.chunksize += 0x04; // intensity
  556.  item.chunksize += 0x02; // envelope
  557.  
  558.  // add SURF to TAGS
  559.  typedef boost::bimap<uint16, string>::value_type tags_item;
  560.  tags.surftags.insert(tags_item(tags.currindex, name));
  561.  tags.chunksize += align02(strlen(name) + 1);
  562.  tags.currindex++;
  563.  
  564.  // add SURF
  565.  typedef map<string, lwSURF>::value_type value_type;
  566.  surfs.insert(value_type(name, item));
  567.  
  568.  return true;
  569. }
  570.  
  571. bool lwFileSaver::setSurfColr(const char* name, real32 r, real32 g, real32 b)
  572. {
  573.  // validate
  574.  using namespace std;
  575.  if(!name) return error("setSurfColor: Invalid surface name.");
  576.  if(!strlen(name)) return error("setSurfColor: Invalid surface name.");
  577.  
  578.  // find surface
  579.  map<string, lwSURF>::iterator iter = surfs.find(name);
  580.  if(iter == surfs.end()) return error("setSurfColor: Surface name does not exist.");
  581.  
  582.  // set color
  583.  iter->second.flags |= LWO_SURF_FLAGS_COLR;
  584.  iter->second.colr[0] = r;
  585.  iter->second.colr[1] = g;
  586.  iter->second.colr[2] = b;
  587.  
  588.  return true;
  589. }
  590.  
  591. bool lwFileSaver::setSurfDiff(const char* name, real32 intensity)
  592. {
  593.  // validate
  594.  using namespace std;
  595.  if(!name) return error("Invalid surface name.");
  596.  if(!strlen(name)) return error("Invalid surface name.");
  597.  
  598.  // find surface
  599.  map<string, lwSURF>::iterator iter = surfs.find(name);
  600.  if(iter == surfs.end()) return error("Surface name does not exist.");
  601.  
  602.  // set color
  603.  iter->second.flags |= LWO_SURF_FLAGS_DIFF;
  604.  iter->second.diff = intensity;
  605.  
  606.  return true;
  607. }
  608.  
  609. bool lwFileSaver::setSurfSpec(const char* name, real32 intensity)
  610. {
  611.  // validate
  612.  using namespace std;
  613.  if(!name) return error("Invalid surface name.");
  614.  if(!strlen(name)) return error("Invalid surface name.");
  615.  
  616.  // find surface
  617.  map<string, lwSURF>::iterator iter = surfs.find(name);
  618.  if(iter == surfs.end()) return error("Surface name does not exist.");
  619.  
  620.  // set color
  621.  iter->second.flags |= LWO_SURF_FLAGS_SPEC;
  622.  iter->second.spec = intensity;
  623.  
  624.  return true;
  625. }
  626.  
  627. bool lwFileSaver::setSurfTran(const char* name, real32 intensity)
  628. {
  629.  // validate
  630.  using namespace std;
  631.  if(!name) return error("Invalid surface name.");
  632.  if(!strlen(name)) return error("Invalid surface name.");
  633.  
  634.  // find surface
  635.  map<string, lwSURF>::iterator iter = surfs.find(name);
  636.  if(iter == surfs.end()) return error("Surface name does not exist.");
  637.  
  638.  // set color
  639.  iter->second.flags |= LWO_SURF_FLAGS_TRAN;
  640.  iter->second.tran = intensity;
  641.  
  642.  return true;
  643. }
  644.  
  645. bool lwFileSaver::enableSurfColrImag(const char* name)
  646. {
  647.  // validate
  648.  using namespace std;
  649.  if(!name) return error("Invalid surface name.");
  650.  if(!strlen(name)) return error("Invalid surface name.");
  651.  
  652.  // find surface
  653.  map<string, lwSURF>::iterator iter = surfs.find(name);
  654.  if(iter == surfs.end()) return error("Surface name does not exist.");
  655.  
  656.  // texture channel already enabled
  657.  if(iter->second.flags & LWO_SURF_FLAGS_COLR_BLOK) return true;
  658.  
  659.  // set default PROJ
  660.  iter->second.colr_map.proj.chunksize = 0x02;
  661.  iter->second.colr_map.proj.mode = 0x05;
  662.  
  663.  // set default AXIS
  664.  iter->second.colr_map.axis.chunksize = 0x02;
  665.  iter->second.colr_map.axis.axis = 0x02;
  666.  
  667.  // set default IMAG
  668.  iter->second.colr_map.imag.chunksize = 0x00;
  669.  iter->second.colr_map.imag.clipindex = 0;
  670.  
  671.  // set default WRAP
  672.  iter->second.colr_map.wrap.chunksize = 0x04;
  673.  iter->second.colr_map.wrap.wrap_w = 1; // REPEAT
  674.  iter->second.colr_map.wrap.wrap_h = 1; // REPEAT
  675.  
  676.  // set default VMAP
  677.  iter->second.colr_map.vmap.chunksize = 0x00;
  678.  iter->second.colr_map.vmap.name = "";
  679.  
  680.  // set default AAST
  681.  iter->second.colr_map.aast.chunksize = 0x06;
  682.  iter->second.colr_map.aast.flags = 0x01;
  683.  iter->second.colr_map.aast.strength = 1.0f;
  684.  
  685.  // set default PIXB
  686.  iter->second.colr_map.pixb.chunksize = 0x02;
  687.  iter->second.colr_map.pixb.flags = 0x01;
  688.  
  689.  // set default IMAP
  690.  iter->second.colr_map.imap.chunksize = 0x0;
  691.  iter->second.colr_map.imap.chunksize += 0x02; // ordinal
  692.  iter->second.colr_map.imap.chunksize += 0x0A; // CHAN chunk
  693.  iter->second.colr_map.imap.chunksize += 0x08; // ENAB chunk
  694.  iter->second.colr_map.imap.chunksize += 0x08; // NEGA chunk
  695.  iter->second.colr_map.imap.chunksize += 0x0E; // OPAC chunk
  696.  iter->second.colr_map.imap.chunksize += 0x08; // AXIS chunk
  697.  
  698.  // set default IMAP:CHAN
  699.  iter->second.colr_map.imap.chan.chunksize = 0x04;
  700.  iter->second.colr_map.imap.chan.channel = LWO_COLR;
  701.  
  702.  // set default IMAP:ENAB
  703.  iter->second.colr_map.imap.enab.chunksize = 0x02;
  704.  iter->second.colr_map.imap.enab.enable = 0x01;
  705.  
  706.  // set default IMAP:NEGA
  707.  iter->second.colr_map.imap.nega.chunksize = 0x02;
  708.  iter->second.colr_map.imap.nega.enable = 0x00;
  709.  
  710.  // set default IMAP:OPAC
  711.  iter->second.colr_map.imap.opac.chunksize = 0x08;
  712.  iter->second.colr_map.imap.opac.type = 0x07;
  713.  iter->second.colr_map.imap.opac.opacity = 1.0f;
  714.  
  715.  // set default IMAP:AXIS
  716.  iter->second.colr_map.imap.axis.chunksize = 0x02;
  717.  iter->second.colr_map.imap.axis.axis = 0x01; 
  718.  
  719.  // set defalut TMAP
  720.  iter->second.colr_map.tmap.chunksize = 0x0;
  721.  iter->second.colr_map.tmap.chunksize += 0x14; // CNTR chunk
  722.  iter->second.colr_map.tmap.chunksize += 0x14; // SIZE chunk
  723.  iter->second.colr_map.tmap.chunksize += 0x14; // ROTA chunk
  724.  iter->second.colr_map.tmap.chunksize += 0x16; // FALL chunk
  725.  iter->second.colr_map.tmap.chunksize += 0x08; // CSYS chunk
  726.  
  727.  // set default TMAP:CNTR
  728.  iter->second.colr_map.tmap.cntr.chunksize = 0x0E;
  729.  iter->second.colr_map.tmap.cntr.x = 0.0f;
  730.  iter->second.colr_map.tmap.cntr.y = 0.0f;
  731.  iter->second.colr_map.tmap.cntr.z = 0.0f;
  732.  
  733.  // set default TMAP:SIZE
  734.  iter->second.colr_map.tmap.size.chunksize = 0x0E;
  735.  iter->second.colr_map.tmap.size.x = 0.0f;
  736.  iter->second.colr_map.tmap.size.y = 0.0f;
  737.  iter->second.colr_map.tmap.size.z = 0.0f;
  738.  
  739.  // set default TMAP:ROTA
  740.  iter->second.colr_map.tmap.rota.chunksize = 0x0E;
  741.  iter->second.colr_map.tmap.rota.x = 0.0f;
  742.  iter->second.colr_map.tmap.rota.y = 0.0f;
  743.  iter->second.colr_map.tmap.rota.z = 0.0f;
  744.  
  745.  // set default TMAP:FALL
  746.  iter->second.colr_map.tmap.fall.chunksize = 0x10;
  747.  iter->second.colr_map.tmap.fall.type = 0;
  748.  iter->second.colr_map.tmap.fall.x = 0.0f;
  749.  iter->second.colr_map.tmap.fall.y = 0.0f;
  750.  iter->second.colr_map.tmap.fall.z = 0.0f;
  751.  
  752.  // set default TMAP:CSYS
  753.  iter->second.colr_map.tmap.csys.chunksize = 0x02;
  754.  iter->second.colr_map.tmap.csys.type = 0;
  755.  
  756.  // compute BLOK chunksize
  757.  iter->second.colr_map.chunksize += 0x06 + iter->second.colr_map.imap.chunksize; // IMAP
  758.  iter->second.colr_map.chunksize += 0x06 + iter->second.colr_map.tmap.chunksize; // TMAP
  759.  iter->second.colr_map.chunksize += 0x06 + iter->second.colr_map.proj.chunksize; // PROJ
  760.  iter->second.colr_map.chunksize += 0x06 + iter->second.colr_map.axis.chunksize; // AXIS
  761.  iter->second.colr_map.chunksize += 0x06 + iter->second.colr_map.wrap.chunksize; // WRAP
  762.  iter->second.colr_map.chunksize += 0x06 + iter->second.colr_map.aast.chunksize; // AAST
  763.  iter->second.colr_map.chunksize += 0x06 + iter->second.colr_map.pixb.chunksize; // PIXB
  764.  
  765.  // enable texture channel
  766.  iter->second.chunksize += 0x06 + iter->second.colr_map.chunksize; // BLOK
  767.  iter->second.flags |= LWO_SURF_FLAGS_COLR_BLOK;
  768.  
  769.  return true;
  770. }
  771.  
  772. bool lwFileSaver::enableSurfDiffImag(const char* name)
  773. {
  774.  // validate
  775.  using namespace std;
  776.  if(!name) return error("Invalid surface name.");
  777.  if(!strlen(name)) return error("Invalid surface name.");
  778.  
  779.  // find surface
  780.  map<string, lwSURF>::iterator iter = surfs.find(name);
  781.  if(iter == surfs.end()) return error("Surface name does not exist.");
  782.  
  783.  // texture channel already enabled
  784.  if(iter->second.flags & LWO_SURF_FLAGS_DIFF_BLOK) return true;
  785.  
  786.  // set default PROJ
  787.  iter->second.diff_map.proj.chunksize = 0x02;
  788.  iter->second.diff_map.proj.mode = 0x05;
  789.  
  790.  // set default AXIS
  791.  iter->second.diff_map.axis.chunksize = 0x02;
  792.  iter->second.diff_map.axis.axis = 0x02;
  793.  
  794.  // set default IMAG
  795.  iter->second.diff_map.imag.chunksize = 0x00;
  796.  iter->second.diff_map.imag.clipindex = 0;
  797.  
  798.  // set default WRAP
  799.  iter->second.diff_map.wrap.chunksize = 0x04;
  800.  iter->second.diff_map.wrap.wrap_w = 1; // REPEAT
  801.  iter->second.diff_map.wrap.wrap_h = 1; // REPEAT
  802.  
  803.  // set default VMAP
  804.  iter->second.diff_map.vmap.chunksize = 0x00;
  805.  iter->second.diff_map.vmap.name = "";
  806.  
  807.  // set default AAST
  808.  iter->second.diff_map.aast.chunksize = 0x06;
  809.  iter->second.diff_map.aast.flags = 0x01;
  810.  iter->second.diff_map.aast.strength = 1.0f;
  811.  
  812.  // set default PIXB
  813.  iter->second.diff_map.pixb.chunksize = 0x02;
  814.  iter->second.diff_map.pixb.flags = 0x01;
  815.  
  816.  // set default IMAP
  817.  iter->second.diff_map.imap.chunksize = 0x0;
  818.  iter->second.diff_map.imap.chunksize += 0x02; // ordinal
  819.  iter->second.diff_map.imap.chunksize += 0x0A; // CHAN chunk
  820.  iter->second.diff_map.imap.chunksize += 0x08; // ENAB chunk
  821.  iter->second.diff_map.imap.chunksize += 0x08; // NEGA chunk
  822.  iter->second.diff_map.imap.chunksize += 0x0E; // OPAC chunk
  823.  iter->second.diff_map.imap.chunksize += 0x08; // AXIS chunk
  824.  
  825.  // set default IMAP:CHAN
  826.  iter->second.diff_map.imap.chan.chunksize = 0x04;
  827.  iter->second.diff_map.imap.chan.channel = LWO_DIFF;
  828.  
  829.  // set default IMAP:ENAB
  830.  iter->second.diff_map.imap.enab.chunksize = 0x02;
  831.  iter->second.diff_map.imap.enab.enable = 0x01;
  832.  
  833.  // set default IMAP:NEGA
  834.  iter->second.diff_map.imap.nega.chunksize = 0x02;
  835.  iter->second.diff_map.imap.nega.enable = 0x00;
  836.  
  837.  // set default IMAP:OPAC
  838.  iter->second.diff_map.imap.opac.chunksize = 0x08;
  839.  iter->second.diff_map.imap.opac.type = 0x07;
  840.  iter->second.diff_map.imap.opac.opacity = 1.0f;
  841.  
  842.  // set default IMAP:AXIS
  843.  iter->second.diff_map.imap.axis.chunksize = 0x02;
  844.  iter->second.diff_map.imap.axis.axis = 0x01; 
  845.  
  846.  // set defalut TMAP
  847.  iter->second.diff_map.tmap.chunksize = 0x0;
  848.  iter->second.diff_map.tmap.chunksize += 0x14; // CNTR chunk
  849.  iter->second.diff_map.tmap.chunksize += 0x14; // SIZE chunk
  850.  iter->second.diff_map.tmap.chunksize += 0x14; // ROTA chunk
  851.  iter->second.diff_map.tmap.chunksize += 0x16; // FALL chunk
  852.  iter->second.diff_map.tmap.chunksize += 0x08; // CSYS chunk
  853.  
  854.  // set default TMAP:CNTR
  855.  iter->second.diff_map.tmap.cntr.chunksize = 0x0E;
  856.  iter->second.diff_map.tmap.cntr.x = 0.0f;
  857.  iter->second.diff_map.tmap.cntr.y = 0.0f;
  858.  iter->second.diff_map.tmap.cntr.z = 0.0f;
  859.  
  860.  // set default TMAP:SIZE
  861.  iter->second.diff_map.tmap.size.chunksize = 0x0E;
  862.  iter->second.diff_map.tmap.size.x = 0.0f;
  863.  iter->second.diff_map.tmap.size.y = 0.0f;
  864.  iter->second.diff_map.tmap.size.z = 0.0f;
  865.  
  866.  // set default TMAP:ROTA
  867.  iter->second.diff_map.tmap.rota.chunksize = 0x0E;
  868.  iter->second.diff_map.tmap.rota.x = 0.0f;
  869.  iter->second.diff_map.tmap.rota.y = 0.0f;
  870.  iter->second.diff_map.tmap.rota.z = 0.0f;
  871.  
  872.  // set default TMAP:FALL
  873.  iter->second.diff_map.tmap.fall.chunksize = 0x10;
  874.  iter->second.diff_map.tmap.fall.type = 0;
  875.  iter->second.diff_map.tmap.fall.x = 0.0f;
  876.  iter->second.diff_map.tmap.fall.y = 0.0f;
  877.  iter->second.diff_map.tmap.fall.z = 0.0f;
  878.  
  879.  // set default TMAP:CSYS
  880.  iter->second.diff_map.tmap.csys.chunksize = 0x02;
  881.  iter->second.diff_map.tmap.csys.type = 0;
  882.  
  883.  // compute BLOK chunksize
  884.  iter->second.diff_map.chunksize += 0x06 + iter->second.diff_map.imap.chunksize; // IMAP
  885.  iter->second.diff_map.chunksize += 0x06 + iter->second.diff_map.tmap.chunksize; // TMAP
  886.  iter->second.diff_map.chunksize += 0x06 + iter->second.diff_map.proj.chunksize; // PROJ
  887.  iter->second.diff_map.chunksize += 0x06 + iter->second.diff_map.axis.chunksize; // AXIS
  888.  iter->second.diff_map.chunksize += 0x06 + iter->second.diff_map.wrap.chunksize; // WRAP
  889.  iter->second.diff_map.chunksize += 0x06 + iter->second.diff_map.aast.chunksize; // AAST
  890.  iter->second.diff_map.chunksize += 0x06 + iter->second.diff_map.pixb.chunksize; // PIXB
  891.  
  892.  // enable texture channel
  893.  iter->second.chunksize += 0x06 + iter->second.diff_map.chunksize; // BLOK
  894.  iter->second.flags |= LWO_SURF_FLAGS_DIFF_BLOK;
  895.  
  896.  return true;
  897. }
  898.  
  899. bool lwFileSaver::enableSurfSpecImag(const char* name)
  900. {
  901.  // validate
  902.  using namespace std;
  903.  if(!name) return error("Invalid surface name.");
  904.  if(!strlen(name)) return error("Invalid surface name.");
  905.  
  906.  // find surface
  907.  map<string, lwSURF>::iterator iter = surfs.find(name);
  908.  if(iter == surfs.end()) return error("Surface name does not exist.");
  909.  
  910.  // texture channel already enabled
  911.  if(iter->second.flags & LWO_SURF_FLAGS_SPEC_BLOK) return true;
  912.  
  913.  // set default PROJ
  914.  iter->second.spec_map.proj.chunksize = 0x02;
  915.  iter->second.spec_map.proj.mode = 0x05;
  916.  
  917.  // set default AXIS
  918.  iter->second.spec_map.axis.chunksize = 0x02;
  919.  iter->second.spec_map.axis.axis = 0x02;
  920.  
  921.  // set default IMAG
  922.  iter->second.spec_map.imag.chunksize = 0x00;
  923.  iter->second.spec_map.imag.clipindex = 0;
  924.  
  925.  // set default WRAP
  926.  iter->second.spec_map.wrap.chunksize = 0x04;
  927.  iter->second.spec_map.wrap.wrap_w = 1; // REPEAT
  928.  iter->second.spec_map.wrap.wrap_h = 1; // REPEAT
  929.  
  930.  // set default VMAP
  931.  iter->second.spec_map.vmap.chunksize = 0x00;
  932.  iter->second.spec_map.vmap.name = "";
  933.  
  934.  // set default AAST
  935.  iter->second.spec_map.aast.chunksize = 0x06;
  936.  iter->second.spec_map.aast.flags = 0x01;
  937.  iter->second.spec_map.aast.strength = 1.0f;
  938.  
  939.  // set default PIXB
  940.  iter->second.spec_map.pixb.chunksize = 0x02;
  941.  iter->second.spec_map.pixb.flags = 0x01;
  942.  
  943.  // set default IMAP
  944.  iter->second.spec_map.imap.chunksize = 0x0;
  945.  iter->second.spec_map.imap.chunksize += 0x02; // ordinal
  946.  iter->second.spec_map.imap.chunksize += 0x0A; // CHAN chunk
  947.  iter->second.spec_map.imap.chunksize += 0x08; // ENAB chunk
  948.  iter->second.spec_map.imap.chunksize += 0x08; // NEGA chunk
  949.  iter->second.spec_map.imap.chunksize += 0x0E; // OPAC chunk
  950.  iter->second.spec_map.imap.chunksize += 0x08; // AXIS chunk
  951.  
  952.  // set default IMAP:CHAN
  953.  iter->second.spec_map.imap.chan.chunksize = 0x04;
  954.  iter->second.spec_map.imap.chan.channel = LWO_SPEC;
  955.  
  956.  // set default IMAP:ENAB
  957.  iter->second.spec_map.imap.enab.chunksize = 0x02;
  958.  iter->second.spec_map.imap.enab.enable = 0x01;
  959.  
  960.  // set default IMAP:NEGA
  961.  iter->second.spec_map.imap.nega.chunksize = 0x02;
  962.  iter->second.spec_map.imap.nega.enable = 0x00;
  963.  
  964.  // set default IMAP:OPAC
  965.  iter->second.spec_map.imap.opac.chunksize = 0x08;
  966.  iter->second.spec_map.imap.opac.type = 0x07;
  967.  iter->second.spec_map.imap.opac.opacity = 1.0f;
  968.  
  969.  // set default IMAP:AXIS
  970.  iter->second.spec_map.imap.axis.chunksize = 0x02;
  971.  iter->second.spec_map.imap.axis.axis = 0x01; 
  972.  
  973.  // set defalut TMAP
  974.  iter->second.spec_map.tmap.chunksize = 0x0;
  975.  iter->second.spec_map.tmap.chunksize += 0x14; // CNTR chunk
  976.  iter->second.spec_map.tmap.chunksize += 0x14; // SIZE chunk
  977.  iter->second.spec_map.tmap.chunksize += 0x14; // ROTA chunk
  978.  iter->second.spec_map.tmap.chunksize += 0x16; // FALL chunk
  979.  iter->second.spec_map.tmap.chunksize += 0x08; // CSYS chunk
  980.  
  981.  // set default TMAP:CNTR
  982.  iter->second.spec_map.tmap.cntr.chunksize = 0x0E;
  983.  iter->second.spec_map.tmap.cntr.x = 0.0f;
  984.  iter->second.spec_map.tmap.cntr.y = 0.0f;
  985.  iter->second.spec_map.tmap.cntr.z = 0.0f;
  986.  
  987.  // set default TMAP:SIZE
  988.  iter->second.spec_map.tmap.size.chunksize = 0x0E;
  989.  iter->second.spec_map.tmap.size.x = 0.0f;
  990.  iter->second.spec_map.tmap.size.y = 0.0f;
  991.  iter->second.spec_map.tmap.size.z = 0.0f;
  992.  
  993.  // set default TMAP:ROTA
  994.  iter->second.spec_map.tmap.rota.chunksize = 0x0E;
  995.  iter->second.spec_map.tmap.rota.x = 0.0f;
  996.  iter->second.spec_map.tmap.rota.y = 0.0f;
  997.  iter->second.spec_map.tmap.rota.z = 0.0f;
  998.  
  999.  // set default TMAP:FALL
  1000.  iter->second.spec_map.tmap.fall.chunksize = 0x10;
  1001.  iter->second.spec_map.tmap.fall.type = 0;
  1002.  iter->second.spec_map.tmap.fall.x = 0.0f;
  1003.  iter->second.spec_map.tmap.fall.y = 0.0f;
  1004.  iter->second.spec_map.tmap.fall.z = 0.0f;
  1005.  
  1006.  // set default TMAP:CSYS
  1007.  iter->second.spec_map.tmap.csys.chunksize = 0x02;
  1008.  iter->second.spec_map.tmap.csys.type = 0;
  1009.  
  1010.  // compute BLOK chunksize
  1011.  iter->second.spec_map.chunksize += 0x06 + iter->second.spec_map.imap.chunksize; // IMAP
  1012.  iter->second.spec_map.chunksize += 0x06 + iter->second.spec_map.tmap.chunksize; // TMAP
  1013.  iter->second.spec_map.chunksize += 0x06 + iter->second.spec_map.proj.chunksize; // PROJ
  1014.  iter->second.spec_map.chunksize += 0x06 + iter->second.spec_map.axis.chunksize; // AXIS
  1015.  iter->second.spec_map.chunksize += 0x06 + iter->second.spec_map.wrap.chunksize; // WRAP
  1016.  iter->second.spec_map.chunksize += 0x06 + iter->second.spec_map.aast.chunksize; // AAST
  1017.  iter->second.spec_map.chunksize += 0x06 + iter->second.spec_map.pixb.chunksize; // PIXB
  1018.  
  1019.  // enable texture channel
  1020.  iter->second.chunksize += 0x06 + iter->second.spec_map.chunksize; // BLOK
  1021.  iter->second.flags |= LWO_SURF_FLAGS_SPEC_BLOK;
  1022.  
  1023.  return true;
  1024. }
  1025.  
  1026. bool lwFileSaver::enableSurfTranImag(const char* name)
  1027. {
  1028.  // validate
  1029.  using namespace std;
  1030.  if(!name) return error("Invalid surface name.");
  1031.  if(!strlen(name)) return error("Invalid surface name.");
  1032.  
  1033.  // find surface
  1034.  map<string, lwSURF>::iterator iter = surfs.find(name);
  1035.  if(iter == surfs.end()) return error("Surface name does not exist.");
  1036.  
  1037.  // texture channel already enabled
  1038.  if(iter->second.flags & LWO_SURF_FLAGS_TRAN_BLOK) return true;
  1039.  
  1040.  // set default PROJ
  1041.  iter->second.tran_map.proj.chunksize = 0x02;
  1042.  iter->second.tran_map.proj.mode = 0x05;
  1043.  
  1044.  // set default AXIS
  1045.  iter->second.tran_map.axis.chunksize = 0x02;
  1046.  iter->second.tran_map.axis.axis = 0x02;
  1047.  
  1048.  // set default IMAG
  1049.  iter->second.tran_map.imag.chunksize = 0x00;
  1050.  iter->second.tran_map.imag.clipindex = 0;
  1051.  
  1052.  // set default WRAP
  1053.  iter->second.tran_map.wrap.chunksize = 0x04;
  1054.  iter->second.tran_map.wrap.wrap_w = 1; // REPEAT
  1055.  iter->second.tran_map.wrap.wrap_h = 1; // REPEAT
  1056.  
  1057.  // set default VMAP
  1058.  iter->second.tran_map.vmap.chunksize = 0x00;
  1059.  iter->second.tran_map.vmap.name = "";
  1060.  
  1061.  // set default AAST
  1062.  iter->second.tran_map.aast.chunksize = 0x06;
  1063.  iter->second.tran_map.aast.flags = 0x01;
  1064.  iter->second.tran_map.aast.strength = 1.0f;
  1065.  
  1066.  // set default PIXB
  1067.  iter->second.tran_map.pixb.chunksize = 0x02;
  1068.  iter->second.tran_map.pixb.flags = 0x01;
  1069.  
  1070.  // set default IMAP
  1071.  iter->second.tran_map.imap.chunksize = 0x0;
  1072.  iter->second.tran_map.imap.chunksize += 0x02; // ordinal
  1073.  iter->second.tran_map.imap.chunksize += 0x0A; // CHAN chunk
  1074.  iter->second.tran_map.imap.chunksize += 0x08; // ENAB chunk
  1075.  iter->second.tran_map.imap.chunksize += 0x08; // NEGA chunk
  1076.  iter->second.tran_map.imap.chunksize += 0x0E; // OPAC chunk
  1077.  iter->second.tran_map.imap.chunksize += 0x08; // AXIS chunk
  1078.  
  1079.  // set default IMAP:CHAN
  1080.  iter->second.tran_map.imap.chan.chunksize = 0x04;
  1081.  iter->second.tran_map.imap.chan.channel = LWO_TRAN;
  1082.  
  1083.  // set default IMAP:ENAB
  1084.  iter->second.tran_map.imap.enab.chunksize = 0x02;
  1085.  iter->second.tran_map.imap.enab.enable = 0x01;
  1086.  
  1087.  // set default IMAP:NEGA
  1088.  iter->second.tran_map.imap.nega.chunksize = 0x02;
  1089.  iter->second.tran_map.imap.nega.enable = 0x00;
  1090.  
  1091.  // set default IMAP:OPAC
  1092.  iter->second.tran_map.imap.opac.chunksize = 0x08;
  1093.  iter->second.tran_map.imap.opac.type = 0x07;
  1094.  iter->second.tran_map.imap.opac.opacity = 1.0f;
  1095.  
  1096.  // set default IMAP:AXIS
  1097.  iter->second.tran_map.imap.axis.chunksize = 0x02;
  1098.  iter->second.tran_map.imap.axis.axis = 0x01; 
  1099.  
  1100.  // set defalut TMAP
  1101.  iter->second.tran_map.tmap.chunksize = 0x0;
  1102.  iter->second.tran_map.tmap.chunksize += 0x14; // CNTR chunk
  1103.  iter->second.tran_map.tmap.chunksize += 0x14; // SIZE chunk
  1104.  iter->second.tran_map.tmap.chunksize += 0x14; // ROTA chunk
  1105.  iter->second.tran_map.tmap.chunksize += 0x16; // FALL chunk
  1106.  iter->second.tran_map.tmap.chunksize += 0x08; // CSYS chunk
  1107.  
  1108.  // set default TMAP:CNTR
  1109.  iter->second.tran_map.tmap.cntr.chunksize = 0x0E;
  1110.  iter->second.tran_map.tmap.cntr.x = 0.0f;
  1111.  iter->second.tran_map.tmap.cntr.y = 0.0f;
  1112.  iter->second.tran_map.tmap.cntr.z = 0.0f;
  1113.  
  1114.  // set default TMAP:SIZE
  1115.  iter->second.tran_map.tmap.size.chunksize = 0x0E;
  1116.  iter->second.tran_map.tmap.size.x = 0.0f;
  1117.  iter->second.tran_map.tmap.size.y = 0.0f;
  1118.  iter->second.tran_map.tmap.size.z = 0.0f;
  1119.  
  1120.  // set default TMAP:ROTA
  1121.  iter->second.tran_map.tmap.rota.chunksize = 0x0E;
  1122.  iter->second.tran_map.tmap.rota.x = 0.0f;
  1123.  iter->second.tran_map.tmap.rota.y = 0.0f;
  1124.  iter->second.tran_map.tmap.rota.z = 0.0f;
  1125.  
  1126.  // set default TMAP:FALL
  1127.  iter->second.tran_map.tmap.fall.chunksize = 0x10;
  1128.  iter->second.tran_map.tmap.fall.type = 0;
  1129.  iter->second.tran_map.tmap.fall.x = 0.0f;
  1130.  iter->second.tran_map.tmap.fall.y = 0.0f;
  1131.  iter->second.tran_map.tmap.fall.z = 0.0f;
  1132.  
  1133.  // set default TMAP:CSYS
  1134.  iter->second.tran_map.tmap.csys.chunksize = 0x02;
  1135.  iter->second.tran_map.tmap.csys.type = 0;
  1136.  
  1137.  // compute BLOK chunksize
  1138.  iter->second.tran_map.chunksize += 0x06 + iter->second.tran_map.imap.chunksize; // IMAP
  1139.  iter->second.tran_map.chunksize += 0x06 + iter->second.tran_map.tmap.chunksize; // TMAP
  1140.  iter->second.tran_map.chunksize += 0x06 + iter->second.tran_map.proj.chunksize; // PROJ
  1141.  iter->second.tran_map.chunksize += 0x06 + iter->second.tran_map.axis.chunksize; // AXIS
  1142.  iter->second.tran_map.chunksize += 0x06 + iter->second.tran_map.wrap.chunksize; // WRAP
  1143.  iter->second.tran_map.chunksize += 0x06 + iter->second.tran_map.aast.chunksize; // AAST
  1144.  iter->second.tran_map.chunksize += 0x06 + iter->second.tran_map.pixb.chunksize; // PIXB
  1145.  
  1146.  // enable texture channel
  1147.  iter->second.chunksize += 0x06 + iter->second.tran_map.chunksize; // BLOK
  1148.  iter->second.flags |= LWO_SURF_FLAGS_TRAN_BLOK;
  1149.  
  1150.  return true;
  1151. }
  1152.  
  1153. bool lwFileSaver::setSurfVmap(const char* surface, const char* mapname, uint32 type)
  1154. {
  1155.  // validate
  1156.  using namespace std;
  1157.  if(!surface) return error("Invalid surface name.");
  1158.  if(!strlen(surface)) return error("Invalid surface name.");
  1159.  
  1160.  // find surface
  1161.  map<string, lwSURF>::iterator iter = surfs.find(surface);
  1162.  if(iter == surfs.end()) return error("Surface name does not exist.");
  1163.  
  1164.  // texture channel not enabled
  1165.  lwSURF* surf = &(iter->second);
  1166.  if(!(surf->flags & LWO_SURF_FLAGS_COLR_BLOK)) return error("Texture channel not enabled.");
  1167.  
  1168.  // find UV map name
  1169.  if(!hasTxuv(mapname)) return error("UV map name not found.");
  1170.  
  1171.  // set block
  1172.  lwBLOK* blok = nullptr;
  1173.  if(type & LWO_SURF_FLAGS_COLR_BLOK) blok = &(iter->second.colr_map);
  1174.  else if(type & LWO_SURF_FLAGS_DIFF_BLOK) blok = &(iter->second.diff_map);
  1175.  else if(type & LWO_SURF_FLAGS_SPEC_BLOK) blok = &(iter->second.spec_map);
  1176.  else if(type & LWO_SURF_FLAGS_TRAN_BLOK) blok = &(iter->second.tran_map);
  1177.  
  1178.  // adjust chunksizes
  1179.  uint32 prev_vmap_chunksize = blok->vmap.chunksize;
  1180.  if(prev_vmap_chunksize) {
  1181.     blok->chunksize -= prev_vmap_chunksize;
  1182.     surf->chunksize -= prev_vmap_chunksize;
  1183.    }
  1184.  else {
  1185.     blok->chunksize += 0x06;
  1186.     surf->chunksize += 0x06;
  1187.    }
  1188.  
  1189.  // set VMAP data
  1190.  blok->vmap.name = mapname;
  1191.  blok->vmap.chunksize += align02(blok->vmap.name.length() + 1);
  1192.  
  1193.  // adjust chunksizes
  1194.  blok->chunksize += blok->vmap.chunksize;
  1195.  surf->chunksize += blok->vmap.chunksize;
  1196.  
  1197.  return true;
  1198. }
  1199.  
  1200. bool lwFileSaver::setSurfColrVmap(const char* surface, const char* mapname)
  1201. {
  1202.  return setSurfVmap(surface, mapname, LWO_SURF_FLAGS_COLR_BLOK);
  1203. }
  1204.  
  1205. bool lwFileSaver::setSurfDiffVmap(const char* surface, const char* mapname)
  1206. {
  1207.  return setSurfVmap(surface, mapname, LWO_SURF_FLAGS_DIFF_BLOK);
  1208. }
  1209.  
  1210. bool lwFileSaver::setSurfSpecVmap(const char* surface, const char* mapname)
  1211. {
  1212.  return setSurfVmap(surface, mapname, LWO_SURF_FLAGS_SPEC_BLOK);
  1213. }
  1214.  
  1215. bool lwFileSaver::setSurfTranVmap(const char* surface, const char* mapname)
  1216. {
  1217.  return setSurfVmap(surface, mapname, LWO_SURF_FLAGS_TRAN_BLOK);
  1218. }
  1219.  
  1220. bool lwFileSaver::setSurfImag(const char* surface, uint32 clipindex, uint32 type)
  1221. {
  1222.  // validate
  1223.  using namespace std;
  1224.  if(!surface) return error("Invalid surface name.");
  1225.  if(!strlen(surface)) return error("Invalid surface name.");
  1226.  if(!clipindex) return error("Invalid clip index.");
  1227.  
  1228.  // find surface
  1229.  map<string, lwSURF>::iterator iter = surfs.find(surface);
  1230.  if(iter == surfs.end()) return error("Surface name does not exist.");
  1231.  
  1232.  // texture channel not enabled
  1233.  lwSURF* surf = &(iter->second);
  1234.  if(!(surf->flags & type)) return error("Texture channel not enabled.");
  1235.  
  1236.  // find clip index
  1237.  map<uint32, lwCLIP>::iterator clipiter = clips.find(clipindex);
  1238.  if(clipiter == clips.end()) return error("Clip index not found.");
  1239.  
  1240.  // set block
  1241.  lwBLOK* blok = nullptr;
  1242.  if(type & LWO_SURF_FLAGS_COLR_BLOK) blok = &(iter->second.colr_map);
  1243.  else if(type & LWO_SURF_FLAGS_DIFF_BLOK) blok = &(iter->second.diff_map);
  1244.  else if(type & LWO_SURF_FLAGS_SPEC_BLOK) blok = &(iter->second.spec_map);
  1245.  else if(type & LWO_SURF_FLAGS_TRAN_BLOK) blok = &(iter->second.tran_map);
  1246.  
  1247.  // adjust chunksizes
  1248.  uint32 prev_imag_chunksize = blok->imag.chunksize;
  1249.  if(prev_imag_chunksize) {
  1250.     blok->chunksize -= prev_imag_chunksize;
  1251.     surf->chunksize -= prev_imag_chunksize;
  1252.    }
  1253.  else {
  1254.     blok->chunksize += 0x06;
  1255.     surf->chunksize += 0x06;
  1256.    }
  1257.  
  1258.  // set IMAG data
  1259.  blok->imag.clipindex = clipindex;
  1260.  blok->imag.chunksize += GetVXBytes(clipindex);
  1261.  
  1262.  // adjust chunksizes
  1263.  blok->chunksize += blok->imag.chunksize;
  1264.  surf->chunksize += blok->imag.chunksize;
  1265.  
  1266.  return true;
  1267. }
  1268.  
  1269. bool lwFileSaver::setSurfColrImag(const char* surface, uint32 clipindex)
  1270. {
  1271.  return setSurfImag(surface, clipindex, LWO_SURF_FLAGS_COLR_BLOK);
  1272. }
  1273.  
  1274. bool lwFileSaver::setSurfDiffImag(const char* surface, uint32 clipindex)
  1275. {
  1276.  return setSurfImag(surface, clipindex, LWO_SURF_FLAGS_DIFF_BLOK);
  1277. }
  1278.  
  1279. bool lwFileSaver::setSurfSpecImag(const char* surface, uint32 clipindex)
  1280. {
  1281.  return setSurfImag(surface, clipindex, LWO_SURF_FLAGS_SPEC_BLOK);
  1282. }
  1283.  
  1284. bool lwFileSaver::setSurfTranImag(const char* surface, uint32 clipindex)
  1285. {
  1286.  return setSurfImag(surface, clipindex, LWO_SURF_FLAGS_TRAN_BLOK);
  1287. }
  1288.  
  1289. bool lwFileSaver::setSurfNega(const char* surface, uint16 state, uint32 type)
  1290. {
  1291.  // validate
  1292.  using namespace std;
  1293.  if(!surface) return error("Invalid surface name.");
  1294.  if(!strlen(surface)) return error("Invalid surface name.");
  1295.  
  1296.  // find surface
  1297.  map<string, lwSURF>::iterator iter = surfs.find(surface);
  1298.  if(iter == surfs.end()) return error("Surface name does not exist.");
  1299.  
  1300.  // texture channel not enabled
  1301.  lwSURF* surf = &(iter->second);
  1302.  if(!(surf->flags & type)) return error("Texture channel not enabled.");
  1303.  
  1304.  // set block
  1305.  lwBLOK* blok = nullptr;
  1306.  if(type & LWO_SURF_FLAGS_COLR_BLOK) blok = &(iter->second.colr_map);
  1307.  else if(type & LWO_SURF_FLAGS_DIFF_BLOK) blok = &(iter->second.diff_map);
  1308.  else if(type & LWO_SURF_FLAGS_SPEC_BLOK) blok = &(iter->second.spec_map);
  1309.  else if(type & LWO_SURF_FLAGS_TRAN_BLOK) blok = &(iter->second.tran_map);
  1310.  
  1311.  // set NEGA data
  1312.  blok->imap.nega.enable = state;
  1313.  return true;
  1314. }
  1315.  
  1316. bool lwFileSaver::setSurfColrNega(const char* surface, uint16 state)
  1317. {
  1318.  return setSurfNega(surface, state, LWO_SURF_FLAGS_COLR_BLOK);
  1319. }
  1320.  
  1321. bool lwFileSaver::setSurfDiffNega(const char* surface, uint16 state)
  1322. {
  1323.  return setSurfNega(surface, state, LWO_SURF_FLAGS_DIFF_BLOK);
  1324. }
  1325.  
  1326. bool lwFileSaver::setSurfSpecNega(const char* surface, uint16 state)
  1327. {
  1328.  return setSurfNega(surface, state, LWO_SURF_FLAGS_SPEC_BLOK);
  1329. }
  1330.  
  1331. bool lwFileSaver::setSurfTranNega(const char* surface, uint16 state)
  1332. {
  1333.  return setSurfNega(surface, state, LWO_SURF_FLAGS_TRAN_BLOK);
  1334. }
  1335.  
  1336. bool lwFileSaver::save(const char* filename)const
  1337. {
  1338.  // create file
  1339.  using namespace std;
  1340.  ofstream ofile(filename, ios::binary);
  1341.  if(!ofile) return error("Failed to create lwo file.");
  1342.  
  1343.  //
  1344.  // COMPUTE FORM CHUNKSIZE
  1345.  //
  1346.  
  1347.  // keep track of FORM chunksize
  1348.  uint32 FORM_chunksize = 0;
  1349.  FORM_chunksize += 0x04; // LWO2
  1350.  
  1351.  // TAGS contribution
  1352.  if(tags.chunksize) {
  1353.      FORM_chunksize += 0x08;
  1354.      FORM_chunksize += tags.chunksize;
  1355.    }
  1356.  
  1357.  // CLIP contribution
  1358.  for(map<uint32, lwCLIP>::const_iterator i = clips.begin(); i != clips.end(); i++) {
  1359.      FORM_chunksize += 0x08;
  1360.      FORM_chunksize += i->second.chunksize;
  1361.     }
  1362.  
  1363.  // LAYR contribution
  1364.  for(map<uint16, lwLAYR>::const_iterator i = layrs.begin(); i != layrs.end(); i++)
  1365.     {
  1366.      FORM_chunksize += 0x08;
  1367.      FORM_chunksize += i->second.chunksize;
  1368.  
  1369.      // PNTS contribution
  1370.      for(map<uint16, lwPNTS>::const_iterator j = i->second.pntss.begin(); j != i->second.pntss.end(); j++)
  1371.         {
  1372.          FORM_chunksize += 0x08;
  1373.          FORM_chunksize += j->second.chunksize;
  1374.          // TXUV contribution
  1375.          for(map<string, lwTXUV>::const_iterator k = j->second.txuv.begin(); k != j->second.txuv.end(); k++) {
  1376.              FORM_chunksize += 0x08;
  1377.              FORM_chunksize += k->second.chunksize;
  1378.             }
  1379.          // WGHT contribution
  1380.          for(map<string, lwWGHT>::const_iterator k = j->second.wght.begin(); k != j->second.wght.end(); k++) {
  1381.              FORM_chunksize += 0x08;
  1382.              FORM_chunksize += k->second.chunksize;
  1383.             }
  1384.          // MORF contribution
  1385.          for(map<string, lwMORF>::const_iterator k = j->second.morf.begin(); k != j->second.morf.end(); k++) {
  1386.              FORM_chunksize += 0x08;
  1387.              FORM_chunksize += k->second.chunksize;
  1388.             }
  1389.          // POLS contribution
  1390.          for(size_t faceindex = 0; faceindex < j->second.face.size(); faceindex++)
  1391.             {
  1392.              // POLS[faceindex]:FACE contribution
  1393.              if(j->second.face[faceindex].chunksize) {
  1394.                 FORM_chunksize += 0x08;
  1395.                 FORM_chunksize += j->second.face[faceindex].chunksize;
  1396.                }
  1397.              // PTAG[faceindex]:SURF contribution
  1398.              if(j->second.face[faceindex].surf.chunksize) {
  1399.                 FORM_chunksize += 0x08;
  1400.                 FORM_chunksize += j->second.face[faceindex].surf.chunksize;
  1401.                }
  1402.             }
  1403.         }
  1404.  
  1405.      // JNTS contribution
  1406.      for(map<uint16, lwJNTS>::const_iterator j = i->second.jntss.begin(); j != i->second.jntss.end(); j++)
  1407.         {
  1408.          // JNTS contribution
  1409.          FORM_chunksize += 0x08;
  1410.          FORM_chunksize += j->second.chunksize;
  1411.  
  1412.          // SKEL contribution
  1413.          for(size_t skelindex = 0; skelindex < j->second.skel.size(); skelindex++)
  1414.             {
  1415.              // POLS[skelindex]:BONE contribution
  1416.              if(j->second.skel[skelindex].chunksize) {
  1417.                 FORM_chunksize += 0x08;
  1418.                 FORM_chunksize += j->second.skel[skelindex].chunksize;
  1419.                }
  1420.              // PTAG[skelindex]:SURF contribution
  1421.              if(j->second.skel[skelindex].stag.chunksize) {
  1422.                 FORM_chunksize += 0x08;
  1423.                 FORM_chunksize += j->second.skel[skelindex].stag.chunksize;
  1424.                }
  1425.              // PTAG[skelindex]:BONE contribution
  1426.              if(j->second.skel[skelindex].btag.chunksize) {
  1427.                 FORM_chunksize += 0x08;
  1428.                 FORM_chunksize += j->second.skel[skelindex].btag.chunksize;
  1429.                }
  1430.              // PTAG[skelindex]:PART contribution
  1431.              if(j->second.skel[skelindex].ptag.chunksize) {
  1432.                 FORM_chunksize += 0x08;
  1433.                 FORM_chunksize += j->second.skel[skelindex].ptag.chunksize;
  1434.                }
  1435.              // PTAG[skelindex]:BNUP contribution
  1436.              if(j->second.skel[skelindex].utag.chunksize) {
  1437.                 FORM_chunksize += 0x08;
  1438.                 FORM_chunksize += j->second.skel[skelindex].utag.chunksize;
  1439.                }
  1440.             }
  1441.         }
  1442.     }
  1443.  
  1444.  // SURF contribution
  1445.  for(map<string, lwSURF>::const_iterator i = surfs.begin(); i != surfs.end(); i++) {
  1446.      FORM_chunksize += 0x08;
  1447.      FORM_chunksize += i->second.chunksize;
  1448.     }
  1449.  
  1450.  //
  1451.  // SAVE DATA
  1452.  //
  1453.  
  1454.  // save FORM + FORM_chunksize + LWO2
  1455.  BE_write_uint32(ofile, LWO_FORM);
  1456.  BE_write_uint32(ofile, FORM_chunksize);
  1457.  BE_write_uint32(ofile, LWO_LWO2);
  1458.  
  1459.  // save TAGS data
  1460.  uint32 n_tags = tags.currindex;
  1461.  if(tags.chunksize && n_tags)
  1462.    {
  1463.     // construct TAGS data
  1464.     typedef boost::bimap<uint16, string>::const_iterator bmiterator;
  1465.     vector<string> tagdata(n_tags);
  1466.     for(bmiterator i = tags.surftags.begin(); i != tags.surftags.end(); i++) tagdata[i->left] = i->right;
  1467.     for(bmiterator i = tags.bonetags.begin(); i != tags.bonetags.end(); i++) tagdata[i->left] = i->right;
  1468.     for(bmiterator i = tags.parttags.begin(); i != tags.parttags.end(); i++) tagdata[i->left] = i->right;
  1469.     for(bmiterator i = tags.bnuptags.begin(); i != tags.bnuptags.end(); i++) tagdata[i->left] = i->right;
  1470.    
  1471.     // save TAGS data
  1472.     BE_write_uint32(ofile, LWO_TAGS);
  1473.     BE_write_uint32(ofile, tags.chunksize);
  1474.     for(uint32 i = 0; i < n_tags; i++) write_aligned_string_02(ofile, tagdata[i].c_str());
  1475.    }
  1476.  
  1477.  // save CLIP data
  1478.  for(map<uint32, lwCLIP>::const_iterator i = clips.begin(); i != clips.end(); i++)
  1479.     {
  1480.      // CLIP
  1481.      BE_write_uint32(ofile, LWO_CLIP);
  1482.      BE_write_uint32(ofile, i->second.chunksize);
  1483.      BE_write_uint32(ofile, i->first);
  1484.  
  1485.      // STIL
  1486.      BE_write_uint32(ofile, LWO_STIL);
  1487.      BE_write_uint16(ofile, (uint16)align02(i->second.filename.length() + 1));
  1488.      write_aligned_string_02(ofile, i->second.filename.c_str());
  1489.  
  1490.      // FLAGS subchunk
  1491.      BE_write_uint32(ofile, LWO_FLAG);
  1492.      BE_write_uint16(ofile, 0x0004);
  1493.      BE_write_uint16(ofile, 0x0800);
  1494.      BE_write_uint16(ofile, 0x0080);
  1495.     }
  1496.  
  1497.  // save LAYR data
  1498.  for(map<uint16, lwLAYR>::const_iterator i = layrs.begin(); i != layrs.end(); i++)
  1499.     {
  1500.      // save LAYR chunk
  1501.      BE_write_uint32(ofile, LWO_LAYR); // LAYR
  1502.      BE_write_uint32(ofile, i->second.chunksize); // chunksize
  1503.      BE_write_uint16(ofile, i->first); // number
  1504.      BE_write_uint16(ofile, i->second.flags); // flags
  1505.      BE_write_real32(ofile, i->second.pivot_x); // pivot
  1506.      BE_write_real32(ofile, i->second.pivot_y); // pivot
  1507.      BE_write_real32(ofile, i->second.pivot_z); // pivot
  1508.      if(i->second.name.length()) write_aligned_string_02(ofile, i->second.name.c_str()); // name
  1509.      else BE_write_uint16(ofile, 0); // name
  1510.  
  1511.      // save PNTS
  1512.      const map<uint16, lwPNTS>& pmap = i->second.pntss;
  1513.      for(map<uint16, lwPNTS>::const_iterator j = pmap.begin(); j != pmap.end(); j++)
  1514.         {
  1515.          // save PNTS chunk
  1516.          BE_write_uint32(ofile, LWO_PNTS); // PNTS
  1517.          BE_write_uint32(ofile, j->second.chunksize); // chunksize
  1518.          for(uint32 index = 0; index < j->second.elem; index++) { // data
  1519.              BE_write_real32(ofile, j->second.data[index].x); // x
  1520.              BE_write_real32(ofile, j->second.data[index].y); // y
  1521.              BE_write_real32(ofile, j->second.data[index].z); // z
  1522.             }
  1523.  
  1524.          // save TXUV data
  1525.          for(map<string, lwTXUV>::const_iterator k = j->second.txuv.begin(); k != j->second.txuv.end(); k++)
  1526.             {
  1527.              // save VMAP chunk
  1528.              BE_write_uint32(ofile, LWO_VMAP); // VMAP
  1529.              BE_write_uint32(ofile, k->second.chunksize); // chunksize
  1530.              BE_write_uint32(ofile, LWO_TXUV); // TXUV
  1531.              BE_write_uint16(ofile, 2); // dimension
  1532.              write_aligned_string_02(ofile, k->first.c_str()); // name
  1533.              for(uint32 index = 0; index < k->second.elem; index++) {
  1534.                  WriteVX(ofile, k->second.data[index].reference); // reference
  1535.                  BE_write_real32(ofile, k->second.data[index].x); // x
  1536.                  BE_write_real32(ofile, k->second.data[index].y); // y
  1537.                 }
  1538.             }
  1539.  
  1540.          // save WGHT data
  1541.          for(map<string, lwWGHT>::const_iterator k = j->second.wght.begin(); k != j->second.wght.end(); k++)
  1542.             {
  1543.              // save VMAP chunk
  1544.              BE_write_uint32(ofile, LWO_VMAP); // VMAP
  1545.              BE_write_uint32(ofile, k->second.chunksize); // chunksize
  1546.              BE_write_uint32(ofile, LWO_WGHT); // WGHT
  1547.              BE_write_uint16(ofile, 1); // dimension
  1548.              write_aligned_string_02(ofile, k->first.c_str()); // name
  1549.              for(uint32 index = 0; index < k->second.elem; index++) {
  1550.                  WriteVX(ofile, k->second.data[index].reference); // reference
  1551.                  BE_write_real32(ofile, k->second.data[index].x); // x
  1552.                 }
  1553.             }
  1554.  
  1555.          // save MORF data
  1556.          for(map<string, lwMORF>::const_iterator k = j->second.morf.begin(); k != j->second.morf.end(); k++)
  1557.             {
  1558.              // save VMAP chunk
  1559.              BE_write_uint32(ofile, LWO_VMAP); // VMAP
  1560.              BE_write_uint32(ofile, k->second.chunksize); // chunksize
  1561.              BE_write_uint32(ofile, LWO_MORF); // MORF
  1562.              BE_write_uint16(ofile, 3); // dimension
  1563.              write_aligned_string_02(ofile, k->first.c_str()); // name
  1564.              for(uint32 index = 0; index < k->second.elem; index++) {
  1565.                  WriteVX(ofile, k->second.data[index].reference); // reference
  1566.                  BE_write_real32(ofile, k->second.data[index].x); // x
  1567.                  BE_write_real32(ofile, k->second.data[index].y); // y
  1568.                  BE_write_real32(ofile, k->second.data[index].z); // z
  1569.                 }
  1570.             }
  1571.  
  1572.          // save POLS data
  1573.          for(size_t faceindex = 0; faceindex < j->second.face.size(); faceindex++)
  1574.             {
  1575.              // save POLS data
  1576.              const lwPOLS& pols = j->second.face[faceindex];
  1577.              if(pols.chunksize) {
  1578.                 BE_write_uint32(ofile, LWO_POLS);
  1579.                 BE_write_uint32(ofile, pols.chunksize);
  1580.                 BE_write_uint32(ofile, LWO_FACE);
  1581.                 for(uint32 index = 0; index < pols.elem; index++) {
  1582.                     BE_write_uint16(ofile, 3);
  1583.                     WriteVX(ofile, pols.data[index].a);
  1584.                     WriteVX(ofile, pols.data[index].b);
  1585.                     WriteVX(ofile, pols.data[index].c);
  1586.                    }
  1587.                }
  1588.  
  1589.              // save PTAG:SURF data
  1590.              const lwPTAG& ptag = pols.surf;
  1591.              if(ptag.chunksize) {
  1592.                 BE_write_uint32(ofile, LWO_PTAG);
  1593.                 BE_write_uint32(ofile, ptag.chunksize);
  1594.                 BE_write_uint32(ofile, ptag.type);
  1595.                 for(map<uint32, uint16>::const_iterator k = ptag.tags.begin(); k != ptag.tags.end(); k++) {
  1596.                     WriteVX(ofile, k->first);
  1597.                     BE_write_uint16(ofile, k->second);
  1598.                    }
  1599.                }
  1600.             }
  1601.         }
  1602.  
  1603.      // save JNTS
  1604.      const map<uint16, lwJNTS>& jmap = i->second.jntss;
  1605.      for(map<uint16, lwJNTS>::const_iterator j = jmap.begin(); j != jmap.end(); j++)
  1606.         {
  1607.          // save PNTS chunk
  1608.          BE_write_uint32(ofile, LWO_PNTS); // PNTS
  1609.          BE_write_uint32(ofile, j->second.chunksize); // chunksize
  1610.          for(uint32 index = 0; index < j->second.elem; index++) { // data
  1611.              BE_write_real32(ofile, j->second.data[index].x); // x
  1612.              BE_write_real32(ofile, j->second.data[index].y); // y
  1613.              BE_write_real32(ofile, j->second.data[index].z); // z
  1614.             }
  1615.  
  1616.          // save SKEL data
  1617.          for(size_t skelindex = 0; skelindex < j->second.skel.size(); skelindex++)
  1618.             {
  1619.              // save SKEL data
  1620.              const lwSKEL& skel = j->second.skel[skelindex];
  1621.              if(skel.chunksize) {
  1622.                 BE_write_uint32(ofile, LWO_POLS); // POLS
  1623.                 BE_write_uint32(ofile, skel.chunksize); // chunksize
  1624.                 BE_write_uint32(ofile, LWO_BONE); // BONE
  1625.                 for(uint32 index = 0; index < skel.elem; index++) { // data
  1626.                     BE_write_uint16(ofile, 2); // vertices
  1627.                     WriteVX(ofile, skel.data[index].a); // a
  1628.                     WriteVX(ofile, skel.data[index].b); // b
  1629.                    }
  1630.                }
  1631.  
  1632.              // save PTAG:SURF data
  1633.              const lwPTAG& stag = skel.stag;
  1634.              if(stag.chunksize) {
  1635.                 BE_write_uint32(ofile, LWO_PTAG);
  1636.                 BE_write_uint32(ofile, stag.chunksize);
  1637.                 BE_write_uint32(ofile, stag.type);
  1638.                 for(map<uint32, uint16>::const_iterator k = stag.tags.begin(); k != stag.tags.end(); k++) {
  1639.                     WriteVX(ofile, k->first);
  1640.                     BE_write_uint16(ofile, k->second);
  1641.                    }
  1642.                }
  1643.  
  1644.              // save PTAG:BONE data
  1645.              const lwPTAG& btag = skel.btag;
  1646.              if(btag.chunksize) {
  1647.                 BE_write_uint32(ofile, LWO_PTAG);
  1648.                 BE_write_uint32(ofile, btag.chunksize);
  1649.                 BE_write_uint32(ofile, btag.type);
  1650.                 for(map<uint32, uint16>::const_iterator k = btag.tags.begin(); k != btag.tags.end(); k++) {
  1651.                     WriteVX(ofile, k->first);
  1652.                     BE_write_uint16(ofile, k->second);
  1653.                    }
  1654.                }
  1655.  
  1656.              // save PTAG:PART data
  1657.              const lwPTAG& ptag = skel.ptag;
  1658.              if(ptag.chunksize) {
  1659.                 BE_write_uint32(ofile, LWO_PTAG);
  1660.                 BE_write_uint32(ofile, ptag.chunksize);
  1661.                 BE_write_uint32(ofile, ptag.type);
  1662.                 for(map<uint32, uint16>::const_iterator k = ptag.tags.begin(); k != ptag.tags.end(); k++) {
  1663.                     WriteVX(ofile, k->first);
  1664.                     BE_write_uint16(ofile, k->second);
  1665.                    }
  1666.                }
  1667.  
  1668.              // save PTAG:BNUP data
  1669.              const lwPTAG& utag = skel.utag;
  1670.              if(utag.chunksize)
  1671.                {
  1672.                }
  1673.             }
  1674.         }
  1675.     }
  1676.  
  1677.  // save SURF data
  1678.  for(map<string, lwSURF>::const_iterator i = surfs.begin(); i != surfs.end(); i++)
  1679.     {
  1680.      // part 1
  1681.      BE_write_uint32(ofile, LWO_SURF); // SURF
  1682.      BE_write_uint32(ofile, i->second.chunksize); // chunksize
  1683.      write_aligned_string_02(ofile, i->first.c_str()); // name
  1684.      BE_write_uint16(ofile, 0); // source
  1685.  
  1686.      // part 2
  1687.      if(i->second.flags & LWO_SURF_FLAGS_COLR) {
  1688.         BE_write_uint32(ofile, LWO_COLR);
  1689.         BE_write_uint16(ofile, 0x0E);
  1690.         BE_write_real32(ofile, i->second.colr[0]);
  1691.         BE_write_real32(ofile, i->second.colr[1]);
  1692.         BE_write_real32(ofile, i->second.colr[2]);
  1693.         BE_write_uint16(ofile, 0x00);
  1694.        }
  1695.      if(i->second.flags & LWO_SURF_FLAGS_DIFF) {
  1696.         BE_write_uint32(ofile, LWO_DIFF);
  1697.         BE_write_uint16(ofile, 0x06);
  1698.         BE_write_real32(ofile, i->second.diff);
  1699.         BE_write_uint16(ofile, 0x00);
  1700.        }
  1701.      if(i->second.flags & LWO_SURF_FLAGS_SPEC) {
  1702.         BE_write_uint32(ofile, LWO_SPEC);
  1703.         BE_write_uint16(ofile, 0x06);
  1704.         BE_write_real32(ofile, i->second.spec);
  1705.         BE_write_uint16(ofile, 0x00);
  1706.        }
  1707.      if(i->second.flags & LWO_SURF_FLAGS_TRAN) {
  1708.         BE_write_uint32(ofile, LWO_TRAN);
  1709.         BE_write_uint16(ofile, 0x06);
  1710.         BE_write_real32(ofile, i->second.tran);
  1711.         BE_write_uint16(ofile, 0x00);
  1712.        }
  1713.  
  1714.      // part 3
  1715.      if(i->second.flags & LWO_SURF_FLAGS_COLR_BLOK)
  1716.        {
  1717.         // BLOK
  1718.         BE_write_uint32(ofile, LWO_BLOK);
  1719.         BE_write_uint16(ofile, i->second.colr_map.chunksize);
  1720.  
  1721.         // BLOK:IMAP
  1722.         BE_write_uint32(ofile, LWO_IMAP);
  1723.         BE_write_uint16(ofile, i->second.colr_map.imap.chunksize);
  1724.         BE_write_uint16(ofile, 0x8000); // constant ordinal
  1725.  
  1726.         // BLOK:IMAP:CHAN
  1727.         BE_write_uint32(ofile, LWO_CHAN);
  1728.         BE_write_uint16(ofile, i->second.colr_map.imap.chan.chunksize);
  1729.         BE_write_uint32(ofile, i->second.colr_map.imap.chan.channel);
  1730.  
  1731.         // BLOK:IMAP:ENAB
  1732.         BE_write_uint32(ofile, LWO_ENAB);
  1733.         BE_write_uint16(ofile, i->second.colr_map.imap.enab.chunksize);
  1734.         BE_write_uint16(ofile, i->second.colr_map.imap.enab.enable);
  1735.  
  1736.         // BLOK:IMAP:NEGA
  1737.         BE_write_uint32(ofile, LWO_NEGA);
  1738.         BE_write_uint16(ofile, i->second.colr_map.imap.nega.chunksize);
  1739.         BE_write_uint16(ofile, i->second.colr_map.imap.nega.enable);
  1740.  
  1741.         // BLOK:IMAP:OPAC
  1742.         BE_write_uint32(ofile, LWO_OPAC);
  1743.         BE_write_uint16(ofile, i->second.colr_map.imap.opac.chunksize);
  1744.         BE_write_uint16(ofile, i->second.colr_map.imap.opac.type);
  1745.         BE_write_real32(ofile, i->second.colr_map.imap.opac.opacity);
  1746.         BE_write_uint16(ofile, 0x00); // envelope
  1747.  
  1748.         // BLOK:IMAP:AXIS
  1749.         BE_write_uint32(ofile, LWO_AXIS);
  1750.         BE_write_uint16(ofile, i->second.colr_map.imap.axis.chunksize);
  1751.         BE_write_uint16(ofile, i->second.colr_map.imap.axis.axis);
  1752.  
  1753.         // BLOK:TMAP
  1754.         uint16 TMAP_chunksize = 0x5A;
  1755.         BE_write_uint32(ofile, LWO_TMAP);
  1756.         BE_write_uint16(ofile, i->second.colr_map.tmap.chunksize);
  1757.  
  1758.         // BLCK:TMAP:CNTR
  1759.         BE_write_uint32(ofile, LWO_CNTR);
  1760.         BE_write_uint16(ofile, i->second.colr_map.tmap.cntr.chunksize);
  1761.         BE_write_real32(ofile, i->second.colr_map.tmap.cntr.x);
  1762.         BE_write_real32(ofile, i->second.colr_map.tmap.cntr.y);
  1763.         BE_write_real32(ofile, i->second.colr_map.tmap.cntr.z);
  1764.         BE_write_uint16(ofile, 0x00); // envelope
  1765.  
  1766.         // BLCK:TMAP:SIZE
  1767.         BE_write_uint32(ofile, LWO_SIZE);
  1768.         BE_write_uint16(ofile, i->second.colr_map.tmap.size.chunksize);
  1769.         BE_write_real32(ofile, i->second.colr_map.tmap.size.x);
  1770.         BE_write_real32(ofile, i->second.colr_map.tmap.size.y);
  1771.         BE_write_real32(ofile, i->second.colr_map.tmap.size.z);
  1772.         BE_write_uint16(ofile, 0x00); // envelope
  1773.  
  1774.         // BLCK:TMAP:ROTA
  1775.         BE_write_uint32(ofile, LWO_ROTA);
  1776.         BE_write_uint16(ofile, i->second.colr_map.tmap.rota.chunksize);
  1777.         BE_write_real32(ofile, i->second.colr_map.tmap.rota.x);
  1778.         BE_write_real32(ofile, i->second.colr_map.tmap.rota.y);
  1779.         BE_write_real32(ofile, i->second.colr_map.tmap.rota.z);
  1780.         BE_write_uint16(ofile, 0x00); // envelope
  1781.  
  1782.         // BLCK:TMAP:FALL
  1783.         BE_write_uint32(ofile, LWO_FALL);
  1784.         BE_write_uint16(ofile, i->second.colr_map.tmap.fall.chunksize);
  1785.         BE_write_uint16(ofile, i->second.colr_map.tmap.fall.type);
  1786.         BE_write_real32(ofile, i->second.colr_map.tmap.fall.x);
  1787.         BE_write_real32(ofile, i->second.colr_map.tmap.fall.y);
  1788.         BE_write_real32(ofile, i->second.colr_map.tmap.fall.z);
  1789.         BE_write_uint16(ofile, 0x00); // envelope
  1790.  
  1791.         // BLCK:TMAP:CSYS
  1792.         BE_write_uint32(ofile, LWO_CSYS);
  1793.         BE_write_uint16(ofile, i->second.colr_map.tmap.csys.chunksize);
  1794.         BE_write_uint16(ofile, i->second.colr_map.tmap.csys.type);
  1795.  
  1796.         // BLCK:PROJ
  1797.         BE_write_uint32(ofile, LWO_PROJ);
  1798.         BE_write_uint16(ofile, i->second.colr_map.proj.chunksize);
  1799.         BE_write_uint16(ofile, i->second.colr_map.proj.mode);
  1800.  
  1801.         // BLCK:AXIS
  1802.         BE_write_uint32(ofile, LWO_AXIS);
  1803.         BE_write_uint16(ofile, i->second.colr_map.axis.chunksize);
  1804.         BE_write_uint16(ofile, i->second.colr_map.axis.axis);
  1805.  
  1806.         // BLCK:IMAG
  1807.         if(i->second.colr_map.imag.chunksize) {
  1808.            BE_write_uint32(ofile, LWO_IMAG);
  1809.            BE_write_uint16(ofile, i->second.colr_map.imag.chunksize);
  1810.            WriteVX(ofile, i->second.colr_map.imag.clipindex);
  1811.           }
  1812.  
  1813.         // BLCK:WRAP
  1814.         BE_write_uint32(ofile, LWO_WRAP);
  1815.         BE_write_uint16(ofile, i->second.colr_map.wrap.chunksize);
  1816.         BE_write_uint16(ofile, i->second.colr_map.wrap.wrap_w);
  1817.         BE_write_uint16(ofile, i->second.colr_map.wrap.wrap_h);
  1818.  
  1819.         // BLCK:VMAP
  1820.         if(i->second.colr_map.vmap.chunksize) {
  1821.            BE_write_uint32(ofile, LWO_VMAP);
  1822.            BE_write_uint16(ofile, i->second.colr_map.vmap.chunksize);
  1823.            write_aligned_string_02(ofile, i->second.colr_map.vmap.name.c_str());
  1824.           }
  1825.  
  1826.         // BLCK:AAST
  1827.         BE_write_uint32(ofile, LWO_AAST);
  1828.         BE_write_uint16(ofile, i->second.colr_map.aast.chunksize);
  1829.         BE_write_uint16(ofile, i->second.colr_map.aast.flags);
  1830.         BE_write_real32(ofile, i->second.colr_map.aast.strength);
  1831.  
  1832.         // BLCK:PIXB
  1833.         BE_write_uint32(ofile, LWO_PIXB);
  1834.         BE_write_uint16(ofile, i->second.colr_map.pixb.chunksize);
  1835.         BE_write_uint16(ofile, i->second.colr_map.pixb.flags);
  1836.        }
  1837.      if(i->second.flags & LWO_SURF_FLAGS_DIFF_BLOK)
  1838.        {
  1839.         // BLOK
  1840.         BE_write_uint32(ofile, LWO_BLOK);
  1841.         BE_write_uint16(ofile, i->second.diff_map.chunksize);
  1842.  
  1843.         // BLOK:IMAP
  1844.         BE_write_uint32(ofile, LWO_IMAP);
  1845.         BE_write_uint16(ofile, i->second.diff_map.imap.chunksize);
  1846.         BE_write_uint16(ofile, 0x8000); // constant ordinal
  1847.  
  1848.         // BLOK:IMAP:CHAN
  1849.         BE_write_uint32(ofile, LWO_CHAN);
  1850.         BE_write_uint16(ofile, i->second.diff_map.imap.chan.chunksize);
  1851.         BE_write_uint32(ofile, i->second.diff_map.imap.chan.channel);
  1852.  
  1853.         // BLOK:IMAP:ENAB
  1854.         BE_write_uint32(ofile, LWO_ENAB);
  1855.         BE_write_uint16(ofile, i->second.diff_map.imap.enab.chunksize);
  1856.         BE_write_uint16(ofile, i->second.diff_map.imap.enab.enable);
  1857.  
  1858.         // BLOK:IMAP:NEGA
  1859.         BE_write_uint32(ofile, LWO_NEGA);
  1860.         BE_write_uint16(ofile, i->second.diff_map.imap.nega.chunksize);
  1861.         BE_write_uint16(ofile, i->second.diff_map.imap.nega.enable);
  1862.  
  1863.         // BLOK:IMAP:OPAC
  1864.         BE_write_uint32(ofile, LWO_OPAC);
  1865.         BE_write_uint16(ofile, i->second.diff_map.imap.opac.chunksize);
  1866.         BE_write_uint16(ofile, i->second.diff_map.imap.opac.type);
  1867.         BE_write_real32(ofile, i->second.diff_map.imap.opac.opacity);
  1868.         BE_write_uint16(ofile, 0x00); // envelope
  1869.  
  1870.         // BLOK:IMAP:AXIS
  1871.         BE_write_uint32(ofile, LWO_AXIS);
  1872.         BE_write_uint16(ofile, i->second.diff_map.imap.axis.chunksize);
  1873.         BE_write_uint16(ofile, i->second.diff_map.imap.axis.axis);
  1874.  
  1875.         // BLOK:TMAP
  1876.         uint16 TMAP_chunksize = 0x5A;
  1877.         BE_write_uint32(ofile, LWO_TMAP);
  1878.         BE_write_uint16(ofile, i->second.diff_map.tmap.chunksize);
  1879.  
  1880.         // BLCK:TMAP:CNTR
  1881.         BE_write_uint32(ofile, LWO_CNTR);
  1882.         BE_write_uint16(ofile, i->second.diff_map.tmap.cntr.chunksize);
  1883.         BE_write_real32(ofile, i->second.diff_map.tmap.cntr.x);
  1884.         BE_write_real32(ofile, i->second.diff_map.tmap.cntr.y);
  1885.         BE_write_real32(ofile, i->second.diff_map.tmap.cntr.z);
  1886.         BE_write_uint16(ofile, 0x00); // envelope
  1887.  
  1888.         // BLCK:TMAP:SIZE
  1889.         BE_write_uint32(ofile, LWO_SIZE);
  1890.         BE_write_uint16(ofile, i->second.diff_map.tmap.size.chunksize);
  1891.         BE_write_real32(ofile, i->second.diff_map.tmap.size.x);
  1892.         BE_write_real32(ofile, i->second.diff_map.tmap.size.y);
  1893.         BE_write_real32(ofile, i->second.diff_map.tmap.size.z);
  1894.         BE_write_uint16(ofile, 0x00); // envelope
  1895.  
  1896.         // BLCK:TMAP:ROTA
  1897.         BE_write_uint32(ofile, LWO_ROTA);
  1898.         BE_write_uint16(ofile, i->second.diff_map.tmap.rota.chunksize);
  1899.         BE_write_real32(ofile, i->second.diff_map.tmap.rota.x);
  1900.         BE_write_real32(ofile, i->second.diff_map.tmap.rota.y);
  1901.         BE_write_real32(ofile, i->second.diff_map.tmap.rota.z);
  1902.         BE_write_uint16(ofile, 0x00); // envelope
  1903.  
  1904.         // BLCK:TMAP:FALL
  1905.         BE_write_uint32(ofile, LWO_FALL);
  1906.         BE_write_uint16(ofile, i->second.diff_map.tmap.fall.chunksize);
  1907.         BE_write_uint16(ofile, i->second.diff_map.tmap.fall.type);
  1908.         BE_write_real32(ofile, i->second.diff_map.tmap.fall.x);
  1909.         BE_write_real32(ofile, i->second.diff_map.tmap.fall.y);
  1910.         BE_write_real32(ofile, i->second.diff_map.tmap.fall.z);
  1911.         BE_write_uint16(ofile, 0x00); // envelope
  1912.  
  1913.         // BLCK:TMAP:CSYS
  1914.         BE_write_uint32(ofile, LWO_CSYS);
  1915.         BE_write_uint16(ofile, i->second.diff_map.tmap.csys.chunksize);
  1916.         BE_write_uint16(ofile, i->second.diff_map.tmap.csys.type);
  1917.  
  1918.         // BLCK:PROJ
  1919.         BE_write_uint32(ofile, LWO_PROJ);
  1920.         BE_write_uint16(ofile, i->second.diff_map.proj.chunksize);
  1921.         BE_write_uint16(ofile, i->second.diff_map.proj.mode);
  1922.  
  1923.         // BLCK:AXIS
  1924.         BE_write_uint32(ofile, LWO_AXIS);
  1925.         BE_write_uint16(ofile, i->second.diff_map.axis.chunksize);
  1926.         BE_write_uint16(ofile, i->second.diff_map.axis.axis);
  1927.  
  1928.         // BLCK:IMAG
  1929.         if(i->second.diff_map.imag.chunksize) {
  1930.            BE_write_uint32(ofile, LWO_IMAG);
  1931.            BE_write_uint16(ofile, i->second.diff_map.imag.chunksize);
  1932.            WriteVX(ofile, i->second.diff_map.imag.clipindex);
  1933.           }
  1934.  
  1935.         // BLCK:WRAP
  1936.         BE_write_uint32(ofile, LWO_WRAP);
  1937.         BE_write_uint16(ofile, i->second.diff_map.wrap.chunksize);
  1938.         BE_write_uint16(ofile, i->second.diff_map.wrap.wrap_w);
  1939.         BE_write_uint16(ofile, i->second.diff_map.wrap.wrap_h);
  1940.  
  1941.         // BLCK:VMAP
  1942.         if(i->second.diff_map.vmap.chunksize) {
  1943.            BE_write_uint32(ofile, LWO_VMAP);
  1944.            BE_write_uint16(ofile, i->second.diff_map.vmap.chunksize);
  1945.            write_aligned_string_02(ofile, i->second.diff_map.vmap.name.c_str());
  1946.           }
  1947.  
  1948.         // BLCK:AAST
  1949.         BE_write_uint32(ofile, LWO_AAST);
  1950.         BE_write_uint16(ofile, i->second.diff_map.aast.chunksize);
  1951.         BE_write_uint16(ofile, i->second.diff_map.aast.flags);
  1952.         BE_write_real32(ofile, i->second.diff_map.aast.strength);
  1953.  
  1954.         // BLCK:PIXB
  1955.         BE_write_uint32(ofile, LWO_PIXB);
  1956.         BE_write_uint16(ofile, i->second.diff_map.pixb.chunksize);
  1957.         BE_write_uint16(ofile, i->second.diff_map.pixb.flags);
  1958.        }
  1959.      if(i->second.flags & LWO_SURF_FLAGS_SPEC_BLOK)
  1960.        {
  1961.         // BLOK
  1962.         BE_write_uint32(ofile, LWO_BLOK);
  1963.         BE_write_uint16(ofile, i->second.spec_map.chunksize);
  1964.  
  1965.         // BLOK:IMAP
  1966.         BE_write_uint32(ofile, LWO_IMAP);
  1967.         BE_write_uint16(ofile, i->second.spec_map.imap.chunksize);
  1968.         BE_write_uint16(ofile, 0x8000); // constant ordinal
  1969.  
  1970.         // BLOK:IMAP:CHAN
  1971.         BE_write_uint32(ofile, LWO_CHAN);
  1972.         BE_write_uint16(ofile, i->second.spec_map.imap.chan.chunksize);
  1973.         BE_write_uint32(ofile, i->second.spec_map.imap.chan.channel);
  1974.  
  1975.         // BLOK:IMAP:ENAB
  1976.         BE_write_uint32(ofile, LWO_ENAB);
  1977.         BE_write_uint16(ofile, i->second.spec_map.imap.enab.chunksize);
  1978.         BE_write_uint16(ofile, i->second.spec_map.imap.enab.enable);
  1979.  
  1980.         // BLOK:IMAP:NEGA
  1981.         BE_write_uint32(ofile, LWO_NEGA);
  1982.         BE_write_uint16(ofile, i->second.spec_map.imap.nega.chunksize);
  1983.         BE_write_uint16(ofile, i->second.spec_map.imap.nega.enable);
  1984.  
  1985.         // BLOK:IMAP:OPAC
  1986.         BE_write_uint32(ofile, LWO_OPAC);
  1987.         BE_write_uint16(ofile, i->second.spec_map.imap.opac.chunksize);
  1988.         BE_write_uint16(ofile, i->second.spec_map.imap.opac.type);
  1989.         BE_write_real32(ofile, i->second.spec_map.imap.opac.opacity);
  1990.         BE_write_uint16(ofile, 0x00); // envelope
  1991.  
  1992.         // BLOK:IMAP:AXIS
  1993.         BE_write_uint32(ofile, LWO_AXIS);
  1994.         BE_write_uint16(ofile, i->second.spec_map.imap.axis.chunksize);
  1995.         BE_write_uint16(ofile, i->second.spec_map.imap.axis.axis);
  1996.  
  1997.         // BLOK:TMAP
  1998.         uint16 TMAP_chunksize = 0x5A;
  1999.         BE_write_uint32(ofile, LWO_TMAP);
  2000.         BE_write_uint16(ofile, i->second.spec_map.tmap.chunksize);
  2001.  
  2002.         // BLCK:TMAP:CNTR
  2003.         BE_write_uint32(ofile, LWO_CNTR);
  2004.         BE_write_uint16(ofile, i->second.spec_map.tmap.cntr.chunksize);
  2005.         BE_write_real32(ofile, i->second.spec_map.tmap.cntr.x);
  2006.         BE_write_real32(ofile, i->second.spec_map.tmap.cntr.y);
  2007.         BE_write_real32(ofile, i->second.spec_map.tmap.cntr.z);
  2008.         BE_write_uint16(ofile, 0x00); // envelope
  2009.  
  2010.         // BLCK:TMAP:SIZE
  2011.         BE_write_uint32(ofile, LWO_SIZE);
  2012.         BE_write_uint16(ofile, i->second.spec_map.tmap.size.chunksize);
  2013.         BE_write_real32(ofile, i->second.spec_map.tmap.size.x);
  2014.         BE_write_real32(ofile, i->second.spec_map.tmap.size.y);
  2015.         BE_write_real32(ofile, i->second.spec_map.tmap.size.z);
  2016.         BE_write_uint16(ofile, 0x00); // envelope
  2017.  
  2018.         // BLCK:TMAP:ROTA
  2019.         BE_write_uint32(ofile, LWO_ROTA);
  2020.         BE_write_uint16(ofile, i->second.spec_map.tmap.rota.chunksize);
  2021.         BE_write_real32(ofile, i->second.spec_map.tmap.rota.x);
  2022.         BE_write_real32(ofile, i->second.spec_map.tmap.rota.y);
  2023.         BE_write_real32(ofile, i->second.spec_map.tmap.rota.z);
  2024.         BE_write_uint16(ofile, 0x00); // envelope
  2025.  
  2026.         // BLCK:TMAP:FALL
  2027.         BE_write_uint32(ofile, LWO_FALL);
  2028.         BE_write_uint16(ofile, i->second.spec_map.tmap.fall.chunksize);
  2029.         BE_write_uint16(ofile, i->second.spec_map.tmap.fall.type);
  2030.         BE_write_real32(ofile, i->second.spec_map.tmap.fall.x);
  2031.         BE_write_real32(ofile, i->second.spec_map.tmap.fall.y);
  2032.         BE_write_real32(ofile, i->second.spec_map.tmap.fall.z);
  2033.         BE_write_uint16(ofile, 0x00); // envelope
  2034.  
  2035.         // BLCK:TMAP:CSYS
  2036.         BE_write_uint32(ofile, LWO_CSYS);
  2037.         BE_write_uint16(ofile, i->second.spec_map.tmap.csys.chunksize);
  2038.         BE_write_uint16(ofile, i->second.spec_map.tmap.csys.type);
  2039.  
  2040.         // BLCK:PROJ
  2041.         BE_write_uint32(ofile, LWO_PROJ);
  2042.         BE_write_uint16(ofile, i->second.spec_map.proj.chunksize);
  2043.         BE_write_uint16(ofile, i->second.spec_map.proj.mode);
  2044.  
  2045.         // BLCK:AXIS
  2046.         BE_write_uint32(ofile, LWO_AXIS);
  2047.         BE_write_uint16(ofile, i->second.spec_map.axis.chunksize);
  2048.         BE_write_uint16(ofile, i->second.spec_map.axis.axis);
  2049.  
  2050.         // BLCK:IMAG
  2051.         if(i->second.spec_map.imag.chunksize) {
  2052.            BE_write_uint32(ofile, LWO_IMAG);
  2053.            BE_write_uint16(ofile, i->second.spec_map.imag.chunksize);
  2054.            WriteVX(ofile, i->second.spec_map.imag.clipindex);
  2055.           }
  2056.  
  2057.         // BLCK:WRAP
  2058.         BE_write_uint32(ofile, LWO_WRAP);
  2059.         BE_write_uint16(ofile, i->second.spec_map.wrap.chunksize);
  2060.         BE_write_uint16(ofile, i->second.spec_map.wrap.wrap_w);
  2061.         BE_write_uint16(ofile, i->second.spec_map.wrap.wrap_h);
  2062.  
  2063.         // BLCK:VMAP
  2064.         if(i->second.spec_map.vmap.chunksize) {
  2065.            BE_write_uint32(ofile, LWO_VMAP);
  2066.            BE_write_uint16(ofile, i->second.spec_map.vmap.chunksize);
  2067.            write_aligned_string_02(ofile, i->second.spec_map.vmap.name.c_str());
  2068.           }
  2069.  
  2070.         // BLCK:AAST
  2071.         BE_write_uint32(ofile, LWO_AAST);
  2072.         BE_write_uint16(ofile, i->second.spec_map.aast.chunksize);
  2073.         BE_write_uint16(ofile, i->second.spec_map.aast.flags);
  2074.         BE_write_real32(ofile, i->second.spec_map.aast.strength);
  2075.  
  2076.         // BLCK:PIXB
  2077.         BE_write_uint32(ofile, LWO_PIXB);
  2078.         BE_write_uint16(ofile, i->second.spec_map.pixb.chunksize);
  2079.         BE_write_uint16(ofile, i->second.spec_map.pixb.flags);
  2080.        }
  2081.      if(i->second.flags & LWO_SURF_FLAGS_TRAN_BLOK)
  2082.        {
  2083.         // BLOK
  2084.         BE_write_uint32(ofile, LWO_BLOK);
  2085.         BE_write_uint16(ofile, i->second.tran_map.chunksize);
  2086.  
  2087.         // BLOK:IMAP
  2088.         BE_write_uint32(ofile, LWO_IMAP);
  2089.         BE_write_uint16(ofile, i->second.tran_map.imap.chunksize);
  2090.         BE_write_uint16(ofile, 0x8000); // constant ordinal
  2091.  
  2092.         // BLOK:IMAP:CHAN
  2093.         BE_write_uint32(ofile, LWO_CHAN);
  2094.         BE_write_uint16(ofile, i->second.tran_map.imap.chan.chunksize);
  2095.         BE_write_uint32(ofile, i->second.tran_map.imap.chan.channel);
  2096.  
  2097.         // BLOK:IMAP:ENAB
  2098.         BE_write_uint32(ofile, LWO_ENAB);
  2099.         BE_write_uint16(ofile, i->second.tran_map.imap.enab.chunksize);
  2100.         BE_write_uint16(ofile, i->second.tran_map.imap.enab.enable);
  2101.  
  2102.         // BLOK:IMAP:NEGA
  2103.         BE_write_uint32(ofile, LWO_NEGA);
  2104.         BE_write_uint16(ofile, i->second.tran_map.imap.nega.chunksize);
  2105.         BE_write_uint16(ofile, i->second.tran_map.imap.nega.enable);
  2106.  
  2107.         // BLOK:IMAP:OPAC
  2108.         BE_write_uint32(ofile, LWO_OPAC);
  2109.         BE_write_uint16(ofile, i->second.tran_map.imap.opac.chunksize);
  2110.         BE_write_uint16(ofile, i->second.tran_map.imap.opac.type);
  2111.         BE_write_real32(ofile, i->second.tran_map.imap.opac.opacity);
  2112.         BE_write_uint16(ofile, 0x00); // envelope
  2113.  
  2114.         // BLOK:IMAP:AXIS
  2115.         BE_write_uint32(ofile, LWO_AXIS);
  2116.         BE_write_uint16(ofile, i->second.tran_map.imap.axis.chunksize);
  2117.         BE_write_uint16(ofile, i->second.tran_map.imap.axis.axis);
  2118.  
  2119.         // BLOK:TMAP
  2120.         uint16 TMAP_chunksize = 0x5A;
  2121.         BE_write_uint32(ofile, LWO_TMAP);
  2122.         BE_write_uint16(ofile, i->second.tran_map.tmap.chunksize);
  2123.  
  2124.         // BLCK:TMAP:CNTR
  2125.         BE_write_uint32(ofile, LWO_CNTR);
  2126.         BE_write_uint16(ofile, i->second.tran_map.tmap.cntr.chunksize);
  2127.         BE_write_real32(ofile, i->second.tran_map.tmap.cntr.x);
  2128.         BE_write_real32(ofile, i->second.tran_map.tmap.cntr.y);
  2129.         BE_write_real32(ofile, i->second.tran_map.tmap.cntr.z);
  2130.         BE_write_uint16(ofile, 0x00); // envelope
  2131.  
  2132.         // BLCK:TMAP:SIZE
  2133.         BE_write_uint32(ofile, LWO_SIZE);
  2134.         BE_write_uint16(ofile, i->second.tran_map.tmap.size.chunksize);
  2135.         BE_write_real32(ofile, i->second.tran_map.tmap.size.x);
  2136.         BE_write_real32(ofile, i->second.tran_map.tmap.size.y);
  2137.         BE_write_real32(ofile, i->second.tran_map.tmap.size.z);
  2138.         BE_write_uint16(ofile, 0x00); // envelope
  2139.  
  2140.         // BLCK:TMAP:ROTA
  2141.         BE_write_uint32(ofile, LWO_ROTA);
  2142.         BE_write_uint16(ofile, i->second.tran_map.tmap.rota.chunksize);
  2143.         BE_write_real32(ofile, i->second.tran_map.tmap.rota.x);
  2144.         BE_write_real32(ofile, i->second.tran_map.tmap.rota.y);
  2145.         BE_write_real32(ofile, i->second.tran_map.tmap.rota.z);
  2146.         BE_write_uint16(ofile, 0x00); // envelope
  2147.  
  2148.         // BLCK:TMAP:FALL
  2149.         BE_write_uint32(ofile, LWO_FALL);
  2150.         BE_write_uint16(ofile, i->second.tran_map.tmap.fall.chunksize);
  2151.         BE_write_uint16(ofile, i->second.tran_map.tmap.fall.type);
  2152.         BE_write_real32(ofile, i->second.tran_map.tmap.fall.x);
  2153.         BE_write_real32(ofile, i->second.tran_map.tmap.fall.y);
  2154.         BE_write_real32(ofile, i->second.tran_map.tmap.fall.z);
  2155.         BE_write_uint16(ofile, 0x00); // envelope
  2156.  
  2157.         // BLCK:TMAP:CSYS
  2158.         BE_write_uint32(ofile, LWO_CSYS);
  2159.         BE_write_uint16(ofile, i->second.tran_map.tmap.csys.chunksize);
  2160.         BE_write_uint16(ofile, i->second.tran_map.tmap.csys.type);
  2161.  
  2162.         // BLCK:PROJ
  2163.         BE_write_uint32(ofile, LWO_PROJ);
  2164.         BE_write_uint16(ofile, i->second.tran_map.proj.chunksize);
  2165.         BE_write_uint16(ofile, i->second.tran_map.proj.mode);
  2166.  
  2167.         // BLCK:AXIS
  2168.         BE_write_uint32(ofile, LWO_AXIS);
  2169.         BE_write_uint16(ofile, i->second.tran_map.axis.chunksize);
  2170.         BE_write_uint16(ofile, i->second.tran_map.axis.axis);
  2171.  
  2172.         // BLCK:IMAG
  2173.         if(i->second.tran_map.imag.chunksize) {
  2174.            BE_write_uint32(ofile, LWO_IMAG);
  2175.            BE_write_uint16(ofile, i->second.tran_map.imag.chunksize);
  2176.            WriteVX(ofile, i->second.tran_map.imag.clipindex);
  2177.           }
  2178.  
  2179.         // BLCK:WRAP
  2180.         BE_write_uint32(ofile, LWO_WRAP);
  2181.         BE_write_uint16(ofile, i->second.tran_map.wrap.chunksize);
  2182.         BE_write_uint16(ofile, i->second.tran_map.wrap.wrap_w);
  2183.         BE_write_uint16(ofile, i->second.tran_map.wrap.wrap_h);
  2184.  
  2185.         // BLCK:VMAP
  2186.         if(i->second.tran_map.vmap.chunksize) {
  2187.            BE_write_uint32(ofile, LWO_VMAP);
  2188.            BE_write_uint16(ofile, i->second.tran_map.vmap.chunksize);
  2189.            write_aligned_string_02(ofile, i->second.tran_map.vmap.name.c_str());
  2190.           }
  2191.  
  2192.         // BLCK:AAST
  2193.         BE_write_uint32(ofile, LWO_AAST);
  2194.         BE_write_uint16(ofile, i->second.tran_map.aast.chunksize);
  2195.         BE_write_uint16(ofile, i->second.tran_map.aast.flags);
  2196.         BE_write_real32(ofile, i->second.tran_map.aast.strength);
  2197.  
  2198.         // BLCK:PIXB
  2199.         BE_write_uint32(ofile, LWO_PIXB);
  2200.         BE_write_uint16(ofile, i->second.tran_map.pixb.chunksize);
  2201.         BE_write_uint16(ofile, i->second.tran_map.pixb.flags);
  2202.        }
  2203.     }
  2204.  
  2205.  return true;
  2206. }
  2207.  
  2208. void lwFileSaverExample(void)
  2209. {
  2210.  using namespace std;
  2211.  lwFileSaver saver;
  2212.  
  2213.  // image clips
  2214.  saver.insertClip(1, "image1.tga");
  2215.  saver.insertClip(2, "image2.tga");
  2216.  
  2217.  // layer #0
  2218.  saver.insertLayr(0, nullptr);
  2219.  boost::shared_array<lwVertex3D> data1(new lwVertex3D[3]);
  2220.  data1[0].x = data1[0].y = data1[0].z = 0.0f;
  2221.  data1[1].x = data1[1].y = data1[1].z = 1.0f;
  2222.  data1[2].x = data1[2].y = data1[2].z = 2.0f;
  2223.  saver.insertPnts(0, 0, data1, 3);
  2224.  
  2225.  boost::shared_array<lwRefVertex2D> uv1(new lwRefVertex2D[3]);
  2226.  uv1[0].reference = 0; uv1[0].x = 0.0f; uv1[0].y = 0.0f;
  2227.  uv1[1].reference = 1; uv1[1].x = 0.0f; uv1[1].y = 0.5f;
  2228.  uv1[2].reference = 2; uv1[2].x = 0.0f; uv1[2].y = 1.0f;
  2229.  saver.insertTxuv(0, 0, "uv1", uv1, 3);
  2230.  
  2231.  boost::shared_array<lwRefVertex1D> w1(new lwRefVertex1D[3]);
  2232.  w1[0].reference = 0; w1[0].x = 0.1f;
  2233.  w1[1].reference = 1; w1[1].x = 0.2f;
  2234.  w1[2].reference = 2; w1[2].x = 0.3f;
  2235.  saver.insertWght(0, 0, "w1", w1, 3);
  2236.  
  2237.  boost::shared_array<lwRefVertex3D> m1(new lwRefVertex3D[3]);
  2238.  m1[0].reference = 0; m1[0].x = m1[0].y = m1[0].z = -1.0f;
  2239.  m1[1].reference = 1; m1[1].x = m1[1].y = m1[1].z = -1.0f;
  2240.  m1[2].reference = 2; m1[2].x = m1[2].y = m1[2].z = -1.0f;
  2241.  saver.insertMorf(0, 0, "m1", m1, 3);
  2242.  
  2243.  boost::shared_array<lwTriangle> p1(new lwTriangle[1]);
  2244.  p1[0].a = 0;
  2245.  p1[0].b = 1;
  2246.  p1[0].c = 2;
  2247.  saver.insertPols(0, 0, "surface_000", p1, 1);
  2248.  
  2249.  // layer #1
  2250.  saver.insertLayr(1, nullptr);
  2251.  boost::shared_array<lwVertex3D> data2(new lwVertex3D[3]);
  2252.  data2[0].x = data2[0].y = data2[0].z = 3.0f;
  2253.  data2[1].x = data2[1].y = data2[1].z = 4.0f;
  2254.  data2[2].x = data2[2].y = data2[2].z = 5.0f;
  2255.  saver.insertPnts(1, 0, data2, 3);
  2256.  
  2257.  boost::shared_array<lwRefVertex2D> uv2(new lwRefVertex2D[3]);
  2258.  uv2[0].reference = 0; uv2[0].x = 1.0; uv2[0].y = 0.0f;
  2259.  uv2[1].reference = 1; uv2[1].x = 1.0; uv2[1].y = 0.5f;
  2260.  uv2[2].reference = 2; uv2[2].x = 1.0; uv2[2].y = 1.0f;
  2261.  saver.insertTxuv(1, 0, "uv2", uv2, 3);
  2262.  
  2263.  boost::shared_array<lwRefVertex1D> w2(new lwRefVertex1D[3]);
  2264.  w2[0].reference = 0; w2[0].x = 0.7f;
  2265.  w2[1].reference = 1; w2[1].x = 0.8f;
  2266.  w2[2].reference = 2; w2[2].x = 0.9f;
  2267.  saver.insertWght(1, 0, "w2", w2, 3);
  2268.  
  2269.  boost::shared_array<lwRefVertex3D> m2(new lwRefVertex3D[3]);
  2270.  m2[0].reference = 0; m2[0].x = m2[0].y = m2[0].z = 1.0f;
  2271.  m2[1].reference = 1; m2[1].x = m2[1].y = m2[1].z = 1.0f;
  2272.  m2[2].reference = 2; m2[2].x = m2[2].y = m2[2].z = 1.0f;
  2273.  saver.insertMorf(1, 0, "m2", m2, 3);
  2274.  
  2275.  boost::shared_array<lwTriangle> p2(new lwTriangle[1]);
  2276.  p2[0].a = 0;
  2277.  p2[0].b = 1;
  2278.  p2[0].c = 2;
  2279.  saver.insertPols(1, 0, "surface_001", p2, 1);
  2280.  
  2281.  saver.insertSurf("surface_000");
  2282.  saver.insertSurf("surface_001");
  2283.  saver.insertSurf("surface_002");
  2284.  saver.setSurfColr("surface_000", 1.0f, 0.0f, 0.0f);
  2285.  saver.setSurfColr("surface_001", 0.0f, 1.0f, 0.0f);
  2286.  saver.setSurfColr("surface_002", 0.0f, 0.0f, 1.0f);
  2287.  
  2288.  // enable surface UV map
  2289.  saver.enableSurfColrImag("surface_000");
  2290.  saver.enableSurfDiffImag("surface_000");
  2291.  saver.enableSurfSpecImag("surface_000");
  2292.  saver.enableSurfTranImag("surface_000");
  2293.  
  2294.  // set surface UV map 
  2295.  saver.setSurfColrVmap("surface_000", "uv1");
  2296.  saver.setSurfDiffVmap("surface_000", "uv1");
  2297.  saver.setSurfSpecVmap("surface_000", "uv1");
  2298.  saver.setSurfTranVmap("surface_000", "uv1");
  2299.  
  2300.  // set surface image
  2301.  saver.setSurfColrImag("surface_000", 1);
  2302.  saver.setSurfTranImag("surface_000", 1);
  2303.  saver.setSurfTranNega("surface_000", 1);
  2304.  
  2305.  // enable surface UV map
  2306.  saver.enableSurfColrImag("surface_001");
  2307.  saver.enableSurfDiffImag("surface_001");
  2308.  saver.enableSurfSpecImag("surface_001");
  2309.  saver.enableSurfTranImag("surface_001");
  2310.  
  2311.  // set surface UV map 
  2312.  saver.setSurfColrVmap("surface_001", "uv2");
  2313.  saver.setSurfDiffVmap("surface_001", "uv2");
  2314.  saver.setSurfSpecVmap("surface_001", "uv2");
  2315.  saver.setSurfTranVmap("surface_001", "uv2");
  2316.  
  2317.  // set surface image
  2318.  saver.setSurfColrImag("surface_001", 1);
  2319.  
  2320.  //
  2321.  // HOW TO: SKELETONS
  2322.  //
  2323.  
  2324.  // add joints
  2325.  uint32 n_joints = 4;
  2326.  boost::shared_array<lwVertex3D> joints(new lwVertex3D[n_joints]);
  2327.  joints[0].x = 1.0f; joints[0].y = 1.0f; joints[0].z = 0.0f;
  2328.  joints[1].x = 1.0f; joints[1].y = 2.0f; joints[1].z = 0.0f;
  2329.  joints[2].x = 2.0f; joints[2].y = 2.0f; joints[2].z = 0.0f;
  2330.  joints[3].x = 2.0f; joints[3].y = 1.0f; joints[3].z = 0.0f;
  2331.  saver.insertJnts(0, 0, joints, n_joints);
  2332.  
  2333.  // add bones
  2334.  uint32 n_bones = 3;
  2335.  boost::shared_array<lwSkelegon> bones(new lwSkelegon[n_bones]);
  2336.  bones[0].name = "root"; bones[0].a = 0; bones[0].b = 1;
  2337.  bones[1].name = "hand"; bones[1].a = 1; bones[1].b = 2;
  2338.  bones[2].name = "fing"; bones[2].a = 2; bones[2].b = 3;
  2339.  saver.insertSkel(0, 0, "skeleton", bones, n_bones);
  2340.  
  2341.  //
  2342.  // HOW TO: SAVE LWO
  2343.  //
  2344.  
  2345.  saver.save("test.lwo");
  2346. }
  2347.  
  2348. /*
  2349. inline uint32 lwConvertToVX(uint32 index)
  2350. {
  2351.  if(index < 0xFF00) return index;
  2352.  reverse_byte_order(&index);
  2353.  index |= 0x000000FF;
  2354.  reverse_byte_order(&index);
  2355.  return index;
  2356. }
  2357.  
  2358. class lwJointPolygonTagsChunkSizeCalc : public JOINTVISITOR {
  2359.  private :
  2360.   std::ofstream& ofile;
  2361.   uint32 chunksize;
  2362.  public :
  2363.   lwJointPolygonTagsChunkSizeCalc(std::ofstream& out) : ofile(out), chunksize(0)
  2364.   {
  2365.   }
  2366.   uint32 getChunkSize(void)const
  2367.   {
  2368.    return chunksize;
  2369.   }
  2370.   return_type operator ()(argument1 joint, argument2 index)
  2371.   {
  2372.    chunksize += align02(joint.name.length() + 1);
  2373.    return true;
  2374.   }
  2375. };
  2376.  
  2377. class lwJointPolygonTagsSaver : public JOINTVISITOR {
  2378.  private :
  2379.   std::ofstream& ofile;
  2380.  public :
  2381.   lwJointPolygonTagsSaver(std::ofstream& out) : ofile(out)
  2382.   {
  2383.   }
  2384.   return_type operator ()(argument1 joint, argument2 index)
  2385.   {
  2386.    write_aligned_string_02(ofile, joint.name.c_str());
  2387.    return true;
  2388.   }
  2389. };
  2390.  
  2391. class lwJointPointSaver : public JOINTVISITOR {
  2392.  private :
  2393.   std::ofstream& ofile;
  2394.  public :
  2395.   lwJointPointSaver(std::ofstream& out) : ofile(out)
  2396.   {
  2397.   }
  2398.   return_type operator ()(argument1 joint, argument2 index)
  2399.   {
  2400.    BE_write_real32(ofile, -joint.matrix[12]);
  2401.    BE_write_real32(ofile, -joint.matrix[13]);
  2402.    BE_write_real32(ofile, -joint.matrix[14]);
  2403.    return true;
  2404.   }
  2405. };
  2406.  
  2407. class lwJointPolygonChunkSizeCalc : public JOINTVISITOR {
  2408.  private :
  2409.   std::ofstream& ofile;
  2410.   uint32 chunksize;
  2411.  public :
  2412.   lwJointPolygonChunkSizeCalc(std::ofstream& out) : ofile(out), chunksize(0)
  2413.   {
  2414.   }
  2415.   uint32 getChunkSize(void)const
  2416.   {
  2417.    return chunksize;
  2418.   }
  2419.   return_type operator ()(argument1 joint, argument2 index)
  2420.   {
  2421.    // skip root joint
  2422.    if(joint.parent == INVALID_JOINT) return true;
  2423.    chunksize += 0x02; // for number of vertices + flags
  2424.    chunksize += 0x04; // for indices
  2425.    return true;
  2426.   }
  2427. };
  2428.  
  2429. class lwJointPolygonSaver : public JOINTVISITOR {
  2430.  private :
  2431.   std::ofstream& ofile;
  2432.   std::map<uint32, uint32> assoc;
  2433.   uint32 point_id;
  2434.  public :
  2435.   lwJointPolygonSaver(std::ofstream& out) : ofile(out), point_id(0)
  2436.   {
  2437.    // TODO:
  2438.    // We need to set a different initial point_id when we have
  2439.    // multiple skeletons.
  2440.   }
  2441.   return_type operator ()(argument1 joint, argument2 joint_id)
  2442.   {
  2443.    // add (joint_id, point_id) association data to map
  2444.    assoc.insert(std::map<uint32, uint32>::value_type(joint_id, point_id));
  2445.  
  2446.    // polygon for each parent-child bone
  2447.    if(joint.parent != INVALID_JOINT)
  2448.      {
  2449.       // get parent point_id
  2450.       std::map<uint32, uint32>::iterator iter = assoc.find(joint.parent);
  2451.       if(iter == assoc.end()) return false; // every child must have a parent
  2452.  
  2453.       // polygon data
  2454.       BE_write_uint16(ofile, 0x0002);
  2455.       BE_write_uint16(ofile, (uint16)iter->second);
  2456.       BE_write_uint16(ofile, (uint16)point_id);
  2457.      }
  2458.  
  2459.    // update current point index
  2460.    point_id++;
  2461.    return true;
  2462.   }
  2463. };
  2464.  
  2465. class lwJointPolyTagChunkSizeCalc : public JOINTVISITOR {
  2466.  private :
  2467.   std::ofstream& ofile;
  2468.   uint32 chunksize;
  2469.  public :
  2470.   lwJointPolyTagChunkSizeCalc(std::ofstream& out) : ofile(out), chunksize(0)
  2471.   {
  2472.   }
  2473.   uint32 getChunkSize(void)const
  2474.   {
  2475.    return chunksize;
  2476.   }
  2477.   return_type operator ()(argument1 joint, argument2 index)
  2478.   {
  2479.    // skip root joint
  2480.    if(joint.parent == INVALID_JOINT) return true;
  2481.    chunksize += 0x02; // for VX
  2482.    chunksize += 0x02; // for tag
  2483.    return true;
  2484.   }
  2485. };
  2486.  
  2487. class lwJointPolyTagSaver : public JOINTVISITOR {
  2488.  private :
  2489.   std::ofstream& ofile;
  2490.   uint32 polygon_index;
  2491.   uint32 joint_index;
  2492.  public :
  2493.   lwJointPolyTagSaver(std::ofstream& out) : ofile(out), polygon_index(0), joint_index(0)
  2494.   {
  2495.    // TODO:
  2496.    // We need to set a different initial point_id when we have
  2497.    // multiple skeletons.
  2498.   }
  2499.   return_type operator ()(argument1 joint, argument2 joint_id)
  2500.   {
  2501.    // polygon for each parent-child bone
  2502.    if(joint.parent != INVALID_JOINT)
  2503.      {
  2504.       // polygon data
  2505.       BE_write_uint16(ofile, (uint16)(polygon_index));
  2506.       BE_write_uint16(ofile, (uint16)(joint_index + 1));
  2507.  
  2508.       // update number of polygons seen
  2509.       polygon_index++;
  2510.      }
  2511.  
  2512.    joint_index++;
  2513.    return true;
  2514.   }
  2515. };
  2516.  
  2517. class lwJointPartTagChunkSizeCalc : public JOINTVISITOR {
  2518.  private :
  2519.   std::ofstream& ofile;
  2520.   uint32 chunksize;
  2521.  public :
  2522.   lwJointPartTagChunkSizeCalc(std::ofstream& out) : ofile(out), chunksize(0)
  2523.   {
  2524.   }
  2525.   uint32 getChunkSize(void)const
  2526.   {
  2527.    return chunksize;
  2528.   }
  2529.   return_type operator ()(argument1 joint, argument2 index)
  2530.   {
  2531.    // skip root joint
  2532.    if(joint.parent == INVALID_JOINT) return true;
  2533.    chunksize += 0x02; // for VX
  2534.    chunksize += 0x02; // for tag
  2535.    return true;
  2536.   }
  2537. };
  2538.  
  2539. class lwJointPartTagSaver : public JOINTVISITOR {
  2540.  private :
  2541.   std::ofstream& ofile;
  2542.   uint32 polygon_index;
  2543.   uint32 joint_index;
  2544.  public :
  2545.   lwJointPartTagSaver(std::ofstream& out) : ofile(out), polygon_index(0), joint_index(0)
  2546.   {
  2547.    // TODO:
  2548.    // We need to set a different initial point_id when we have
  2549.    // multiple skeletons.
  2550.   }
  2551.   return_type operator ()(argument1 joint, argument2 joint_id)
  2552.   {
  2553.    // polygon for each parent-child bone
  2554.    if(joint.parent != INVALID_JOINT)
  2555.      {
  2556.       // polygon data
  2557.       BE_write_uint16(ofile, (uint16)(polygon_index));
  2558.       BE_write_uint16(ofile, (uint16)(joint_index + 1));
  2559.  
  2560.       // update number of polygons seen
  2561.       polygon_index++;
  2562.      }
  2563.  
  2564.    joint_index++;
  2565.    return true;
  2566.   }
  2567. };
  2568.  
  2569. struct lwWeightMapPair {
  2570.  uint32 index;
  2571.  real32 value;
  2572.  lwWeightMapPair(uint32 p1 = 0, real32 p2 = 0.0f) : index(p1), value(p2) {}
  2573. };
  2574.  
  2575. struct lwWeightMap {
  2576.  std::string name;
  2577.  std::deque<lwWeightMapPair> data;
  2578. };
  2579.  
  2580. class lwConverter {
  2581.  private :
  2582.   const SIMPLEMODELCONTAINER& data;
  2583.   std::ofstream ofile;
  2584.  private :
  2585.   uint32 n_wmaps;
  2586.   std::vector<lwWeightMap> wmapdata;
  2587.  private :
  2588.   uint32 FORM_chunksize;
  2589.   uint32 LAYR_chunksize;
  2590.   uint32 TAGS_chunksize;
  2591.   uint32 PNTS_chunksize;
  2592.   uint32 POLS_chunksize;
  2593.   uint32 PTAG_chunksize;
  2594.   boost::shared_array<uint32> TXUV_chunksize;
  2595.   boost::shared_array<uint32> WGHT_chunksize;
  2596.  private :
  2597.   uint32 BONELAYR_chunksize;
  2598.   uint32 BONETAGS_chunksize;
  2599.   uint32 BONEPNTS_chunksize;
  2600.   uint32 BONEPOLS_chunksize;
  2601.   uint32 BONEPTAG_chunksize;
  2602.   uint32 BONEPART_chunksize;
  2603.  private :
  2604.   bool sanityChecker(void)const;
  2605.   bool error(const char* message)const;
  2606.   bool constructWeightMaps(void);
  2607.  private :
  2608.   void computeFORMChunkSize(void);  // FORM
  2609.   void computeLAYRChunkSize(void);  // LAYR
  2610.   void computeTAGSChunkSize(void);  // TAGS
  2611.   void computePNTSChunkSize(void);  // PNTS
  2612.   void computePOLSChunkSize(void);  // POLS
  2613.   void computePTAGChunkSize(void);  // SURF
  2614.   void computeTXUVChunkSize(void);  // VMAP:TXUV
  2615.   void computeWGHTChunkSize(void);  // VMAP:WGHT
  2616.   bool saveFORM(void);
  2617.   bool saveLAYR(void);
  2618.   bool saveTAGS(void);
  2619.   bool savePNTS(void);
  2620.   bool savePOLS(void);
  2621.   bool savePTAG(void);
  2622.   bool saveTXUV(void);
  2623.   bool saveWGHT(void);
  2624.  private :
  2625.   void computeBONELAYRChunkSize(void);  // LAYR
  2626.   void computeBONETAGSChunkSize(void);  // TAGS
  2627.   void computeBONEPNTSChunkSize(void);  // PNTS
  2628.   void computeBONEPOLSChunkSize(void);  // POLS
  2629.   void computeBONEPTAGChunkSize(void);  // PTAG - BONE
  2630.   void computeBONEPARTChunkSize(void);  // PTAG - PART
  2631.   bool saveBONELAYR(void);
  2632.   bool saveBONETAGS(void);
  2633.   bool saveBONEPNTS(void);
  2634.   bool saveBONEPOLS(void);
  2635.   bool saveBONEPTAG(void);
  2636.   bool saveBONEPART(void);
  2637.  public :
  2638.   bool convert(const char* path, const char* name);
  2639.  public :
  2640.   lwConverter(const SIMPLEMODELCONTAINER& smc);
  2641.  ~lwConverter();
  2642. };
  2643.  
  2644. lwConverter::lwConverter(const SIMPLEMODELCONTAINER& smc) : data(smc), n_wmaps(0)
  2645. {
  2646.  FORM_chunksize = 0;
  2647.  LAYR_chunksize = 0;
  2648.  TAGS_chunksize = 0;
  2649.  PNTS_chunksize = 0;
  2650.  POLS_chunksize = 0;
  2651.  PTAG_chunksize = 0;
  2652.  
  2653.  BONELAYR_chunksize = 0;
  2654.  BONETAGS_chunksize = 0;
  2655.  BONEPNTS_chunksize = 0;
  2656.  BONEPOLS_chunksize = 0;
  2657.  BONEPTAG_chunksize = 0;
  2658.  BONEPART_chunksize = 0;
  2659. }
  2660.  
  2661. lwConverter::~lwConverter()
  2662. {
  2663. }
  2664.  
  2665. bool lwConverter::sanityChecker(void)const
  2666. {
  2667.  // must have model
  2668.  if(!data.model) return error("No model present in container.");
  2669.  
  2670.  // if index buffers are present
  2671.  uint32 n_ibuffers = data.model->ibuffer.size();
  2672.  for(size_t i = 0; i < n_ibuffers; i++)
  2673.     {
  2674.      // index buffer must be a triangle list
  2675.      IDX_BUFFER& ib = data.model->ibuffer[i];
  2676.      if(ib.elem == 0) return error("One or more index buffers are empty.");
  2677.      if(ib.elem <= 2) return error("One or more index buffers do not contain at least one triangle.");
  2678.  
  2679.      // index buffer must have a valid format
  2680.      if(data.model->ibuffer[i].format == FACE_FORMAT_UINT_32) ;
  2681.      else if(data.model->ibuffer[i].format == FACE_FORMAT_UINT_16) ;
  2682.      else if(data.model->ibuffer[i].format == FACE_FORMAT_UINT_08) ;
  2683.      else return error("Unknown face format.");
  2684.  
  2685.      // index buffer must have a valid triangle type
  2686.      if(data.model->ibuffer[i].type == FACE_TYPE_TRIANGLES) ;
  2687.      else if(data.model->ibuffer[i].type == FACE_TYPE_TRISTRIP) ;
  2688.      else if(data.model->ibuffer[i].type == FACE_TYPE_TRISTRIPCUT) ;
  2689.      else return error("Unknown triangle type.");
  2690.     }
  2691.  
  2692.  // if skeletons are present
  2693.  uint32 n_skeletons = data.skeletons.size();
  2694.  if(n_skeletons) {
  2695.     for(uint32 i = 0; i < n_skeletons; i++) {
  2696.         const SKELETON& skel = data.skeletons[i];
  2697.         if(skel.joints() < 2) return error("Skeletons must have at least two joints.");
  2698.         if(strlen(skel.get_identifier()) < 1) return error("Skeletons must have a valid string identifier.");
  2699.        }
  2700.    }
  2701.  
  2702.  // TODO:
  2703.  // if weight maps are present
  2704.  
  2705.  return true;
  2706. }
  2707.  
  2708. bool lwConverter::error(const char* message)const
  2709. {
  2710.  std::cout << "LWO Export Error: " << message << std::endl;
  2711.  return false;
  2712. }
  2713.  
  2714. bool lwConverter::constructWeightMaps(void)
  2715. {
  2716.  // nothing to compute
  2717.  n_wmaps = 0;
  2718.  if(!(data.model->vbuffer.flags & VERTEX_WEIGHTS)) return true;
  2719.  
  2720.  // compute number of weight maps
  2721.  if(data.model->vbuffer.flags & VERTEX_WMAPIDX)
  2722.    {
  2723.     // create weight maps
  2724.     uint16 max_index = 0;
  2725.     for(uint32 i = 0; i < data.model->vbuffer.elem; i++) {
  2726.         const VERTEX& v = data.model->vbuffer.data[i];
  2727.         if(v.m1 != INVALID_VERTEX_WMAP_INDEX && !(v.m1 < max_index)) max_index = v.m1;
  2728.         if(v.m2 != INVALID_VERTEX_WMAP_INDEX && !(v.m2 < max_index)) max_index = v.m2;
  2729.         if(v.m3 != INVALID_VERTEX_WMAP_INDEX && !(v.m3 < max_index)) max_index = v.m3;
  2730.         if(v.m4 != INVALID_VERTEX_WMAP_INDEX && !(v.m4 < max_index)) max_index = v.m4;
  2731.         if(v.m5 != INVALID_VERTEX_WMAP_INDEX && !(v.m5 < max_index)) max_index = v.m5;
  2732.         if(v.m6 != INVALID_VERTEX_WMAP_INDEX && !(v.m6 < max_index)) max_index = v.m6;
  2733.         if(v.m7 != INVALID_VERTEX_WMAP_INDEX && !(v.m7 < max_index)) max_index = v.m7;
  2734.         if(v.m8 != INVALID_VERTEX_WMAP_INDEX && !(v.m8 < max_index)) max_index = v.m8;
  2735.        }
  2736.     n_wmaps = max_index + 1;
  2737.     wmapdata.resize(n_wmaps);
  2738.  
  2739.     // assign names
  2740.     for(uint32 i = 0; i < wmapdata.size(); i++) {
  2741.         std::stringstream ss;
  2742.         ss << "wmap_" << std::setfill('0') << std::setw(3) << i;
  2743.         wmapdata[i].name = ss.str();
  2744.        }
  2745.  
  2746.     // assign weights
  2747.     for(uint32 i = 0; i < data.model->vbuffer.elem; i++) {
  2748.         const VERTEX& v = data.model->vbuffer.data[i];
  2749.         if(v.m1 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m1].data.push_back(lwWeightMapPair(i, v.w1/65535.0f));
  2750.         if(v.m2 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m2].data.push_back(lwWeightMapPair(i, v.w2/65535.0f));
  2751.         if(v.m3 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m3].data.push_back(lwWeightMapPair(i, v.w3/65535.0f));
  2752.         if(v.m4 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m4].data.push_back(lwWeightMapPair(i, v.w4/65535.0f));
  2753.         if(v.m5 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m5].data.push_back(lwWeightMapPair(i, v.w5/65535.0f));
  2754.         if(v.m6 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m6].data.push_back(lwWeightMapPair(i, v.w6/65535.0f));
  2755.         if(v.m7 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m7].data.push_back(lwWeightMapPair(i, v.w7/65535.0f));
  2756.         if(v.m8 != INVALID_VERTEX_WMAP_INDEX) wmapdata[v.m8].data.push_back(lwWeightMapPair(i, v.w8/65535.0f));
  2757.        }
  2758.    }
  2759.  else if(data.model->vbuffer.flags & VERTEX_BONEIDX)
  2760.    {
  2761.     // create weight maps
  2762.     uint16 max_index = 0;
  2763.     for(uint32 i = 0; i < data.model->vbuffer.elem; i++) {
  2764.         const VERTEX& v = data.model->vbuffer.data[i];
  2765.         if(v.b1 != INVALID_VERTEX_BONE_INDEX && !(v.b1 < max_index)) max_index = v.b1;
  2766.         if(v.b2 != INVALID_VERTEX_BONE_INDEX && !(v.b2 < max_index)) max_index = v.b2;
  2767.         if(v.b3 != INVALID_VERTEX_BONE_INDEX && !(v.b3 < max_index)) max_index = v.b3;
  2768.         if(v.b4 != INVALID_VERTEX_BONE_INDEX && !(v.b4 < max_index)) max_index = v.b4;
  2769.         if(v.b5 != INVALID_VERTEX_BONE_INDEX && !(v.b5 < max_index)) max_index = v.b5;
  2770.         if(v.b6 != INVALID_VERTEX_BONE_INDEX && !(v.b6 < max_index)) max_index = v.b6;
  2771.         if(v.b7 != INVALID_VERTEX_BONE_INDEX && !(v.b7 < max_index)) max_index = v.b7;
  2772.         if(v.b8 != INVALID_VERTEX_BONE_INDEX && !(v.b8 < max_index)) max_index = v.b8;
  2773.        }
  2774.     n_wmaps = max_index + 1;
  2775.     wmapdata.resize(n_wmaps);
  2776.     std::cout << " n_wmaps = " << n_wmaps << std::endl;
  2777.  
  2778.     // TODO
  2779.    }
  2780.  else
  2781.    {
  2782.     // assume there is only one weight map
  2783.     n_wmaps = 1;
  2784.     wmapdata.resize(n_wmaps);
  2785.     std::cout << " n_wmaps = " << n_wmaps << std::endl;
  2786.  
  2787.     // TODO
  2788.    }
  2789.  
  2790.  return true;
  2791. }
  2792.  
  2793. bool lwConverter::convert(const char* path, const char* name)
  2794. {
  2795.  // preprocessing
  2796.  if(!sanityChecker()) return false;
  2797.  if(!constructWeightMaps()) return false;
  2798.  
  2799.  // create file
  2800.  std::stringstream ss;
  2801.  ss << path << name << ".lwo";
  2802.  ofile.open(ss.str().c_str(), std::ios::binary);
  2803.  if(!ofile) return error("Error creating LWO file.");
  2804.  
  2805.  // compute 1st layer chunksizes
  2806.  computeLAYRChunkSize();
  2807.  computeTAGSChunkSize();
  2808.  computePNTSChunkSize();
  2809.  computePOLSChunkSize();
  2810.  computePTAGChunkSize();
  2811.  computeTXUVChunkSize();
  2812.  computeWGHTChunkSize();
  2813.  
  2814.  // compute 2nd layer chunksizes
  2815.  computeBONELAYRChunkSize();
  2816.  computeBONETAGSChunkSize();
  2817.  computeBONEPNTSChunkSize();
  2818.  computeBONEPOLSChunkSize();
  2819.  computeBONEPTAGChunkSize();
  2820.  computeBONEPARTChunkSize();
  2821.  
  2822.  // compute form chunksize
  2823.  computeFORMChunkSize();
  2824.  
  2825.  // save 1st layer chunks
  2826.  if(!saveFORM()) return false;
  2827.  if(!saveLAYR()) return false;
  2828.  if(!saveTAGS()) return false;
  2829.  if(!savePNTS()) return false;
  2830.  if(!savePOLS()) return false;
  2831.  if(!savePTAG()) return false;
  2832.  if(!saveTXUV()) return false;
  2833.  if(!saveWGHT()) return false;
  2834.  
  2835.  // save 2nd layer chunks
  2836.  if(!saveBONELAYR()) return false;
  2837.  if(!saveBONETAGS()) return false;
  2838.  if(!saveBONEPNTS()) return false;
  2839.  if(!saveBONEPOLS()) return false;
  2840.  if(!saveBONEPTAG()) return false;
  2841.  if(!saveBONEPART()) return false;
  2842.  
  2843.  return true;
  2844. }
  2845.  
  2846. //
  2847. // FORM
  2848. //
  2849.  
  2850. void lwConverter::computeFORMChunkSize(void)
  2851. {
  2852.  FORM_chunksize = 0;
  2853.  FORM_chunksize += 0x04; // LWO2
  2854.  
  2855.  // TAGS contribution
  2856.  if(TAGS_chunksize) {
  2857.     FORM_chunksize += 0x08;
  2858.     FORM_chunksize += TAGS_chunksize;
  2859.    }
  2860.  
  2861.  // LAYR contribution
  2862.  FORM_chunksize += 0x08;
  2863.  FORM_chunksize += LAYR_chunksize;
  2864.  
  2865.  // PNTS contribution
  2866.  if(PNTS_chunksize) {
  2867.     FORM_chunksize += 0x08;
  2868.     FORM_chunksize += PNTS_chunksize;
  2869.    }
  2870.  
  2871.  // POLS contribution
  2872.  if(POLS_chunksize) {
  2873.     FORM_chunksize += 0x08;
  2874.     FORM_chunksize += POLS_chunksize;
  2875.    }
  2876.  
  2877.  // PTAG contribution
  2878.  if(PTAG_chunksize) {
  2879.     FORM_chunksize += 0x08;
  2880.     FORM_chunksize += PTAG_chunksize;
  2881.    }
  2882.  
  2883.  // TXUV contribution
  2884.  if(TXUV_chunksize) {
  2885.     uint32 n_surface = (uint32)data.model->ibuffer.size();
  2886.     for(uint32 i = 0; i < n_surface; i++) {
  2887.         FORM_chunksize += 0x08;
  2888.         FORM_chunksize += TXUV_chunksize[i];
  2889.        }
  2890.    }
  2891.  
  2892.  // WGHT contribution
  2893.  if(WGHT_chunksize) {
  2894.     for(uint32 i = 0; i < n_wmaps; i++) {
  2895.         if(WGHT_chunksize[i]) {
  2896.            FORM_chunksize += 0x08;
  2897.            FORM_chunksize += WGHT_chunksize[i];
  2898.           }
  2899.        }
  2900.    }
  2901.  
  2902.  // LAYR (from bones) contribution
  2903.  if(BONELAYR_chunksize) {
  2904.     FORM_chunksize += 0x08;
  2905.     FORM_chunksize += BONELAYR_chunksize;
  2906.    }
  2907.  
  2908.  // TAGS (from bones) contribution
  2909.  if(BONETAGS_chunksize) {
  2910.     FORM_chunksize += 0x08;
  2911.     FORM_chunksize += BONETAGS_chunksize;
  2912.    }
  2913.  
  2914.  // PNTS (from bones) contribution
  2915.  if(BONEPNTS_chunksize) {
  2916.     FORM_chunksize += 0x08;
  2917.     FORM_chunksize += BONEPNTS_chunksize;
  2918.    }
  2919.  
  2920.  // POLS (from bones) contribution
  2921.  if(BONEPOLS_chunksize) {
  2922.     FORM_chunksize += 0x08;
  2923.     FORM_chunksize += BONEPOLS_chunksize;
  2924.    }
  2925.  
  2926.  // PTAG (from bones) contribution
  2927.  if(BONEPTAG_chunksize) {
  2928.     FORM_chunksize += 0x08;
  2929.     FORM_chunksize += BONEPTAG_chunksize;
  2930.    }
  2931.  
  2932.  // PTAG (from bones) contribution
  2933.  if(BONEPART_chunksize) {
  2934.     FORM_chunksize += 0x08;
  2935.     FORM_chunksize += BONEPART_chunksize;
  2936.    }
  2937. }
  2938.  
  2939. bool lwConverter::saveFORM(void)
  2940. {
  2941.  // FORM + FORM_chunksize + LWO2
  2942.  BE_write_uint32(ofile, LWO_FORM);
  2943.  BE_write_uint32(ofile, FORM_chunksize);
  2944.  BE_write_uint32(ofile, LWO_LWO2);
  2945.  return true;
  2946. }
  2947.  
  2948. void lwConverter::computeLAYRChunkSize(void)
  2949. {
  2950.  LAYR_chunksize = 0x12;
  2951. }
  2952.  
  2953. bool lwConverter::saveLAYR(void)
  2954. {
  2955.  // save LAYR + LAYR_chunksize
  2956.  BE_write_uint32(ofile, LWO_LAYR);
  2957.  BE_write_uint32(ofile, LAYR_chunksize);
  2958.  
  2959.  // save LAYR data
  2960.  BE_write_uint16(ofile, 0); // number
  2961.  BE_write_uint16(ofile, 0); // flags
  2962.  BE_write_real32(ofile, 0); // pivot
  2963.  BE_write_real32(ofile, 0); // ...
  2964.  BE_write_real32(ofile, 0); // ...
  2965.  BE_write_uint08(ofile, 0); // name
  2966.  BE_write_uint08(ofile, 0); // ...
  2967.  
  2968.  return true;
  2969. }
  2970.  
  2971. void lwConverter::computeTAGSChunkSize(void)
  2972. {
  2973.  // compute chunksize
  2974.  TAGS_chunksize = 0;
  2975.  for(size_t i = 0; i < data.model->ibuffer.size(); i++) {
  2976.      IDX_BUFFER& ib = data.model->ibuffer[i];
  2977.      TAGS_chunksize += align02((ib.name.length() + 1));
  2978.     }
  2979. }
  2980.  
  2981. bool lwConverter::saveTAGS(void)
  2982. {
  2983.  // don't save chunk if there are no TAGS
  2984.  if(!TAGS_chunksize) return true;
  2985.  
  2986.  // save TAGS + TAGS_chunksize
  2987.  BE_write_uint32(ofile, LWO_TAGS);
  2988.  BE_write_uint32(ofile, TAGS_chunksize);
  2989.  
  2990.  // save surface names
  2991.  for(size_t i = 0; i < data.model->ibuffer.size(); i++) {
  2992.      IDX_BUFFER& ib = data.model->ibuffer[i];
  2993.      write_aligned_string_02(ofile, ib.name.c_str());
  2994.     }
  2995.  
  2996.  return true;
  2997. }
  2998.  
  2999. void lwConverter::computePNTSChunkSize(void)
  3000. {
  3001.  // compute chunksize
  3002.  uint32 n_points = data.model->vbuffer.elem;
  3003.  PNTS_chunksize = 0x0C*n_points;
  3004. }
  3005.  
  3006. bool lwConverter::savePNTS(void)
  3007. {
  3008.  // don't save chunk if there are no PNTS
  3009.  if(!PNTS_chunksize) return true;
  3010.  
  3011.  // save PNTS + PNTS_chunksize
  3012.  BE_write_uint32(ofile, LWO_PNTS);
  3013.  BE_write_uint32(ofile, PNTS_chunksize);
  3014.  
  3015.  // save points
  3016.  for(uint32 i = 0; i < data.model->vbuffer.elem; i++) {
  3017.      float x = data.model->vbuffer.data[i].vx;
  3018.      float y = data.model->vbuffer.data[i].vy;
  3019.      float z = data.model->vbuffer.data[i].vz;
  3020.      BE_write_real32(ofile, x);
  3021.      BE_write_real32(ofile, y);
  3022.      BE_write_real32(ofile, z);
  3023.     }
  3024.  
  3025.  return true;
  3026. }
  3027.  
  3028. //
  3029. // POLS
  3030. //
  3031.  
  3032. template<class T>
  3033. uint32 computeHelperPOLS(const IDX_BUFFER& ib)
  3034. {
  3035.  uint32 datasize = 0;
  3036.  
  3037.  if(ib.type == FACE_TYPE_TRIANGLES)
  3038.    {
  3039.     // for number of vertices and flags
  3040.     uint32 n_triangles = ib.elem/3;
  3041.     datasize += 2*n_triangles;
  3042.  
  3043.     // for indices
  3044.     const T limit = (T)0xFF00;
  3045.     const T* buffer = (const T*)(ib.data.get());
  3046.     for(uint32 j = 0; j < ib.elem; j++) {
  3047.         if(buffer[j] < limit) datasize += 2;
  3048.         else datasize += 4;
  3049.        }
  3050.    }
  3051.  else if(ib.type == FACE_TYPE_TRISTRIP)
  3052.    {
  3053.    }
  3054.  else if(ib.type == FACE_TYPE_TRISTRIPCUT)
  3055.    {
  3056.    }
  3057.  
  3058.  return datasize;
  3059. }
  3060.  
  3061. template<class T>
  3062. bool saveHelperPOLS(const IDX_BUFFER& ib, std::ofstream& ofile)
  3063. {
  3064.  if(ib.type == FACE_TYPE_TRIANGLES)
  3065.    {
  3066.     uint32 index = 0;
  3067.     uint32 n_triangles = ib.elem/3;
  3068.     const T* buffer = reinterpret_cast<const T*>(ib.data.get());
  3069.     for(uint32 j = 0; j < n_triangles; j++) {
  3070.         BE_write_uint16(ofile, 0x0003);     // number of vertices + flags
  3071.         uint32 a = (uint32)buffer[index++]; // vertex
  3072.         uint32 b = (uint32)buffer[index++]; // vertex
  3073.         uint32 c = (uint32)buffer[index++]; // vertex
  3074.         if(a < 0xFF00) BE_write_uint16(ofile, (uint16)a); else BE_write_uint32(ofile, lwConvertToVX(a));
  3075.         if(b < 0xFF00) BE_write_uint16(ofile, (uint16)b); else BE_write_uint32(ofile, lwConvertToVX(b));
  3076.         if(c < 0xFF00) BE_write_uint16(ofile, (uint16)c); else BE_write_uint32(ofile, lwConvertToVX(c));
  3077.        }
  3078.    }
  3079.  else if(ib.type == FACE_TYPE_TRISTRIP)
  3080.    {
  3081.    }
  3082.  else if(ib.type == FACE_TYPE_TRISTRIPCUT)
  3083.    {
  3084.    }
  3085.  
  3086.  return true;
  3087. }
  3088.  
  3089. void lwConverter::computePOLSChunkSize(void)
  3090. {
  3091.  // compute chunksize
  3092.  POLS_chunksize = 0;
  3093.  if(data.model->ibuffer.size()) {
  3094.     POLS_chunksize += 0x04; // FACE
  3095.     for(uint32 i = 0; i < data.model->ibuffer.size(); i++) {
  3096.         // for indices
  3097.         IDX_BUFFER& ib = data.model->ibuffer[i];
  3098.         if(ib.format == FACE_FORMAT_UINT_32) POLS_chunksize += computeHelperPOLS<const uint32>(ib);
  3099.         else if(ib.format == FACE_FORMAT_UINT_16) POLS_chunksize += computeHelperPOLS<const uint16>(ib);
  3100.         else if(ib.format == FACE_FORMAT_UINT_08) POLS_chunksize += computeHelperPOLS<const uint08>(ib);
  3101.        }
  3102.    }
  3103. }
  3104.  
  3105. bool lwConverter::savePOLS(void)
  3106. {
  3107.  // don't save chunk if there are no POLS
  3108.  if(!POLS_chunksize) return true;
  3109.  
  3110.  // save PNTS + PNTS_chunksize + FACE
  3111.  BE_write_uint32(ofile, LWO_POLS);
  3112.  BE_write_uint32(ofile, POLS_chunksize);
  3113.  BE_write_uint32(ofile, LWO_FACE);
  3114.  
  3115.  // save polygons
  3116.  for(uint32 i = 0; i < data.model->ibuffer.size(); i++) {
  3117.      IDX_BUFFER& ib = data.model->ibuffer[i];
  3118.      if(ib.format == FACE_FORMAT_UINT_32) saveHelperPOLS<const uint32>(ib, ofile);
  3119.      if(ib.format == FACE_FORMAT_UINT_16) saveHelperPOLS<const uint16>(ib, ofile);
  3120.      if(ib.format == FACE_FORMAT_UINT_08) saveHelperPOLS<const uint08>(ib, ofile);
  3121.     }
  3122.  
  3123.  return true;
  3124. }
  3125.  
  3126. //
  3127. // PTAG:SURF
  3128. //
  3129.  
  3130. void lwConverter::computePTAGChunkSize(void)
  3131. {
  3132.  // compute chunksize
  3133.  PTAG_chunksize = 0;
  3134.  if(data.model->ibuffer.size())
  3135.    {
  3136.     PTAG_chunksize += 0x04; // SURF
  3137.     for(uint32 i = 0; i < (uint32)data.model->ibuffer.size(); i++)
  3138.        {
  3139.         // compute size of VX + tag
  3140.         IDX_BUFFER& ib = data.model->ibuffer[i];
  3141.         if(ib.tris < 0xFF00) {
  3142.            PTAG_chunksize += ib.tris*2; // VX
  3143.            PTAG_chunksize += ib.tris*2; // tag
  3144.           }
  3145.         else {
  3146.            PTAG_chunksize += 0xFF00*2; // VX
  3147.            PTAG_chunksize += (ib.tris - 0xFF00)*4; // VX
  3148.            PTAG_chunksize += ib.tris*2; // tag
  3149.           }
  3150.        }
  3151.    }
  3152. }
  3153.  
  3154. bool lwConverter::savePTAG(void)
  3155. {
  3156.  // don't save chunk if there are no TAGS
  3157.  if(!PTAG_chunksize) return true;
  3158.  
  3159.  // save PTAG + PTAG_chunksize + SURF
  3160.  BE_write_uint32(ofile, LWO_PTAG);
  3161.  BE_write_uint32(ofile, PTAG_chunksize);
  3162.  BE_write_uint32(ofile, LWO_SURF);
  3163.  
  3164.  // save VX + tags
  3165.  uint32 total_triangles = 0;
  3166.  for(uint32 i = 0; i < (uint32)data.model->ibuffer.size(); i++)
  3167.     {
  3168.      // get index buffer
  3169.      IDX_BUFFER& ib = data.model->ibuffer[i];
  3170.      if(!ib.elem) continue;
  3171.  
  3172.      // for each triangle
  3173.      for(uint32 j = 0; j < ib.tris; j++)
  3174.         {
  3175.          // save VX
  3176.          uint32 v1 = total_triangles + j;
  3177.          if(v1 < 0xFF00) BE_write_uint16(ofile, (uint16)v1);
  3178.          else BE_write_uint32(ofile, lwConvertToVX(v1));
  3179.     
  3180.          // save tag
  3181.          uint16 v2 = (uint16)i;
  3182.          BE_write_uint16(ofile, v2);
  3183.         }
  3184.  
  3185.      // update triangles seen
  3186.      total_triangles += ib.tris;
  3187.     }
  3188.  
  3189.  return true;
  3190. }
  3191.  
  3192. //
  3193. // VMAP:TXUV
  3194. //
  3195.  
  3196. void lwConverter::computeTXUVChunkSize(void)
  3197. {
  3198.  // must have surfaces
  3199.  uint32 n_surface = (uint32)data.model->ibuffer.size();
  3200.  if(!n_surface) return;
  3201.  
  3202.  // create chunksize array
  3203.  TXUV_chunksize.reset(new uint32[n_surface]);
  3204.  for(uint32 i = 0; i < n_surface; i++) TXUV_chunksize[i] = 0;
  3205.  
  3206.  // for each surface
  3207.  for(uint32 i = 0; i < n_surface; i++)
  3208.     {
  3209.      // get index buffer
  3210.      IDX_BUFFER& ib = data.model->ibuffer[i];
  3211.      if(!ib.elem) continue;
  3212.  
  3213.      // build a set of vertex indices used in surface
  3214.      std::set<uint32> iset;
  3215.      if(ib.format == FACE_FORMAT_UINT_32) {
  3216.         const uint32* ptr = reinterpret_cast<const uint32*>(ib.data.get());
  3217.         for(uint32 j = 0; j < ib.elem; j++) iset.insert((uint32)(ptr[j]));
  3218.        }
  3219.      else if(ib.format == FACE_FORMAT_UINT_16) {
  3220.         const uint16* ptr = reinterpret_cast<const uint16*>(ib.data.get());
  3221.         for(uint32 j = 0; j < ib.elem; j++) iset.insert((uint32)(ptr[j]));
  3222.        }
  3223.      else if(ib.format == FACE_FORMAT_UINT_08) {
  3224.         const uint08* ptr = reinterpret_cast<const uint08*>(ib.data.get());
  3225.         for(uint32 j = 0; j < ib.elem; j++) iset.insert((uint32)(ptr[j]));
  3226.        }
  3227.  
  3228.      // TXUV + dimension + name
  3229.      TXUV_chunksize[i] += 0x04;
  3230.      TXUV_chunksize[i] += 0x02;
  3231.      TXUV_chunksize[i] += align02(ib.name.length() + 1);
  3232.  
  3233.      // VX + data
  3234.      for(std::set<uint32>::iterator ptr = iset.begin(); ptr != iset.end(); ptr++) {
  3235.          if((*ptr) < 0xFF00) TXUV_chunksize[i] += 0x02;
  3236.          else TXUV_chunksize[i] += 0x04;
  3237.          TXUV_chunksize[i] += 0x08;
  3238.         }
  3239.     }
  3240. }
  3241.  
  3242. bool lwConverter::saveTXUV(void)
  3243. {
  3244.  // don't save chunk if there are no TXUV
  3245.  if(!TXUV_chunksize) return true;
  3246.  
  3247.  // must have vertex buffer
  3248.  const VTX_BUFFER& vb = data.model->vbuffer;
  3249.  if(!vb.elem) return true;
  3250.  
  3251.  // save UV maps
  3252.  uint32 n_surface = (uint32)data.model->ibuffer.size();
  3253.  for(size_t i = 0; i < n_surface; i++)
  3254.     {
  3255.      // get index buffer
  3256.      IDX_BUFFER& ib = data.model->ibuffer[i];
  3257.      if(TXUV_chunksize[i] == 0) continue;
  3258.  
  3259.      // build a set of vertex indices used in surface
  3260.      std::set<uint32> iset;
  3261.      if(ib.format == FACE_FORMAT_UINT_32) {
  3262.         const uint32* ptr = reinterpret_cast<const uint32*>(ib.data.get());
  3263.         for(uint32 j = 0; j < ib.elem; j++) iset.insert((uint32)(ptr[j]));
  3264.        }
  3265.      else if(ib.format == FACE_FORMAT_UINT_16) {
  3266.         const uint16* ptr = reinterpret_cast<const uint16*>(ib.data.get());
  3267.         for(uint32 j = 0; j < ib.elem; j++) iset.insert((uint32)(ptr[j]));
  3268.        }
  3269.      else if(ib.format == FACE_FORMAT_UINT_08) {
  3270.         const uint08* ptr = reinterpret_cast<const uint08*>(ib.data.get());
  3271.         for(uint32 j = 0; j < ib.elem; j++) iset.insert((uint32)(ptr[j]));
  3272.        }
  3273.  
  3274.      // save chunkname, chunksize
  3275.      BE_write_uint32(ofile, LWO_VMAP);
  3276.      BE_write_uint32(ofile, TXUV_chunksize[i]);
  3277.  
  3278.      // save type and dimension
  3279.      BE_write_uint32(ofile, LWO_TXUV);
  3280.      BE_write_uint16(ofile, 2);
  3281.  
  3282.      // save name
  3283.      write_aligned_string_02(ofile, ib.name.c_str());
  3284.  
  3285.      // save UV map
  3286.      for(std::set<uint32>::iterator ptr = iset.begin(); ptr != iset.end(); ptr++) {
  3287.          uint32 index = *ptr;
  3288.          if(index < 0xFF00) BE_write_uint16(ofile, (uint16)index);
  3289.          else BE_write_uint32(ofile, lwConvertToVX(index));
  3290.          BE_write_real32(ofile, vb.data[index].tu);
  3291.          BE_write_real32(ofile, vb.data[index].tv);
  3292.         }
  3293.     }
  3294.  
  3295.  return true;
  3296. }
  3297.  
  3298. //
  3299. // VMAP:WGHT
  3300. //
  3301.  
  3302. void lwConverter::computeWGHTChunkSize(void)
  3303. {
  3304.  // nothing to compute
  3305.  if(!n_wmaps) return;
  3306.  
  3307.  // create chunksize array
  3308.  WGHT_chunksize.reset(new uint32[n_wmaps]);
  3309.  for(uint32 i = 0; i < n_wmaps; i++) WGHT_chunksize[i] = 0;
  3310.  
  3311.  // for each weight map
  3312.  for(uint32 i = 0; i < n_wmaps; i++)
  3313.     {
  3314.      // skip, nothing in weight map
  3315.      const lwWeightMap& wm = wmapdata[i];
  3316.      if(!wm.data.size()) continue;
  3317.  
  3318.      // WGHT + dimension + name
  3319.      WGHT_chunksize[i] += 0x04;
  3320.      WGHT_chunksize[i] += 0x02;
  3321.      WGHT_chunksize[i] += align02(wm.name.length() + 1);
  3322.  
  3323.      // VX + data
  3324.      for(uint32 j = 0; j < wm.data.size(); j++) {
  3325.          if(wm.data[j].index < 0xFF00) WGHT_chunksize[i] += 0x02;
  3326.          else WGHT_chunksize[i] += 0x04;
  3327.          WGHT_chunksize[i] += 0x04;
  3328.         }
  3329.     }
  3330. }
  3331.  
  3332. bool lwConverter::saveWGHT(void)
  3333. {
  3334.  // don't save chunk if there are no WGHT
  3335.  if(!WGHT_chunksize) return true;
  3336.  
  3337.  // save WGHT maps
  3338.  for(size_t i = 0; i < n_wmaps; i++)
  3339.     {
  3340.      // skip, nothing in weight map
  3341.      const lwWeightMap& wm = wmapdata[i];
  3342.      if(!wm.data.size()) continue;
  3343.  
  3344.      // save chunkname, chunksize
  3345.      BE_write_uint32(ofile, LWO_VMAP);
  3346.      BE_write_uint32(ofile, WGHT_chunksize[i]);
  3347.  
  3348.      // save type and dimension
  3349.      BE_write_uint32(ofile, LWO_WGHT);
  3350.      BE_write_uint16(ofile, 1);
  3351.  
  3352.      // save name
  3353.      write_aligned_string_02(ofile, wm.name.c_str());
  3354.  
  3355.      // save VX + data
  3356.      for(uint32 j = 0; j < wm.data.size(); j++) {
  3357.          uint32 index = wm.data[j].index;
  3358.          real32 value = wm.data[j].value;
  3359.          if(index < 0xFF00) BE_write_uint16(ofile, (uint16)index);
  3360.          else BE_write_uint32(ofile, lwConvertToVX(index));
  3361.          BE_write_real32(ofile, value);
  3362.         }
  3363.     }
  3364.  
  3365.  return true;
  3366. }
  3367.  
  3368. //
  3369. // LAYR (BONES)
  3370. //
  3371.  
  3372. void lwConverter::computeBONELAYRChunkSize(void)
  3373. {
  3374.  // compute chunksize
  3375.  BONELAYR_chunksize = 0;
  3376.  if(data.skeletons.size()) BONELAYR_chunksize = 0x12;
  3377. }
  3378.  
  3379. bool lwConverter::saveBONELAYR(void)
  3380. {
  3381.  // don't save chunk if there is no skeleton
  3382.  if(!BONELAYR_chunksize) return true;
  3383.  
  3384.  // save LAYR + LAYR_chunksize
  3385.  BE_write_uint32(ofile, LWO_LAYR);
  3386.  BE_write_uint32(ofile, BONELAYR_chunksize);
  3387.  
  3388.  // save LAYR data
  3389.  BE_write_uint16(ofile, 1); // number
  3390.  BE_write_uint16(ofile, 0); // flags
  3391.  BE_write_real32(ofile, 0); // pivot
  3392.  BE_write_real32(ofile, 0); // ...
  3393.  BE_write_real32(ofile, 0); // ...
  3394.  BE_write_uint08(ofile, 0); // name
  3395.  BE_write_uint08(ofile, 0); // ...
  3396.  
  3397.  return true;
  3398. }
  3399.  
  3400. //
  3401. // TAGS (BONES)
  3402. //
  3403.  
  3404. void lwConverter::computeBONETAGSChunkSize(void)
  3405. {
  3406.  // compute chunksize
  3407.  BONETAGS_chunksize = 0;
  3408.  for(size_t i = 0; i < data.skeletons.size(); i++) {
  3409.      const SKELETON& skel = data.skeletons[i];
  3410.      lwJointPolygonTagsChunkSizeCalc lwinfo(ofile);
  3411.      skel.traverse(lwinfo);
  3412.      BONETAGS_chunksize += align02(strlen(skel.get_identifier()) + 1); // surface name
  3413.      BONETAGS_chunksize += lwinfo.getChunkSize(); // bone names
  3414.     }
  3415. }
  3416.  
  3417. bool lwConverter::saveBONETAGS(void)
  3418. {
  3419.  // don't save chunk if there are no TAGS
  3420.  if(!BONETAGS_chunksize) return true;
  3421.  
  3422.  // save TAGS + TAGS_chunksize
  3423.  BE_write_uint32(ofile, LWO_TAGS);
  3424.  BE_write_uint32(ofile, BONETAGS_chunksize);
  3425.  
  3426.  // save surface and bone names
  3427.  for(size_t i = 0; i < data.skeletons.size(); i++) {
  3428.      const SKELETON& skel = data.skeletons[i];
  3429.      write_aligned_string_02(ofile, skel.get_identifier()); // surface name
  3430.      lwJointPolygonTagsSaver lwinfo(ofile); // bone names
  3431.      skel.traverse(lwinfo);
  3432.     }
  3433.  
  3434.  return true;
  3435. }
  3436.  
  3437. //
  3438. // PNTS (BONES)
  3439. //
  3440.  
  3441. void lwConverter::computeBONEPNTSChunkSize(void)
  3442. {
  3443.  // compute chunksize
  3444.  BONEPNTS_chunksize = 0;
  3445.  uint32 n_skeletons = data.skeletons.size();
  3446.  for(uint32 i = 0; i < n_skeletons; i++) BONEPNTS_chunksize += 0x0C*data.skeletons[i].joints();
  3447. }
  3448.  
  3449. bool lwConverter::saveBONEPNTS(void)
  3450. {
  3451.  // don't save chunk if there is no skeleton
  3452.  if(!BONEPNTS_chunksize) return true;
  3453.  
  3454.  // save PNTS + PNTS_chunksize
  3455.  BE_write_uint32(ofile, LWO_PNTS);
  3456.  BE_write_uint32(ofile, BONEPNTS_chunksize);
  3457.  
  3458.  // save joint positions
  3459.  uint32 n_skeletons = data.skeletons.size();
  3460.  for(uint32 i = 0; i < n_skeletons; i++) {
  3461.      const SKELETON& skel = data.skeletons[i];
  3462.      lwJointPointSaver lwjs(ofile);
  3463.      skel.traverse(lwjs);
  3464.     }
  3465.  
  3466.  return true;
  3467. }
  3468.  
  3469. //
  3470. // POLS (BONES)
  3471. //
  3472.  
  3473. void lwConverter::computeBONEPOLSChunkSize(void)
  3474. {
  3475.  // compute chunksize
  3476.  BONEPOLS_chunksize = 0;
  3477.  for(uint32 i = 0; i < data.skeletons.size(); i++) {
  3478.      BONEPOLS_chunksize += 0x04; // BONE
  3479.      const SKELETON& skel = data.skeletons[i];
  3480.      lwJointPolygonChunkSizeCalc lwinfo(ofile);
  3481.      skel.traverse(lwinfo);
  3482.      BONEPOLS_chunksize += lwinfo.getChunkSize();
  3483.     }
  3484. }
  3485.  
  3486. bool lwConverter::saveBONEPOLS(void)
  3487. {
  3488.  // don't save chunk if there is no skeleton
  3489.  if(!BONEPOLS_chunksize) return true;
  3490.  
  3491.  // save POLS + POLS_chunksize
  3492.  BE_write_uint32(ofile, LWO_POLS);
  3493.  BE_write_uint32(ofile, BONEPOLS_chunksize);
  3494.  BE_write_uint32(ofile, LWO_BONE);
  3495.  
  3496.  // save joint polygons
  3497.  uint32 n_skeletons = data.skeletons.size();
  3498.  for(uint32 i = 0; i < n_skeletons; i++) {
  3499.      const SKELETON& skel = data.skeletons[i];
  3500.      lwJointPolygonSaver lwinfo(ofile);
  3501.      skel.traverse(lwinfo);
  3502.     }
  3503.  
  3504.  return true;
  3505. }
  3506.  
  3507. //
  3508. // PTAG:BONE (BONES)
  3509. //
  3510.  
  3511. void lwConverter::computeBONEPTAGChunkSize(void)
  3512. {
  3513.  // compute chunksize
  3514.  BONEPTAG_chunksize = 0;
  3515.  if(!data.skeletons.size()) return;
  3516.  
  3517.  // BONE
  3518.  uint32 n_skeletons = data.skeletons.size();
  3519.  BONEPTAG_chunksize += 0x04;
  3520.  
  3521.  // VX + tags
  3522.  for(uint32 i = 0; i < n_skeletons; i++) {
  3523.      const SKELETON& skel = data.skeletons[i];
  3524.      lwJointPolyTagChunkSizeCalc lwinfo(ofile);
  3525.      skel.traverse(lwinfo);
  3526.      BONEPTAG_chunksize += lwinfo.getChunkSize();
  3527.     }
  3528. }
  3529.  
  3530. bool lwConverter::saveBONEPTAG(void)
  3531. {
  3532.  // don't save chunk if there is no skeleton
  3533.  if(!BONEPTAG_chunksize) return true;
  3534.  
  3535.  // save PTAG + PTAG_chunksize
  3536.  BE_write_uint32(ofile, LWO_PTAG);
  3537.  BE_write_uint32(ofile, BONEPTAG_chunksize);
  3538.  BE_write_uint32(ofile, LWO_BONE);
  3539.  
  3540.  // save joint polygon tags
  3541.  uint32 n_skeletons = data.skeletons.size();
  3542.  for(uint32 i = 0; i < n_skeletons; i++) {
  3543.      const SKELETON& skel = data.skeletons[i];
  3544.      lwJointPolyTagSaver lwinfo(ofile);
  3545.      skel.traverse(lwinfo);
  3546.     }
  3547.  
  3548.  return true;
  3549. }
  3550.  
  3551. //
  3552. // PTAG:PART (BONES)
  3553. //
  3554.  
  3555. void lwConverter::computeBONEPARTChunkSize(void)
  3556. {
  3557.  // compute chunksize
  3558.  BONEPART_chunksize = 0;
  3559.  if(!data.skeletons.size()) return;
  3560.  
  3561.  // BONE
  3562.  uint32 n_skeletons = data.skeletons.size();
  3563.  BONEPART_chunksize += 0x04;
  3564.  
  3565.  // VX + tags
  3566.  for(uint32 i = 0; i < n_skeletons; i++) {
  3567.      const SKELETON& skel = data.skeletons[i];
  3568.      lwJointPartTagChunkSizeCalc lwinfo(ofile);
  3569.      skel.traverse(lwinfo);
  3570.      BONEPART_chunksize += lwinfo.getChunkSize();
  3571.     }
  3572. }
  3573.  
  3574. bool lwConverter::saveBONEPART(void)
  3575. {
  3576.  // don't save chunk if there is no skeleton
  3577.  if(!BONEPART_chunksize) return true;
  3578.  
  3579.  // save PTAG + PTAG_chunksize
  3580.  BE_write_uint32(ofile, LWO_PTAG);
  3581.  BE_write_uint32(ofile, BONEPART_chunksize);
  3582.  BE_write_uint32(ofile, LWO_PART);
  3583.  
  3584.  // save joint polygon tags
  3585.  uint32 n_skeletons = data.skeletons.size();
  3586.  for(uint32 i = 0; i < n_skeletons; i++) {
  3587.      const SKELETON& skel = data.skeletons[i];
  3588.      lwJointPartTagSaver lwinfo(ofile);
  3589.      skel.traverse(lwinfo);
  3590.     }
  3591.  
  3592.  return true;
  3593. }
  3594.  
  3595.  
  3596.  
  3597.  
  3598.  
  3599.  
  3600.  
  3601. uint32 lwGetCLIPContribution(const boost::shared_array<uint32>& chunksize, uint32 n);
  3602. boost::shared_array<uint32> lwGetCLIPChunkSize(const SIMPLEMODELCONTAINER& data);
  3603. bool lwSaveCLIP(std::ofstream& ofile, const SIMPLEMODELCONTAINER& data, const boost::shared_array<uint32>& chunksize);
  3604.  
  3605. boost::shared_array<uint32> lwGetSURFChunkSize(const SIMPLEMODELCONTAINER& data);
  3606. bool lwSaveSURF(std::ofstream& ofile, const SIMPLEMODELCONTAINER& data, const boost::shared_array<uint32>& chunksize);
  3607.  
  3608. bool lwSaveVmapTxuv(std::ofstream& ofile, const SIMPLEMODELCONTAINER& data, const boost::shared_array<uint32>& TXUV_chunksize);
  3609.  
  3610. bool GeometryToLWO(const char* path, const char* name, const SIMPLEMODELCONTAINER& data)
  3611. {
  3612.  lwConverter lwc(data);
  3613.  return lwc.convert(path, name);
  3614. }
  3615.  
  3616. //
  3617. // LWO_CLIP
  3618. //
  3619.  
  3620. uint32 lwGetCLIPContribution(const boost::shared_array<uint32>& chunksize, uint32 n)
  3621. {
  3622.  uint32 retval = 0;
  3623.  for(uint32 i = 0; i < n; i++) {
  3624.      retval += 0x04;         // CLIP
  3625.      retval += 0x04;         // chunksize
  3626.      retval += chunksize[i]; // chunkdata
  3627.     }
  3628.  return retval;
  3629. }
  3630.  
  3631. boost::shared_array<uint32> lwGetCLIPChunkSize(const SIMPLEMODELCONTAINER& data)
  3632. {
  3633.  // must have textures
  3634.  boost::shared_array<uint32> retval;
  3635.  if(data.textures.size() == 0) return retval;
  3636.  
  3637.  // compute chunksizes
  3638.  retval.reset(new uint32[data.textures.size()]);
  3639.  for(uint32 i = 0; i < data.textures.size(); i++)
  3640.     {
  3641.      // get texture
  3642.      const TEXTURE& tex = data.textures[i];
  3643.      retval[i] = 0;
  3644.  
  3645.      // index
  3646.      retval[i] += 0x04;
  3647.  
  3648.      // STIL
  3649.      retval[i] += 0x04;
  3650.  
  3651.      // STIL chunksize
  3652.      retval[i] += 0x02;
  3653.  
  3654.      // filename
  3655.      uint32 namelen = tex.filename.length() + 1;
  3656.      retval[i] += align02(namelen);
  3657.  
  3658.      // FLAG, chunksize, flags
  3659.      retval[i] += 0x0A;
  3660.     }
  3661.  
  3662.  return retval;
  3663. }
  3664.  
  3665. bool lwSaveCLIP(std::ofstream& ofile, const SIMPLEMODELCONTAINER& data, const boost::shared_array<uint32>& chunksize)
  3666. {
  3667.  // for each texture
  3668.  for(uint32 i = 0; i < (uint32)data.textures.size(); i++)
  3669.     {
  3670.      // get texture
  3671.      const TEXTURE& tex = data.textures[i];
  3672.  
  3673.      // save chunkname, chunksize
  3674.      BE_write_uint32(ofile, LWO_CLIP);
  3675.      BE_write_uint32(ofile, chunksize[i]);
  3676.  
  3677.      // save index
  3678.      uint32 clipindex = (i + 1);
  3679.      BE_write_uint32(ofile, clipindex);
  3680.  
  3681.      // save STIL
  3682.      BE_write_uint32(ofile, LWO_STIL);
  3683.  
  3684.      // save STIL chunksize
  3685.      uint16 namelen = (uint16)(tex.filename.length() + 1);
  3686.      namelen = align02(namelen);
  3687.      BE_write_uint16(ofile, namelen);
  3688.  
  3689.      // save filename
  3690.      write_aligned_string_02(ofile, tex.filename.c_str());
  3691.  
  3692.      // save FLAG
  3693.      BE_write_uint32(ofile, LWO_FLAG);
  3694.      BE_write_uint16(ofile, 0x0004);
  3695.      BE_write_uint16(ofile, 0x0800);
  3696.      BE_write_uint16(ofile, 0x0080);
  3697.     }
  3698.  
  3699.  return true;
  3700. }
  3701.  
  3702. //
  3703. // LWO_SURF
  3704. //
  3705.  
  3706. boost::shared_array<uint32> lwGetSURFChunkSize(const SIMPLEMODELCONTAINER& data)
  3707. {
  3708.  // must have index buffer
  3709.  boost::shared_array<uint32> retval;
  3710.  if(data.model->ibuffer.size() == 0) return retval;
  3711.  
  3712.  uint32 n_surface = (uint32)data.model->ibuffer.size();
  3713.  retval.reset(new uint32[n_surface]);
  3714.  
  3715.  // for each surface
  3716.  for(uint32 i = 0; i < n_surface; i++)
  3717.     {
  3718.      // get index buffer
  3719.      IDX_BUFFER& ib = data.model->ibuffer[i];
  3720.      if(!ib.elem) continue;
  3721.  
  3722.      // initialize chunksize
  3723.      retval[i] = 0;
  3724.  
  3725.      // name
  3726.      uint32 namelen = ib.name.length() + 1;
  3727.      retval[i] += align02(namelen);
  3728.  
  3729.      // source
  3730.      retval[i] += 2;
  3731.  
  3732.      // color, diffuse, specular
  3733.      retval[i] += 0x14;
  3734.      retval[i] += 0x0C;
  3735.      retval[i] += 0x0C;
  3736.  
  3737.      // materials
  3738.      if((ib.material != 0xFFFFFFFF) && (ib.material < data.materials.size()))
  3739.        {
  3740.         // base color map
  3741.         const MATERIAL& mat = data.materials[ib.material];
  3742.         if((mat.basemap != 0xFFFFFFFF) && (mat.basemap < data.textures.size()))
  3743.           {
  3744.            retval[i] += 0x06; // BLOK, chunksize
  3745.            retval[i] += 0x08; // IMAP, chunksize
  3746.            retval[i] += 0x0A; // CHAN, chunksize, channel
  3747.            retval[i] += 0x0E; // OPAC, chunksize, type, opacity, envelope
  3748.            retval[i] += 0x08; // ENAB, chunksize, bool
  3749.            retval[i] += 0x08; // NEGA, chunksize, bool
  3750.            retval[i] += 0x06; // TMAP, chunksize
  3751.            retval[i] += 0x14; // CNTR, chunksize, x, y, z, envelope
  3752.            retval[i] += 0x14; // SIZE, chunksize, x, y, z, envelope
  3753.            retval[i] += 0x14; // ROTA, chunksize, x, y, z, envelope
  3754.            retval[i] += 0x16; // FALL, chunksize, type, x, y, z, envelope
  3755.            retval[i] += 0x08; // PROJ, chunksize, mode
  3756.            retval[i] += 0x08; // OREF, chunksize, name
  3757.            retval[i] += 0x08; // CSYS, chunksize, type
  3758.            retval[i] += 0x08; // AXIS, chunksize, axis
  3759.            retval[i] += 0x08; // IMAG, chunksize, clip
  3760.            retval[i] += 0x0A; // WRAP, chunksize, wrap, wrap
  3761.            retval[i] += 0x0C; // WRPW, chunksize, cycles, envelope
  3762.            retval[i] += 0x0C; // WRPW, chunksize, cycles, envelope
  3763.            retval[i] += 0x06; // VMAP, chunksize, string
  3764.            retval[i] += align02(ib.name.length() + 1);
  3765.            retval[i] += 0x0C; // AAST, chunksize, flags, strength
  3766.            retval[i] += 0x08; // PIXB, chunksize, flags
  3767.           }
  3768.  
  3769.         // specular map
  3770.         if((mat.specmap != 0xFFFFFFFF) && (mat.specmap < data.textures.size()))
  3771.           {
  3772.            retval[i] += 0x06; // BLOK, chunksize
  3773.            retval[i] += 0x08; // IMAP, chunksize
  3774.            retval[i] += 0x0A; // CHAN, chunksize, channel
  3775.            retval[i] += 0x0E; // OPAC, chunksize, type, opacity, envelope
  3776.            retval[i] += 0x08; // ENAB, chunksize, bool
  3777.            retval[i] += 0x08; // NEGA, chunksize, bool
  3778.            retval[i] += 0x06; // TMAP, chunksize
  3779.            retval[i] += 0x14; // CNTR, chunksize, x, y, z, envelope
  3780.            retval[i] += 0x14; // SIZE, chunksize, x, y, z, envelope
  3781.            retval[i] += 0x14; // ROTA, chunksize, x, y, z, envelope
  3782.            retval[i] += 0x16; // FALL, chunksize, type, x, y, z, envelope
  3783.            retval[i] += 0x08; // OREF, chunksize, name
  3784.            retval[i] += 0x08; // CSYS, chunksize, type
  3785.            retval[i] += 0x08; // PROJ, chunksize, mode
  3786.            retval[i] += 0x08; // AXIS, chunksize, axis
  3787.            retval[i] += 0x08; // IMAG, chunksize, clip
  3788.            retval[i] += 0x0A; // WRAP, chunksize, wrap, wrap
  3789.            retval[i] += 0x0C; // WRPW, chunksize, cycles, envelope
  3790.            retval[i] += 0x0C; // WRPW, chunksize, cycles, envelope
  3791.            retval[i] += 0x06; // VMAP, chunksize, string
  3792.            retval[i] += align02(ib.name.length() + 1);
  3793.            retval[i] += 0x0C; // AAST, chunksize, flags, strength
  3794.            retval[i] += 0x08; // PIXB, chunksize, flags
  3795.           }
  3796.  
  3797.         // TODO
  3798.         // normal map
  3799.         if((mat.normmap != 0xFFFFFFFF) && (mat.normmap < data.textures.size()))
  3800.           {
  3801.           }
  3802.        }
  3803.     }
  3804.  
  3805.  return retval;
  3806. }
  3807.  
  3808. bool lwSaveSURF(std::ofstream& ofile, const SIMPLEMODELCONTAINER& data, const boost::shared_array<uint32>& chunksize)
  3809. {
  3810.  // must have index buffer
  3811.  if(data.model->ibuffer.size() == 0)
  3812.     return true;
  3813.  
  3814.  // surface names
  3815.  for(size_t i = 0; i < data.model->ibuffer.size(); i++)
  3816.     {
  3817.      // get index buffer
  3818.      IDX_BUFFER& ib = data.model->ibuffer[i];
  3819.      if(!ib.elem) continue;
  3820.  
  3821.      // save chunkname, chunksize
  3822.      BE_write_uint32(ofile, LWO_SURF);
  3823.      BE_write_uint32(ofile, chunksize[i]);
  3824.  
  3825.      // save name
  3826.      write_aligned_string_02(ofile, ib.name.c_str());
  3827.  
  3828.      // save source
  3829.      BE_write_uint08(ofile, 0);
  3830.      BE_write_uint08(ofile, 0);
  3831.  
  3832.      // save color
  3833.      BE_write_uint32(ofile, LWO_COLR);
  3834.      BE_write_uint16(ofile, 0x0E);
  3835.      BE_write_uint32(ofile, 0x3F48C8C9);
  3836.      BE_write_uint32(ofile, 0x3F48C8C9);
  3837.      BE_write_uint32(ofile, 0x3F48C8C9);
  3838.      BE_write_uint16(ofile, 0x00);
  3839.  
  3840.      // save diffuse
  3841.      BE_write_uint32(ofile, LWO_DIFF);
  3842.      BE_write_uint16(ofile, 0x06);
  3843.      BE_write_uint32(ofile, 0x3F800000);
  3844.      BE_write_uint16(ofile, 0x00);
  3845.  
  3846.      // save specular
  3847.      BE_write_uint32(ofile, LWO_SPEC);
  3848.      BE_write_uint16(ofile, 0x06);
  3849.      BE_write_uint32(ofile, 0x00000000);
  3850.      BE_write_uint16(ofile, 0x00);
  3851.  
  3852.      // materials
  3853.      if((ib.material != 0xFFFFFFFF) && (ib.material < data.materials.size()))
  3854.        {
  3855.         // base color map
  3856.         const MATERIAL& mat = data.materials[ib.material];
  3857.         if((mat.basemap != 0xFFFFFFFF) && (mat.basemap < data.textures.size()))
  3858.           {
  3859.            // BLCK
  3860.            uint16 BLOK_chunksize = 0xEA + (uint16)align02(ib.name.length() + 1);
  3861.            BE_write_uint32(ofile, LWO_BLOK);
  3862.            BE_write_uint16(ofile, BLOK_chunksize);
  3863.  
  3864.            // IMAP
  3865.            uint16 IMAP_chunksize = 0x2A;
  3866.            BE_write_uint32(ofile, LWO_IMAP);
  3867.            BE_write_uint16(ofile, IMAP_chunksize);
  3868.            BE_write_uint16(ofile, 0x8000); // ordinal
  3869.  
  3870.            // CHAN
  3871.            uint16 CHAN_chunksize = 0x04;
  3872.            BE_write_uint32(ofile, LWO_CHAN);
  3873.            BE_write_uint16(ofile, CHAN_chunksize);
  3874.            BE_write_uint32(ofile, LWO_COLR);
  3875.  
  3876.            // OPAC
  3877.            uint16 OPAC_chunksize = 0x08;
  3878.            BE_write_uint32(ofile, LWO_OPAC);
  3879.            BE_write_uint16(ofile, OPAC_chunksize);
  3880.            BE_write_uint16(ofile, 0x00);
  3881.            BE_write_uint32(ofile, 0x3F800000);
  3882.            BE_write_uint16(ofile, 0x00);
  3883.  
  3884.            // ENAB
  3885.            uint16 ENAB_chunksize = 0x02;
  3886.            BE_write_uint32(ofile, LWO_ENAB);
  3887.            BE_write_uint16(ofile, ENAB_chunksize);
  3888.            BE_write_uint16(ofile, 0x01);
  3889.  
  3890.            // NEGA
  3891.            uint16 NEGA_chunksize = 0x02;
  3892.            BE_write_uint32(ofile, LWO_NEGA);
  3893.            BE_write_uint16(ofile, NEGA_chunksize);
  3894.            BE_write_uint16(ofile, 0x00);
  3895.  
  3896.            // TMAP
  3897.            uint16 TMAP_chunksize = 0x5A;
  3898.            BE_write_uint32(ofile, LWO_TMAP);
  3899.            BE_write_uint16(ofile, TMAP_chunksize);
  3900.  
  3901.            // CNTR
  3902.            uint16 CNTR_chunksize = 0x0E;
  3903.            BE_write_uint32(ofile, LWO_CNTR);
  3904.            BE_write_uint16(ofile, CNTR_chunksize);
  3905.            BE_write_uint32(ofile, 0x00000000);
  3906.            BE_write_uint32(ofile, 0x00000000);
  3907.            BE_write_uint32(ofile, 0x00000000);
  3908.            BE_write_uint16(ofile, 0x00);
  3909.  
  3910.            // SIZE
  3911.            uint16 SIZE_chunksize = 0x0E;
  3912.            BE_write_uint32(ofile, LWO_SIZE);
  3913.            BE_write_uint16(ofile, SIZE_chunksize);
  3914.            BE_write_uint32(ofile, 0x3F800000);
  3915.            BE_write_uint32(ofile, 0x3F800000);
  3916.            BE_write_uint32(ofile, 0x3F800000);
  3917.            BE_write_uint16(ofile, 0x00);
  3918.  
  3919.            // ROTA
  3920.            uint16 ROTA_chunksize = 0x0E;
  3921.            BE_write_uint32(ofile, LWO_ROTA);
  3922.            BE_write_uint16(ofile, ROTA_chunksize);
  3923.            BE_write_uint32(ofile, 0x00000000);
  3924.            BE_write_uint32(ofile, 0x00000000);
  3925.            BE_write_uint32(ofile, 0x00000000);
  3926.            BE_write_uint16(ofile, 0x00);
  3927.  
  3928.            // FALL
  3929.            uint16 FALL_chunksize = 0x10;
  3930.            BE_write_uint32(ofile, LWO_FALL);
  3931.            BE_write_uint16(ofile, FALL_chunksize);
  3932.            BE_write_uint16(ofile, 0x00);
  3933.            BE_write_uint32(ofile, 0x00000000);
  3934.            BE_write_uint32(ofile, 0x00000000);
  3935.            BE_write_uint32(ofile, 0x00000000);
  3936.            BE_write_uint16(ofile, 0x00);
  3937.  
  3938.            // OMAP
  3939.            uint16 OMAP_chunksize = 0x02;
  3940.            BE_write_uint32(ofile, LWO_OMAP);
  3941.            BE_write_uint16(ofile, OMAP_chunksize);
  3942.            BE_write_uint16(ofile, 0x0000);
  3943.  
  3944.            // CSYS
  3945.            uint16 CSYS_chunksize = 0x02;
  3946.            BE_write_uint32(ofile, LWO_CSYS);
  3947.            BE_write_uint16(ofile, CSYS_chunksize);
  3948.            BE_write_uint16(ofile, 0x0000);
  3949.  
  3950.            // PROJ
  3951.            uint16 PROJ_chunksize = 0x02;
  3952.            BE_write_uint32(ofile, LWO_PROJ);
  3953.            BE_write_uint16(ofile, PROJ_chunksize);
  3954.            BE_write_uint16(ofile, 0x0005);
  3955.  
  3956.            // AXIS
  3957.            uint16 AXIS_chunksize = 0x02;
  3958.            BE_write_uint32(ofile, LWO_AXIS);
  3959.            BE_write_uint16(ofile, AXIS_chunksize);
  3960.            BE_write_uint16(ofile, 0x0002);
  3961.  
  3962.            // IMAG
  3963.            uint16 IMAG_chunksize = 0x02;
  3964.            BE_write_uint32(ofile, LWO_IMAG);
  3965.            BE_write_uint16(ofile, IMAG_chunksize);
  3966.            BE_write_uint16(ofile, (mat.basemap + 1));
  3967.  
  3968.            // WRAP
  3969.            uint16 WRAP_chunksize = 0x04;
  3970.            BE_write_uint32(ofile, LWO_WRAP);
  3971.            BE_write_uint16(ofile, WRAP_chunksize);
  3972.            BE_write_uint16(ofile, 0x0001);
  3973.            BE_write_uint16(ofile, 0x0001);
  3974.  
  3975.            // WRPW
  3976.            uint16 WRPW_chunksize = 0x06;
  3977.            BE_write_uint32(ofile, LWO_WRPW);
  3978.            BE_write_uint16(ofile, WRPW_chunksize);
  3979.            BE_write_uint32(ofile, 0x3F800000);
  3980.            BE_write_uint16(ofile, 0x0000);
  3981.  
  3982.            // WRPH
  3983.            uint16 WRPH_chunksize = 0x06;
  3984.            BE_write_uint32(ofile, LWO_WRPH);
  3985.            BE_write_uint16(ofile, WRPH_chunksize);
  3986.            BE_write_uint32(ofile, 0x3F800000);
  3987.            BE_write_uint16(ofile, 0x0000);
  3988.  
  3989.            // VMAP
  3990.            uint16 VMAP_chunksize = align02(ib.name.length() + 1);
  3991.            BE_write_uint32(ofile, LWO_VMAP);
  3992.            BE_write_uint16(ofile, VMAP_chunksize);
  3993.            write_aligned_string_02(ofile, ib.name.c_str());
  3994.  
  3995.            // AAST
  3996.            uint16 AAST_chunksize = 0x06;
  3997.            BE_write_uint32(ofile, LWO_AAST);
  3998.            BE_write_uint16(ofile, AAST_chunksize);
  3999.            BE_write_uint16(ofile, 0x0001);
  4000.            BE_write_uint32(ofile, 0x3F800000);
  4001.  
  4002.            // PIXB
  4003.            uint16 PIXB_chunksize = 0x02;
  4004.            BE_write_uint32(ofile, LWO_PIXB);
  4005.            BE_write_uint16(ofile, PIXB_chunksize);
  4006.            BE_write_uint16(ofile, 0x0001);
  4007.           }
  4008.         // specular map
  4009.         if((mat.specmap != 0xFFFFFFFF) && (mat.specmap < data.textures.size()))
  4010.           {
  4011.            // BLCK
  4012.            uint16 BLOK_chunksize = 0xEA + (uint16)align02(ib.name.length() + 1);
  4013.            BE_write_uint32(ofile, LWO_BLOK);
  4014.            BE_write_uint16(ofile, BLOK_chunksize);
  4015.  
  4016.            // IMAP
  4017.            uint16 IMAP_chunksize = 0x2A;
  4018.            BE_write_uint32(ofile, LWO_IMAP);
  4019.            BE_write_uint16(ofile, IMAP_chunksize);
  4020.            BE_write_uint16(ofile, 0x8000); // ordinal
  4021.  
  4022.            // CHAN
  4023.            uint16 CHAN_chunksize = 0x04;
  4024.            BE_write_uint32(ofile, LWO_CHAN);
  4025.            BE_write_uint16(ofile, CHAN_chunksize);
  4026.            BE_write_uint32(ofile, LWO_SPEC);
  4027.  
  4028.            // OPAC
  4029.            uint16 OPAC_chunksize = 0x08;
  4030.            BE_write_uint32(ofile, LWO_OPAC);
  4031.            BE_write_uint16(ofile, OPAC_chunksize);
  4032.            BE_write_uint16(ofile, 0x00);
  4033.            BE_write_uint32(ofile, 0x3F800000);
  4034.            BE_write_uint16(ofile, 0x00);
  4035.  
  4036.            // ENAB
  4037.            uint16 ENAB_chunksize = 0x02;
  4038.            BE_write_uint32(ofile, LWO_ENAB);
  4039.            BE_write_uint16(ofile, ENAB_chunksize);
  4040.            BE_write_uint16(ofile, 0x01);
  4041.  
  4042.            // NEGA
  4043.            uint16 NEGA_chunksize = 0x02;
  4044.            BE_write_uint32(ofile, LWO_NEGA);
  4045.            BE_write_uint16(ofile, NEGA_chunksize);
  4046.            BE_write_uint16(ofile, 0x00);
  4047.  
  4048.            // TMAP
  4049.            uint16 TMAP_chunksize = 0x5A;
  4050.            BE_write_uint32(ofile, LWO_TMAP);
  4051.            BE_write_uint16(ofile, TMAP_chunksize);
  4052.  
  4053.            // CNTR
  4054.            uint16 CNTR_chunksize = 0x0E;
  4055.            BE_write_uint32(ofile, LWO_CNTR);
  4056.            BE_write_uint16(ofile, CNTR_chunksize);
  4057.            BE_write_uint32(ofile, 0x00000000);
  4058.            BE_write_uint32(ofile, 0x00000000);
  4059.            BE_write_uint32(ofile, 0x00000000);
  4060.            BE_write_uint16(ofile, 0x00);
  4061.  
  4062.            // SIZE
  4063.            uint16 SIZE_chunksize = 0x0E;
  4064.            BE_write_uint32(ofile, LWO_SIZE);
  4065.            BE_write_uint16(ofile, SIZE_chunksize);
  4066.            BE_write_uint32(ofile, 0x3F800000);
  4067.            BE_write_uint32(ofile, 0x3F800000);
  4068.            BE_write_uint32(ofile, 0x3F800000);
  4069.            BE_write_uint16(ofile, 0x00);
  4070.  
  4071.            // ROTA
  4072.            uint16 ROTA_chunksize = 0x0E;
  4073.            BE_write_uint32(ofile, LWO_ROTA);
  4074.            BE_write_uint16(ofile, ROTA_chunksize);
  4075.            BE_write_uint32(ofile, 0x00000000);
  4076.            BE_write_uint32(ofile, 0x00000000);
  4077.            BE_write_uint32(ofile, 0x00000000);
  4078.            BE_write_uint16(ofile, 0x00);
  4079.  
  4080.            // FALL
  4081.            uint16 FALL_chunksize = 0x10;
  4082.            BE_write_uint32(ofile, LWO_FALL);
  4083.            BE_write_uint16(ofile, FALL_chunksize);
  4084.            BE_write_uint16(ofile, 0x00);
  4085.            BE_write_uint32(ofile, 0x00000000);
  4086.            BE_write_uint32(ofile, 0x00000000);
  4087.            BE_write_uint32(ofile, 0x00000000);
  4088.            BE_write_uint16(ofile, 0x00);
  4089.  
  4090.            // OMAP
  4091.            uint16 OMAP_chunksize = 0x02;
  4092.            BE_write_uint32(ofile, LWO_OMAP);
  4093.            BE_write_uint16(ofile, OMAP_chunksize);
  4094.            BE_write_uint16(ofile, 0x0000);
  4095.  
  4096.            // CSYS
  4097.            uint16 CSYS_chunksize = 0x02;
  4098.            BE_write_uint32(ofile, LWO_CSYS);
  4099.            BE_write_uint16(ofile, CSYS_chunksize);
  4100.            BE_write_uint16(ofile, 0x0000);
  4101.  
  4102.            // PROJ
  4103.            uint16 PROJ_chunksize = 0x02;
  4104.            BE_write_uint32(ofile, LWO_PROJ);
  4105.            BE_write_uint16(ofile, PROJ_chunksize);
  4106.            BE_write_uint16(ofile, 0x0005);
  4107.  
  4108.            // AXIS
  4109.            uint16 AXIS_chunksize = 0x02;
  4110.            BE_write_uint32(ofile, LWO_AXIS);
  4111.            BE_write_uint16(ofile, AXIS_chunksize);
  4112.            BE_write_uint16(ofile, 0x0002);
  4113.  
  4114.            // IMAG
  4115.            uint16 IMAG_chunksize = 0x02;
  4116.            BE_write_uint32(ofile, LWO_IMAG);
  4117.            BE_write_uint16(ofile, IMAG_chunksize);
  4118.            BE_write_uint16(ofile, (mat.specmap + 1));
  4119.  
  4120.            // WRAP
  4121.            uint16 WRAP_chunksize = 0x04;
  4122.            BE_write_uint32(ofile, LWO_WRAP);
  4123.            BE_write_uint16(ofile, WRAP_chunksize);
  4124.            BE_write_uint16(ofile, 0x0001);
  4125.            BE_write_uint16(ofile, 0x0001);
  4126.  
  4127.            // WRPW
  4128.            uint16 WRPW_chunksize = 0x06;
  4129.            BE_write_uint32(ofile, LWO_WRPW);
  4130.            BE_write_uint16(ofile, WRPW_chunksize);
  4131.            BE_write_uint32(ofile, 0x3F800000);
  4132.            BE_write_uint16(ofile, 0x0000);
  4133.  
  4134.            // WRPH
  4135.            uint16 WRPH_chunksize = 0x06;
  4136.            BE_write_uint32(ofile, LWO_WRPH);
  4137.            BE_write_uint16(ofile, WRPH_chunksize);
  4138.            BE_write_uint32(ofile, 0x3F800000);
  4139.            BE_write_uint16(ofile, 0x0000);
  4140.  
  4141.            // VMAP
  4142.            uint16 VMAP_chunksize = align02(ib.name.length() + 1);
  4143.            BE_write_uint32(ofile, LWO_VMAP);
  4144.            BE_write_uint16(ofile, VMAP_chunksize);
  4145.            write_aligned_string_02(ofile, ib.name.c_str());
  4146.  
  4147.            // AAST
  4148.            uint16 AAST_chunksize = 0x06;
  4149.            BE_write_uint32(ofile, LWO_AAST);
  4150.            BE_write_uint16(ofile, AAST_chunksize);
  4151.            BE_write_uint16(ofile, 0x0001);
  4152.            BE_write_uint32(ofile, 0x3F800000);
  4153.  
  4154.            // PIXB
  4155.            uint16 PIXB_chunksize = 0x02;
  4156.            BE_write_uint32(ofile, LWO_PIXB);
  4157.            BE_write_uint16(ofile, PIXB_chunksize);
  4158.            BE_write_uint16(ofile, 0x0001);
  4159.           }
  4160.         
  4161.         // TODO
  4162.         // normal map
  4163.         if((mat.normmap != 0xFFFFFFFF) && (mat.normmap < data.textures.size()))
  4164.           {
  4165.           }
  4166.        }
  4167.     }
  4168.  
  4169.  return true;
  4170. }
  4171. */
  4172.