home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 5164 / miletos.7z / mesh3ds.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2011-04-02  |  20.9 KB  |  782 lines

  1. #define __MILETOS_MESH3DS_CPP__
  2.  
  3. //
  4. // Libmiletos
  5. //
  6. // Copyright (C) Lauris Kaplinski 2008
  7. //
  8.  
  9. static const int debug = 0;
  10.  
  11. #include <string.h>
  12. #include <stdio.h>
  13.  
  14. #include <libnr/nr-image.h>
  15.  
  16. #include <elea/geometry.h>
  17.  
  18. #include <sehle/commonmaterials.h>
  19. #include <sehle/material-multipass-dns.h>
  20.  
  21. #include "uri.h"
  22. #include "image.h"
  23. #include "material.h"
  24.  
  25. #include "mesh3ds.h"
  26.  
  27. namespace Miletos {
  28.  
  29. // SD3Data
  30.  
  31. SD3Data::SD3Data (const unsigned char *cdata, size_t csize, const char *purl)
  32. : DataBlock (purl, "SD3Data")
  33. {
  34.     parse (cdata, csize);
  35. }
  36.  
  37. SD3Data::~SD3Data (void)
  38. {
  39. }
  40.  
  41. SD3Data *
  42. SD3Data::getSD3Data (const char *purl)
  43. {
  44.     SD3Data *sd3 = NULL;
  45.     if (purl) {
  46.         sd3 = (SD3Data *) lookupDataBlock (purl, "SD3Data");
  47.         if (sd3) return sd3;
  48.         URI::URLHandler *handler = URI::getHandler (purl);
  49.         if (handler) {
  50.             size_t csize;
  51.             const unsigned char *cdata = handler->mmapData ((const unsigned char *) purl, &csize);
  52.             if (cdata) {
  53.                 sd3 = new SD3Data (cdata, csize, purl);
  54.                 handler->munmapData (cdata);
  55.             }
  56.             handler->unRef ();
  57.         }
  58.     }
  59.     return sd3;
  60. }
  61.  
  62. SD3Data *
  63. SD3Data::getSD3Data (const unsigned char *cdata, size_t csize, const char *purl)
  64. {
  65.     SD3Data *sd3 = NULL;
  66.     if (purl) {
  67.         sd3 = (SD3Data *) lookupDataBlock (purl, "SD3Data");
  68.         if (sd3) return sd3;
  69.         if (cdata) {
  70.             sd3 = new SD3Data (cdata, csize, purl);
  71.         }
  72.     }
  73.     return sd3;
  74. }
  75.  
  76. static const u32 SD3_EOF = 0x0000;
  77. static const u32 SD3_MAIN = 0x4D4D;
  78. static const u32 SD3_MDATA = 0x3D3D;
  79. static const u32 SD3_KEYFRAMES = 0xB000;
  80. static const u32 SD3_OBJECT = 0x4000;
  81. static const u32 SD3_MESH = 0x4100;
  82. static const u32 SD3_LIGHT = 0x4600;
  83. static const u32 SD3_CAMERA = 0x4700;
  84. static const u32 SD3_VERTICES = 0x4110;
  85. static const u32 SD3_FACES = 0x4120;
  86. static const u32 SD3_FACE_MATERIALS = 0x4130;
  87. static const u32 SD3_UV = 0x4140;
  88. static const u32 SD3_MATRIX = 0x4160;
  89. static const u32 SD3_MATERIAL = 0xAFFF;
  90. static const u32 SD3_MATERIAL_NAME = 0xA000;
  91. static const u32 SD3_MATERIAL_AMBIENT = 0xA010;
  92. static const u32 SD3_MATERIAL_DIFFUSE = 0xA020;
  93. static const u32 SD3_MATERIAL_SPECULAR = 0xA030;
  94. static const u32 SD3_MATERIAL_SHININESS = 0xA040;
  95. static const u32 SD3_MATERIAL_TEXTUREMAP = 0xA200;
  96. static const u32 SD3_MATERIAL_SPECULARMAP = 0xA204;
  97. static const u32 SD3_MATERIAL_OPACITYMAP = 0xA210;
  98. static const u32 SD3_MATERIAL_REFLECTIONMAP = 0xA220;
  99. static const u32 SD3_MATERIAL_BUMPMAP = 0xA230;
  100. static const u32 SD3_MATERIAL_MAP_FILENAME = 0xA300;
  101. static const u32 SD3_MATERIAL_MAP_PARAMETERS = 0xA351;
  102. static const u32 SD3_COLOR_F = 0x0010;
  103. static const u32 SD3_COLOR_24 = 0x0011;
  104. static const u32 SD3_COLOR_LIN_F = 0x0013;
  105. static const u32 SD3_COLOR_LIN_24 = 0x0012;
  106. static const u32 SD3_INT_PERCENTAGE = 0x0030;
  107. static const u32 SD3_FLOAT_PERCENTAGE = 0x0031;
  108.  
  109. static unsigned int
  110. get_chunk (const unsigned char *cdata, size_t csize, size_t& cpos, u32 &id, u32& size)
  111. {
  112.     if (cpos == csize) {
  113.         id = SD3_EOF;
  114.         size = 0;
  115.         return true;
  116.     }
  117.     if ((cpos + 6) > csize) return false;
  118.     id = ((u32) cdata[cpos + 1] << 8) | cdata[cpos + 0];
  119.     size = ((u32) cdata[cpos + 5] << 24) | ((u32) cdata[cpos + 4] << 16) | ((u32) cdata[cpos + 3] << 8) | cdata[cpos + 2];
  120.     if (debug > 1) fprintf (stderr, "Chunk: %4x %x\n", id, size);
  121.     return true;
  122. }
  123.  
  124. static unsigned int
  125. get_u8 (const unsigned char *cdata, size_t csize, size_t& cpos, u8& val)
  126. {
  127.     if ((cpos + 1) > csize) {
  128.         return false;
  129.     } else {
  130.         val = cdata[cpos + 0];
  131.         cpos += 1;
  132.         return true;
  133.     }
  134. }
  135.  
  136. static unsigned int
  137. get_u16 (const unsigned char *cdata, size_t csize, size_t& cpos, u16& val)
  138. {
  139.     if ((cpos + 2) > csize) {
  140.         return false;
  141.     } else {
  142.         val = ((u32) cdata[cpos + 1] << 8) | cdata[cpos + 0];
  143.         cpos += 2;
  144.         return true;
  145.     }
  146. }
  147.  
  148. static unsigned int
  149. get_u32 (const unsigned char *cdata, size_t csize, size_t& cpos, u32& val)
  150. {
  151.     if ((cpos + 4) > csize) {
  152.         return false;
  153.     } else {
  154.         val = ((u32) cdata[cpos + 3] << 24) | ((u32) cdata[cpos + 2] << 16) | ((u32) cdata[cpos + 1] << 8) | cdata[cpos + 0];
  155.         cpos += 4;
  156.         return true;
  157.     }
  158. }
  159.  
  160. static unsigned int
  161. get_f32 (const unsigned char *cdata, size_t csize, size_t& cpos, f32& val)
  162. {
  163.     if ((cpos + 4) > csize) {
  164.         return false;
  165.     } else {
  166.         val = *((f32 *) (cdata + cpos));
  167.         cpos += 4;
  168.         return true;
  169.     }
  170. }
  171.  
  172. static unsigned int
  173. get_string (const unsigned char *cdata, size_t csize, size_t& cpos, const char *& val)
  174. {
  175.     const char *tval = (const char *) cdata + cpos;
  176.     while (cdata[cpos] && (cpos < csize)) cpos += 1;
  177.     if (cpos >= csize) return false;
  178.     cpos += 1;
  179.     val = tval;
  180.     return true;
  181. }
  182.  
  183. unsigned int
  184. SD3Data::parse (const unsigned char *cdata, size_t csize)
  185. {
  186.     size_t cpos = 0;
  187.     u32 id;
  188.     u32 size;
  189.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  190.     if (id != SD3_MAIN) return false;
  191.     if (!parseMAIN (cdata + cpos, size)) return false;
  192.     return true;
  193. }
  194.  
  195. unsigned int
  196. SD3Data::parseMAIN (const unsigned char *cdata, size_t csize)
  197. {
  198.     size_t cpos = 6;
  199.     bool mdatafound = 0;
  200.     u32 id;
  201.     u32 size;
  202.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  203.     while (id != SD3_EOF) {
  204.         if (id == SD3_MDATA) {
  205.             if (mdatafound) {
  206.                 fprintf (stderr, "SD3Data::parseMAIN: Multiple MData nodes in file\n");
  207.             } else {
  208.                 if (!parseMDATA (cdata + cpos, size, mdata)) return false;
  209.                 mdatafound = true;
  210.             }
  211.         } else {
  212.             if (debug) fprintf (stderr, "MAIN: %4x %x\n", id, size);
  213.         }
  214.         cpos += size;
  215.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  216.     }
  217.     return true;
  218. }
  219.  
  220. unsigned int
  221. SD3Data::parseMDATA (const unsigned char *cdata, size_t csize, MData& mdata)
  222. {
  223.     size_t cpos = 6;
  224.     u32 id;
  225.     u32 size;
  226.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  227.     while (id != SD3_EOF) {
  228.         if (id == SD3_OBJECT) {
  229.             Object obj;
  230.             if (!parseOBJECT (cdata + cpos, size, obj)) return false;
  231.             mdata.objects.push_back (obj);
  232.         } else if (id == SD3_MATERIAL) {
  233.             Material mat;
  234.             mat.diffuse = Elea::Color4fWhite;
  235.             if (!parseMATERIAL (cdata + cpos, size, mat)) return false;
  236.             mdata.materials.push_back (mat);
  237.         } else {
  238.             if (debug) fprintf (stderr, "MDATA: %4x %x\n", id, size);
  239.         }
  240.         cpos += size;
  241.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  242.     }
  243.     return true;
  244. }
  245.  
  246. unsigned int
  247. SD3Data::parseOBJECT (const unsigned char *cdata, size_t csize, Object& obj)
  248. {
  249.     size_t cpos = 6;
  250.     const char *name;
  251.     if (!get_string (cdata, csize, cpos, name)) return false;
  252.     obj.name = name;
  253.     bool meshfound = 0;
  254.     u32 id;
  255.     u32 size;
  256.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  257.     while (id != SD3_EOF) {
  258.         if (id == SD3_MESH) {
  259.             if (meshfound) {
  260.                 fprintf (stderr, "SD3Data::parseOBJECT: Multiple Mesh nodes in file\n");
  261.             } else {
  262.                 if (!parseMESH (cdata + cpos, size, obj.mesh)) return false;
  263.                 meshfound = true;
  264.             }
  265.         } else if (id == SD3_LIGHT) {
  266.         } else if (id == SD3_CAMERA) {
  267.         } else {
  268.             if (debug) fprintf (stderr, "OBJECT: %4x %x\n", id, size);
  269.         }
  270.         cpos += size;
  271.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  272.     }
  273.     return true;
  274. }
  275.  
  276. unsigned int
  277. SD3Data::parseMESH (const unsigned char *cdata, size_t csize, Mesh& mesh)
  278. {
  279.     size_t cpos = 6;
  280.     u32 id;
  281.     u32 size;
  282.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  283.     while (id != SD3_EOF) {
  284.         if (id == SD3_VERTICES) {
  285.             if (!parseVERTICES (cdata + cpos, size, mesh)) return false;
  286.         } else if (id == SD3_FACES) {
  287.             if (!parseFACES (cdata + cpos, size, mesh)) return false;
  288.         } else if (id == SD3_UV) {
  289.             if (!parseUV (cdata + cpos, size, mesh)) return false;
  290.         } else if (id == SD3_MATRIX) {
  291.             if (!parseMATRIX (cdata + cpos, size, mesh)) return false;
  292.         } else {
  293.             if (debug) fprintf (stderr, "MESH: %4x %x\n", id, size);
  294.         }
  295.         cpos += size;
  296.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  297.     }
  298.     return true;
  299. }
  300.  
  301. unsigned int
  302. SD3Data::parseVERTICES (const unsigned char *cdata, size_t csize, Mesh& mesh)
  303. {
  304.     size_t cpos = 6;
  305.     u16 count;
  306.     if (!get_u16 (cdata, csize, cpos, count)) return false;
  307.     mesh.vdata.resize (count);
  308.     for (unsigned int i = 0; i < count; i++) {
  309.         for (int j = 0; j < 3; j++) {
  310.             if (!get_f32 (cdata, csize, cpos, mesh.vdata[i][j])) {
  311.                 return false;
  312.             }
  313.         }
  314.     }
  315.     return true;
  316. }
  317.  
  318. unsigned int
  319. SD3Data::parseFACES (const unsigned char *cdata, size_t csize, Mesh& mesh)
  320. {
  321.     size_t cpos = 6;
  322.     u16 count;
  323.     if (!get_u16 (cdata, csize, cpos, count)) return false;
  324.     mesh.fdata.resize (count * 4);
  325.     for (unsigned int i = 0; i < (unsigned int) count * 4; i++) {
  326.         if (!get_u16 (cdata, csize, cpos, mesh.fdata[i])) return false;
  327.     }
  328.     u32 id;
  329.     u32 size;
  330.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  331.     while (id != SD3_EOF) {
  332.         if (id == SD3_FACE_MATERIALS) {
  333.             MGroup mgroup;
  334.             if (!parseMGROUP (cdata + cpos, size, mgroup)) return false;
  335.             mesh.mgroups.push_back (mgroup);
  336.         } else {
  337.             if (debug) fprintf (stderr, "FACES: %4x %x\n", id, size);
  338.         }
  339.         cpos += size;
  340.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  341.     }
  342.     return true;
  343. }
  344.  
  345. unsigned int
  346. SD3Data::parseMGROUP (const unsigned char *cdata, size_t csize, MGroup& mgroup)
  347. {
  348.     size_t cpos = 6;
  349.     const char *name;
  350.     if (!get_string (cdata, csize, cpos, name)) return false;
  351.     mgroup.matname = name;
  352.     u16 count;
  353.     if (!get_u16 (cdata, csize, cpos, count)) return false;
  354.     mgroup.faces.resize (count);
  355.     for (unsigned int i = 0; i < (unsigned int) count; i++) {
  356.         if (!get_u16 (cdata, csize, cpos, mgroup.faces[i])) return false;
  357.     }
  358.     return true;
  359. }
  360.  
  361. unsigned int
  362. SD3Data::parseUV (const unsigned char *cdata, size_t csize, Mesh& mesh)
  363. {
  364.     size_t cpos = 6;
  365.     u16 count;
  366.     if (!get_u16 (cdata, csize, cpos, count)) return false;
  367.     mesh.tdata.resize (count);
  368.     for (unsigned int i = 0; i < count; i++) {
  369.         for (int j = 0; j < 2; j++) {
  370.             if (!get_f32 (cdata, csize, cpos, mesh.tdata[i][j])) {
  371.                 return false;
  372.             }
  373.         }
  374.     }
  375.     return true;
  376. }
  377.  
  378. unsigned int
  379. SD3Data::parseMATRIX (const unsigned char *cdata, size_t csize, Mesh& mesh)
  380. {
  381.     return true;
  382. }
  383.  
  384. unsigned int
  385. SD3Data::parseMATERIAL (const unsigned char *cdata, size_t csize, Material& mat)
  386. {
  387.     size_t cpos = 6;
  388.     const char *name = NULL;
  389.     u32 id;
  390.     u32 size;
  391.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  392.     while (id != SD3_EOF) {
  393.         if (id == SD3_MATERIAL_NAME) {
  394.             size_t pos = 6;
  395.             if (!get_string (cdata + cpos, size, pos, name)) return false;
  396.             mat.name = name;
  397.         } else if (id == SD3_MATERIAL_AMBIENT) {
  398.             if (!parseCOLOR (cdata + cpos, size, mat.ambient)) return false;
  399.         } else if (id == SD3_MATERIAL_DIFFUSE) {
  400.             if (!parseCOLOR (cdata + cpos, size, mat.diffuse)) return false;
  401.         } else if (id == SD3_MATERIAL_SPECULAR) {
  402.             if (!parseCOLOR (cdata + cpos, size, mat.specular)) return false;
  403.         } else if (id == SD3_MATERIAL_SHININESS) {
  404.             if (!parsePERCENTAGE (cdata + cpos, size, mat.shininess)) return false;
  405.         } else if (id == SD3_MATERIAL_TEXTUREMAP) {
  406.             if (!parseMAP (cdata + cpos, size, mat.filename)) return false;
  407.         } else if (id == SD3_MATERIAL_SPECULARMAP) {
  408.         } else if (id == SD3_MATERIAL_OPACITYMAP) {
  409.             if (!parseMAP (cdata + cpos, size, mat.opacitymap)) return false;
  410.         } else if (id == SD3_MATERIAL_REFLECTIONMAP) {
  411.         } else if (id == SD3_MATERIAL_BUMPMAP) {
  412.         } else {
  413.             if (debug) fprintf (stderr, "MATERIAL: %4x %x\n", id, size);
  414.         }
  415.         cpos += size;
  416.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  417.     }
  418.     return true;
  419. }
  420.  
  421. unsigned int
  422. SD3Data::parseMAP (const unsigned char *cdata, size_t csize, std::string& filename)
  423. {
  424.     size_t cpos = 6;
  425.     u32 id;
  426.     u32 size;
  427.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  428.     while (id != SD3_EOF) {
  429.         if (id == SD3_MATERIAL_MAP_FILENAME) {
  430.             size_t pos = 6;
  431.             const char *name = NULL;
  432.             if (!get_string (cdata + cpos, size, pos, name)) return false;
  433.             filename = name;
  434.         } else {
  435.             if (debug) fprintf (stderr, "MAP: %4x %x\n", id, size);
  436.         }
  437.         cpos += size;
  438.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  439.     }
  440.     return true;
  441. }
  442.  
  443. unsigned int
  444. SD3Data::parseCOLOR (const unsigned char *cdata, size_t csize, Elea::Color4f& color)
  445. {
  446.     size_t cpos = 6;
  447.     u32 id;
  448.     u32 size;
  449.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  450.     while (id != SD3_EOF) {
  451.         size_t pos = cpos + 6;
  452.         if (id == SD3_COLOR_F) {
  453.             for (int i = 0; i < 3; i++) {
  454.                 if (!get_f32 (cdata, csize, pos, color[i])) return false;
  455.             }
  456.         } else if (id == SD3_COLOR_LIN_F) {
  457.             for (int i = 0; i < 3; i++) {
  458.                 if (!get_f32 (cdata, csize, pos, color[i])) return false;
  459.             }
  460.         } else if (id == SD3_COLOR_24) {
  461.             u8 c;
  462.             for (int i = 0; i < 3; i++) {
  463.                 if (!get_u8 (cdata, csize, pos, c)) return false;
  464.                 color[i] = (float) c / 255;
  465.             }
  466.         } else if (id == SD3_COLOR_LIN_24) {
  467.             u8 c;
  468.             for (int i = 0; i < 3; i++) {
  469.                 if (!get_u8 (cdata, csize, pos, c)) return false;
  470.                 color[i] = (float) c / 255;
  471.             }
  472.         } else {
  473.             if (debug) fprintf (stderr, "COLOR: %4x %x\n", id, size);
  474.         }
  475.         cpos += size;
  476.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  477.     }
  478.     color[Elea::A] = 1;
  479.     return true;
  480. }
  481.  
  482. unsigned int
  483. SD3Data::parsePERCENTAGE (const unsigned char *cdata, size_t csize, float& value)
  484. {
  485.     size_t cpos = 6;
  486.     u32 id;
  487.     u32 size;
  488.     if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  489.     while (id != SD3_EOF) {
  490.         size_t pos = cpos + 6;
  491.         if (id == SD3_INT_PERCENTAGE) {
  492.             u16 val;
  493.             if (!get_u16 (cdata, csize, pos, val)) return false;
  494.             value = val / 65535.0f;
  495.         } else if (id == SD3_FLOAT_PERCENTAGE) {
  496.             float val;
  497.             if (!get_f32 (cdata, csize, pos, val)) return false;
  498.             value = val;
  499.         } else {
  500.             if (debug) fprintf (stderr, "PERCENTAGE: %4x %x\n", id, size);
  501.         }
  502.         cpos += size;
  503.         if (!get_chunk (cdata, csize, cpos, id, size)) return false;
  504.     }
  505.     return true;
  506. }
  507.  
  508. // Geometry3DS
  509.  
  510. Geometry3DS::Geometry3DS (void)
  511. : StaticGeometry(0), obj(NULL)
  512. {
  513. }
  514.  
  515. static Object *
  516. geometry3ds_factory (void)
  517. {
  518.     return new Geometry3DS();
  519. }
  520.  
  521. const Object::Type *
  522. Geometry3DS::objectType (void)
  523. {
  524.     return type ();
  525. }
  526.  
  527. const Object::Type *
  528. Geometry3DS::type (void)
  529. {
  530.     static Type *mytype = NULL;
  531.     static const Attribute attrs[] = {
  532.         { "source", NULL, 0 }
  533.     };
  534.     if (!mytype) mytype = new Type(StaticGeometry::type (), "Geometry3DS", "geometry3DS", geometry3ds_factory, sizeof (attrs) / sizeof (attrs[0]), attrs);
  535.     return mytype;
  536. }
  537.  
  538. void
  539. Geometry3DS::build (Thera::Node *pnode, Document *doc, BuildCtx *ctx)
  540. {
  541.     StaticGeometry::build (pnode, doc, ctx);
  542.     buildAllAttributes (type (), ctx);
  543. }
  544.  
  545. void
  546. Geometry3DS::release (void)
  547. {
  548.     clear ();
  549.     StaticGeometry::release ();
  550. }
  551.  
  552. void
  553. Geometry3DS::set (const char *attrid, const char *val)
  554. {
  555.     if (!strcmp (attrid, "source")) {
  556.         clear ();
  557.         if (val) {
  558.             obj = SD3Data::getSD3Data (val);
  559.             if (obj) loadData ();
  560.         }
  561.         requestUpdate (MODIFIED | MESH_DEFINITION_MODIFIED);
  562.     } else {
  563.         StaticGeometry::set (attrid, val);
  564.     }
  565. }
  566.  
  567. TextureInfo *
  568. Geometry3DS::getTextureInfo (unsigned int matidx, unsigned int texidx, unsigned int getimage)
  569. {
  570.     if (texidx >= ntextures) return NULL;
  571.     if (!textures[texidx]) return NULL;
  572.     if (nr_image_is_empty (textures[texidx]->pixels)) return NULL;
  573.     TextureInfo *tex = new TextureInfo();
  574.     tex->urn = strdup (textures[texidx]->url.c_str ());
  575.     if (getimage) {
  576.         tex->image = textures[texidx]->pixels;
  577.         nr_image_ref (tex->image);
  578.     }
  579.     return tex;
  580. }
  581.  
  582. u32
  583. Geometry3DS::getMaterialInfo (Miletos::MaterialInfo *mat, u32 matidx)
  584. {
  585.     if (matidx >= (u32) nmaterials) return false;
  586.     if (mat) {
  587.         if (textures[matidx] && !nr_image_is_empty (textures[matidx]->pixels)) {
  588.             mat->type = MaterialInfo::TEXTURE;
  589.             mat->diffuseTexture = (int) matidx;
  590.         } else {
  591.             mat->type = Miletos::MaterialInfo::COLOR;
  592.             mat->diffuseTexture = -1;
  593.         }
  594.         mat->id = obj->mdata.materials[matidx].name.c_str ();
  595.         mat->diffuseColor = obj->mdata.materials[matidx].diffuse;
  596.         mat->specularColor = obj->mdata.materials[matidx].specular;
  597.         mat->specularShininess = obj->mdata.materials[matidx].shininess;
  598.         mat->normalTexture = -1;
  599.         mat->specularTexture = -1;
  600.     }
  601.     return true;
  602. }
  603.  
  604. Sehle::Material *
  605. Geometry3DS::getMaterial (int matidx, Sehle::Engine *engine)
  606. {
  607.     if ((matidx < 0) || (matidx >= (int) nmaterials)) {
  608.         Sehle::WireMaterial *mat = Sehle::WireMaterial::newWireMaterial (engine, "Poser:Geometry:invalidMaterial");
  609.         if (!mat->built) mat->setColor (Elea::Color4fRed);
  610.         return mat;
  611.     }
  612.     if (textures[matidx] && !nr_image_is_empty (textures[matidx]->pixels)) {
  613.         Sehle::MaterialMultipassDNS *mat = Sehle::MaterialMultipassDNS::newMaterialMultipassDNS (engine, textures[matidx]->url.c_str ());
  614.         if (!mat->built) {
  615.             mat->setMap (Sehle::MaterialMultipassDNS::COLOR, textures[matidx]->url.c_str (), &textures[matidx]->pixels->pixels);
  616.         }
  617.         return mat;
  618.     }
  619.     Sehle::ColorMaterial *mat = Sehle::ColorMaterial::newColorMaterial (engine, obj->mdata.materials[matidx].name.c_str ());
  620.     if (!mat->built) mat->setColor (obj->mdata.materials[matidx].diffuse);
  621.     return mat;
  622. }
  623.  
  624. void
  625. Geometry3DS::clear (void)
  626. {
  627.     for (size_t i = 0; i < textures.size (); i++) {
  628.         if (textures[i]) {
  629.             nr_image_unref (textures[i]->pixels);
  630.             delete textures[i];
  631.         }
  632.     }
  633.     textures.clear ();
  634.     if (obj) {
  635.         obj->unRef ();
  636.         obj = NULL;
  637.     }
  638.     StaticGeometry::clear ();
  639. }
  640.  
  641. static NRImage *
  642. add_alpha (NRImage *c, NRImage *a)
  643. {
  644.     if ((c->pixels.area.x0 != a->pixels.area.x0) || (c->pixels.area.x1 != a->pixels.area.x1) ||
  645.         (c->pixels.area.y0 != a->pixels.area.y0) || (c->pixels.area.y1 != a->pixels.area.y1)) {
  646.         nr_image_ref (c);
  647.         return c;
  648.     }
  649.     NRImage *d = nr_image_new ();
  650.     int width = c->pixels.area.x1 - c->pixels.area.x0;
  651.     int height = c->pixels.area.x1 - c->pixels.area.x0;
  652.     int cbpp = NR_PIXBLOCK_BPP (&c->pixels);
  653.     int abpp = NR_PIXBLOCK_BPP (&a->pixels);
  654.     nr_pixblock_setup (&d->pixels, NR_PIXBLOCK_MODE_R8G8B8A8N, 0, 0, width, height, 0);
  655.     for (int y = 0; y < height; y++) {
  656.         unsigned char *dp = NR_PIXBLOCK_PX (&d->pixels) + y * d->pixels.rs;
  657.         unsigned char *cp = NR_PIXBLOCK_PX (&c->pixels) + y * c->pixels.rs;
  658.         unsigned char *ap = NR_PIXBLOCK_PX (&a->pixels) + y * a->pixels.rs;
  659.         for (int x = 0; x < width; x++) {
  660.             if (cbpp == 1) {
  661.                 dp[0] = cp[0];
  662.                 dp[1] = cp[0];
  663.                 dp[2] = cp[0];
  664.             } else {
  665.                 dp[0] = cp[0];
  666.                 dp[1] = cp[1];
  667.                 dp[2] = cp[2];
  668.             }
  669.             dp[3] = 255 - ap[0];
  670.             dp += 4;
  671.             cp += cbpp;
  672.             ap += abpp;
  673.         }
  674.     }
  675.     d->pixels.empty = 0;
  676.     return d;
  677. }
  678.  
  679. void
  680. Geometry3DS::loadData (void)
  681. {
  682.     if (!obj) return;
  683.     if (obj->mdata.materials.empty ()) return;
  684.  
  685.     // Materials
  686.     ntextures = obj->mdata.materials.size ();
  687.     nmaterials = obj->mdata.materials.size ();
  688.     // fixme: Sort out texture stuff
  689.     textures.resize (nmaterials, NULL);
  690.     URI::URLHandler *handler = URI::getHandler (obj->uri);
  691.     if (handler) {
  692.         for (unsigned int i = 0; i < nmaterials; i++) {
  693.             if (!obj->mdata.materials[i].filename.empty ()) {
  694.                 Texture *tex = NULL;
  695.                 size_t csize;
  696.                 const unsigned char *cdata = handler->mmapDataRelative (obj->mdata.materials[i].filename.c_str (), &csize);
  697.                 if (cdata) {
  698.                     NRImage *img = nr_image_new ();
  699.                     if (Image::load (&img->pixels, cdata, csize)) {
  700.                         tex = new Texture ();
  701.                         // fixme:
  702.                         tex->url = obj->mdata.materials[i].filename;
  703.                         tex->pixels = img;
  704.                         textures[i] = tex;
  705.                     } else {
  706.                         nr_image_unref (img);
  707.                     }
  708.                     handler->munmapData (cdata);
  709.                     // Try opacity
  710.                     if (tex && !obj->mdata.materials[i].opacitymap.empty ()) {
  711.                         cdata = handler->mmapDataRelative (obj->mdata.materials[i].opacitymap.c_str (), &csize);
  712.                         if (cdata) {
  713.                             img = nr_image_new ();
  714.                             if (Image::load (&img->pixels, cdata, csize)) {
  715.                                 NRImage *newimg = add_alpha (tex->pixels, img);
  716.                                 nr_image_unref (tex->pixels);
  717.                                 tex->pixels = newimg;
  718.                             }
  719.                             nr_image_unref (img);
  720.                             handler->munmapData (cdata);
  721.                         }
  722.                     }
  723.                 }
  724.             }
  725.         }
  726.         handler->unRef ();
  727.     }
  728.  
  729.     u32 lnumv = 0;
  730.     u32 lnumi = 0;
  731.     std::vector<u32> vstart;
  732.     for (size_t i = 0; i < obj->mdata.objects.size (); i++) {
  733.         vstart.push_back (lnumv);
  734.         lnumv += obj->mdata.objects[i].mesh.vdata.size ();
  735.         lnumi += 3 * (obj->mdata.objects[i].mesh.fdata.size () / 4);
  736.     }
  737.     // Vertices
  738.     setNumVertices (lnumv, true, true, false);
  739.     for (size_t i = 0; i < obj->mdata.objects.size (); i++) {
  740.         if (obj->mdata.objects[i].mesh.vdata.empty ()) continue;
  741.         memcpy (&vbase[vstart[i]], &obj->mdata.objects[i].mesh.vdata[0], obj->mdata.objects[i].mesh.vdata.size () * sizeof (Elea::Vector3f));
  742.         if (obj->mdata.objects[i].mesh.tdata.size () == obj->mdata.objects[i].mesh.vdata.size ()) {
  743.             memcpy (&xbase[vstart[i]], &obj->mdata.objects[i].mesh.tdata[0], obj->mdata.objects[i].mesh.tdata.size () * sizeof (Elea::Vector2f));
  744.         }
  745.     }
  746.     // Indices
  747.     setNumIndices (lnumi);
  748.     setNumFrags (nmaterials);
  749.     // Assign indices
  750.     unsigned int iidx = 0;
  751.     for (unsigned int i = 0; i < nmaterials; i++) {
  752.         Frag *frag = &frags[i];
  753.         frag->matidx = i;
  754.         frag->firstindex = iidx;
  755.         frag->visible = 1;
  756.         const char *matname = obj->mdata.materials[i].name.c_str ();
  757.         for (size_t j = 0; j < obj->mdata.objects.size (); j++) {
  758.             for (size_t k = 0; k < obj->mdata.objects[j].mesh.mgroups.size (); k++) {
  759.                 if (!obj->mdata.objects[j].mesh.mgroups[k].matname.compare (matname)) {
  760.                     // Assign this MGroup to current fragment
  761.                     for (size_t l = 0; l < obj->mdata.objects[j].mesh.mgroups[k].faces.size (); l++) {
  762.                         unsigned int fidx = obj->mdata.objects[j].mesh.mgroups[k].faces[l];
  763.                         for (int m = 0; m < 3; m++) {
  764.                             indices[iidx++] = vstart[j] + obj->mdata.objects[j].mesh.fdata[4 * fidx + m];
  765.                         }
  766.                     }
  767.                 }
  768.             }
  769.         }
  770.         frag->numindices = iidx - frag->firstindex;
  771.     }
  772.  
  773.     if (nindices > 0) {
  774.         Elea::Geometry::calculateNormals (nbase[0], sizeof (nbase[0]), vbase[0], sizeof (vbase[0]), nvertices, &indices[0], nindices, true);
  775.     }
  776.  
  777.     requestUpdate (MODIFIED | MESH_DEFINITION_MODIFIED);
  778. }
  779.  
  780. } // Namespace Miletos
  781.  
  782.