voxel.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. * m3dconv/voxel.h
  3. *
  4. * Copyright (C) 2019 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief simple voxel image to M3D converter
  27. * https://gitlab.com/bztsrc/model3d
  28. *
  29. */
  30. /* tables */
  31. static char *schem_names[256] = {
  32. "air","stone","grass","dirt","cobblestone","planks","sapling","bedrock","flowing_water","water","flowing_lava","lava","sand",
  33. "gravel","gold_ore","iron_ore","coal_ore","log","leaves","sponge","glass","lapis_ore","lapis_block","dispenser","sandstone",
  34. "noteblock","bed","golden_rail","detector_rail","sticky_piston","web","tallgrass","deadbush","piston","piston_head","wool",
  35. "piston_extension","yellow_flower","red_flower","brown_mushroom","red_mushroom","gold_block","iron_block","double_stone_slab",
  36. "stone_slab","brick_block","tnt","bookshelf","mossy_cobblestone","obsidian","torch","fire","mob_spawner","oak_stairs","chest",
  37. "redstone_wire","diamond_ore","diamond_block","crafting_table","wheat","farmland","furnace","lit_furnace","standing_sign",
  38. "wooden_door","ladder","rail","stone_stairs","wall_sign","lever","stone_pressure_plate","iron_door","wooden_pressure_plate",
  39. "redstone_ore","lit_redstone_ore","unlit_redstone_torch","redstone_torch","stone_button","snow_layer","ice","snow","cactus",
  40. "clay","reeds","jukebox","fence","pumpkin","netherrack","soul_sand","glowstone","portal","lit_pumpkin","cake","unpowered_repeater",
  41. "powered_repeater","stained_glass","trapdoor","monster_egg","stonebrick","brown_mushroom_block","red_mushroom_block","iron_bars",
  42. "glass_pane","melon_block","pumpkin_stem","melon_stem","vine","fence_gate","brick_stairs","stone_brick_stairs","mycelium",
  43. "waterlily","nether_brick","nether_brick_fence","nether_brick_stairs","nether_wart","enchanting_table","brewing_stand","cauldron",
  44. "end_portal","end_portal_frame","end_stone","dragon_egg","redstone_lamp","lit_redstone_lamp","double_wooden_slab","wooden_slab",
  45. "cocoa","sandstone_stairs","emerald_ore","ender_chest","tripwire_hook","tripwire","emerald_block","spruce_stairs","birch_stairs",
  46. "jungle_stairs","command_block","beacon","cobblestone_wall","flower_pot","carrots","potatoes","oak_button","skull","anvil",
  47. "trapped_chest","light_weighted_pressure_plate","heavy_weighted_pressure_plate","unpowered_comparator","powered_comparator",
  48. "daylight_detector","redstone_block","quartz_ore","hopper","quartz_block","quartz_stairs","activator_rail","dropper",
  49. "stained_hardened_clay","stained_glass_pane","leaves2","log2","acacia_stairs","dark_oak_stairs","slime","barrier","iron_trapdoor",
  50. "prismarine","sea_lantern","hay_block","carpet","hardened_clay","coal_block","packed_ice","double_plant","standing_banner",
  51. "wall_banner","daylight_detector_inverted","red_sandstone","red_sandstone_stairs","double_stone_slab2","stone_slab2",
  52. "spruce_fence_gate","birch_fence_gate","jungle_fence_gate","dark_oak_fence_gate","acacia_fence_gate","spruce_fence","birch_fence",
  53. "jungle_fence","dark_oak_fence","acacia_fence","spruce_door","birch_door","jungle_door","acacia_door","dark_oak_door","end_rod",
  54. "chorus_plant","chorus_flower","purpur_block","purpur_pillar","purpur_stairs","purpur_double_slab","purpur_slab","end_bricks",
  55. "beetroots","grass_path","end_gateway","repeating_command_block","chain_command_block","frosted_ice","magma","nether_wart_block",
  56. "red_nether_brick","bone_block","structure_void","observer","white_shulker_box","orange_shulker_box","magenta_shulker_box",
  57. "light_blue_shulker_box","yellow_shulker_box","lime_shulker_box","pink_shulker_box","gray_shulker_box","silver_shulker_box",
  58. "cyan_shulker_box","purple_shulker_box","blue_shulker_box","brown_shulker_box","green_shulker_box","red_shulker_box",
  59. "black_shulker_box","white_glazed_terracotta","orange_glazed_terracotta","magenta_glazed_terracotta","light_blue_glazed_terracotta",
  60. "yellow_glazed_terracotta","lime_glazed_terracotta","pink_glazed_terracotta","gray_glazed_terracotta","silver_glazed_terracotta",
  61. "cyan_glazed_terracotta","purple_glazed_terracotta","blue_glazed_terracotta","brown_glazed_terracotta","green_glazed_terracotta",
  62. "red_glazed_terracotta","black_glazed_terracotta","concrete","concrete_powder",NULL,NULL,NULL
  63. };
  64. static uint32_t schem_palette[256] = {
  65. 0x00000000,0xff38403c,0xff113634,0xff192b41,0xff383a3c,0xff244459,0xff296d4c,0xff404143,0xffcd7a18,0xffcd7c18,0xff053a8b,0xff054a8b,0xff6f9297,0xff636467,0xff636e71,0xff393e4b,
  66. 0xff38383a,0xff223342,0xff112114,0xff3a989a,0xffa68c8c,0xff68574e,0xff6e3518,0xff5c5c5d,0xff64888b,0xff202e46,0xff242b63,0xff466a87,0xff586778,0xff4c605c,0xffa3a29f,0xff33855b,
  67. 0xff284f6b,0xff4b5a65,0xff9a9a9a,0xff119fc2,0xff183076,0xff5c759b,0xff3f43d6,0xff31a4c1,0xff686768,0xff393c3e,0xff3b3e3f,0xff313351,0xff22228a,0xff213e4e,0xff2e3d3b,0xff100d0c,
  68. 0xff3b6079,0xff2882cf,0xff1f1911,0xff20303e,0xff2c4a5f,0xff000051,0xff575851,0xffb2b94e,0xff223648,0xff4e9daf,0xff364e6c,0xff36393a,0xff36383a,0xff32566e,0xff2b4d63,0xff576e7b,
  69. 0xff383b3c,0xff385e72,0xff5d5f61,0xff757575,0xff9c9a9b,0xff4a7894,0xff314b4b,0xff314a4b,0xff31476a,0xff2647a3,0xff666666,0xffaea5a4,0xffae9075,0xffa79e9e,0xff114e25,0xff7f7f7f,
  70. 0xff2a8e48,0xff223048,0xff3d667f,0xff135d9a,0xff1e1e4c,0xff283140,0xff426787,0xff181006,0xff1b66a0,0xff8c9bba,0xff787a82,0xff71768d,0xffc6c4c4,0xff2d4f63,0xff383e3c,0xff404243,
  71. 0xff405b76,0xff23279e,0xff808080,0xffbab79c,0xff177359,0xff135c9a,0xff177259,0xff0a5120,0xff3f6982,0xff313352,0xff414243,0xff414858,0xff194310,0xff141122,0xff141222,0xff141322,
  72. 0xff111273,0xff464d59,0xff485560,0xff393738,0xff180f06,0xff5b776a,0xff7cafac,0xff0d070a,0xff619695,0xff263949,0xff2c4154,0xff214978,0xff65898c,0xff616b5c,0xff27271a,0x00000000,
  73. 0xff46a122,0xff26445b,0xff919fa4,0xff204155,0xff556785,0xff393a3d,0xff28345d,0xff0c8a1b,0xff22ad19,0xff416b85,0xff898989,0xff393939,0xff1f465f,0xff2e539b,0xff70a2b2,0xff797d86,
  74. 0xff767b96,0xff3c4e59,0xff009a9a,0xff31335c,0xff3d3e3d,0xff31345c,0xff2f315b,0xff576d7b,0xff5c5d5d,0xff1b6892,0xffd3d3d3,0xff0d6327,0xff132331,0xff3b495d,0xff132330,0xff489758,
  75. 0xff0000d5,0xffa2a2a2,0xff75814e,0xff969e88,0xff2c7f94,0xffe0dfdd,0xff364b79,0xff202020,0xffc79071,0xff797470,0xff464b4c,0xff174d91,0xff174e91,0xff185095,0xff19529a,0xff26435b,
  76. 0xff618c9a,0xff405c80,0xff102234,0xff284886,0xff26425a,0xff608a98,0xff3f5a7e,0xff0f2134,0xff274684,0xff97a1a7,0xff816b81,0xff278c65,0xff866386,0xff876687,0xff836284,0xff8a678a,
  77. 0xff8f6a8f,0xff80b0ac,0xff357848,0xff375a74,0xffc78f71,0xff193271,0xff02035a,0xff070637,0xff9babae,0xff473a45,0xff000000,0xff8d8c88,0xff0e4894,0xff67256d,0xff886924,0xff1b7ca1,
  78. 0xff136a3f,0xff675093,0xff2b2926,0xff454a4a,0xff5d530f,0xff6d1647,0xff63201f,0xff192e4a,0xff184738,0xff151561,0xff171413,0xffa3a895,0xff4a757c,0xff9a50a6,0xffa8844c,0xff4799bb,
  79. 0xff2d9e83,0xff927cbb,0xff4b4842,0xff878573,0xff655e2a,0xff7b2657,0xff703326,0xff455560,0xff36725d,0xff2a2f91,0xff1a1836,0xff302d2a,0xff423f3c,0x00000000,0x00000000,0x00000000
  80. };
  81. static uint32_t vox_palette[256] = {
  82. 0x00000000, 0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff,
  83. 0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff,
  84. 0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc,
  85. 0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc,
  86. 0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99,
  87. 0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699,
  88. 0xff006699, 0xffff3399, 0xffcc3399, 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66,
  89. 0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966, 0xffff6666,
  90. 0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066,
  91. 0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933,
  92. 0xff669933, 0xff339933, 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033,
  93. 0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00, 0xff66cc00, 0xff33cc00,
  94. 0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300,
  95. 0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044,
  96. 0xff000022, 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000,
  97. 0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555, 0xff444444, 0xff222222, 0xff111111,
  98. };
  99. /**
  100. * Allocate a voxel m3d structure
  101. */
  102. m3d_t *alloc_voxm3d()
  103. {
  104. m3d_t *m3d;
  105. m3d = (m3d_t*)malloc(sizeof(m3d_t));
  106. if(!m3d) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  107. memset(m3d, 0, sizeof(m3d_t));
  108. m3d->flags = M3D_FLG_FREESTR;
  109. m3d->scale = 1.0f;
  110. if(voxpal && voxpal->voxtype && voxpal->numvoxtype) {
  111. m3d->numvoxtype = voxpal->numvoxtype;
  112. m3d->voxtype = voxpal->voxtype;
  113. }
  114. return m3d;
  115. }
  116. /**
  117. * Returns voxel type id for the closest color match
  118. */
  119. int color2voxtypeid(uint32_t color, m3d_t *m3d)
  120. {
  121. unsigned char *c = (unsigned char*)&color, *d;
  122. int i, j, k, ld, diff = 255;
  123. if(!c[3] || (!c[0] && !c[1] && !c[2])) return -1;
  124. for(i = 1, j = 0; i < (int)m3d->numvoxtype; i++) {
  125. /* get local maximum */
  126. ld = 0; d = (unsigned char*)&m3d->voxtype[i].color;
  127. k = d[0] > c[0] ? d[0] - c[0] : c[0] - d[0]; if(k > ld) ld = k;
  128. k = d[1] > c[1] ? d[1] - c[1] : c[1] - d[1]; if(k > ld) ld = k;
  129. k = d[2] > c[2] ? d[2] - c[2] : c[2] - d[2]; if(k > ld) ld = k;
  130. k = d[3] > c[3] ? d[3] - c[3] : c[3] - d[3]; if(k > ld) ld = k;
  131. /* is it smaller than global minimum? */
  132. if(ld < diff) { diff = ld; j = i; }
  133. }
  134. return j;
  135. }
  136. /**
  137. * Load a schematic and convert into a Model 3D in-memory format
  138. */
  139. /* parse an integer, the only dynamic type we are interested in. */
  140. #define SCHEM_GETINT(v,t) do{switch(t){case 1:v=d[0];d++;break;case 2:v=(d[0]<<8)|d[1];d+=2;break; \
  141. case 3:v=(d[0]<<24)|(d[1]<<16)|(d[2]<<8)|d[3];d+=4;break;}}while(0)
  142. m3d_t *schem_load(unsigned char *data, int size)
  143. {
  144. int i, j, k, l, g = 0, sx = 0, sy = 0, sz = 0, tr[256];
  145. unsigned char *d, *blk = NULL, *end = data + size;
  146. m3d_t *m3d = NULL;
  147. /* we don't care about that overcomplicated NBT mess */
  148. for(d = data; d < end; d++) {
  149. if(!memcmp(d, "\000\006Height", 8)) { d += 8; SCHEM_GETINT(sy, d[-9]); d--; } else
  150. if(!memcmp(d, "\000\006Length", 8)) { d += 8; SCHEM_GETINT(sz, d[-9]); d--; } else
  151. if(!memcmp(d, "\000\005Width", 7)) { d += 7; SCHEM_GETINT(sx, d[-8]); d--; } else
  152. if(!memcmp(d, "\000\009WEOffsetY", 11)) { d += 11; SCHEM_GETINT(g, d[-12]); d--; } else
  153. if(!memcmp(d, "\007\000\006Blocks", 9)) { d += 9; SCHEM_GETINT(l, 3); blk = d; d += l; }
  154. }
  155. if(!blk || !sy || !sz || !sx || l != sy * sz * sx) return NULL;
  156. m3d = alloc_voxm3d();
  157. memset(tr, 0, sizeof(tr));
  158. for(i = 0; i < l; i++) tr[blk[i]] = 1;
  159. if(!m3d->voxtype) {
  160. for(i = 1; i < 256; i++)
  161. m3d->numvoxtype += tr[i];
  162. m3d->voxtype = (m3dvt_t*)malloc(m3d->numvoxtype * sizeof(m3dvt_t));
  163. if(!m3d->voxtype) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  164. memset(m3d->voxtype, 0, m3d->numvoxtype * sizeof(m3dvt_t));
  165. for(i = j = 0; i < 256 && j < (int)m3d->numvoxtype; i++)
  166. if(i && tr[i]) {
  167. d = (unsigned char*)schem_names[i];
  168. if(d) {
  169. k = strlen((char*)d) + 1;
  170. m3d->voxtype[j].name = (char*)malloc(k+10);
  171. if(!m3d->voxtype[j].name) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  172. memcpy(m3d->voxtype[j].name, "minecraft:", 10);
  173. memcpy(m3d->voxtype[j].name + 10, d, k);
  174. }
  175. m3d->voxtype[j].color = schem_palette[i];
  176. m3d->voxtype[j].materialid = M3D_UNDEF;
  177. m3d->voxtype[j].skinid = M3D_UNDEF;
  178. tr[i] = j++;
  179. } else
  180. tr[i] = -1;
  181. } else {
  182. for(i = 0; i < 256; i++)
  183. tr[i] = i-1;
  184. }
  185. m3d->numvoxel = 1;
  186. m3d->voxel = (m3dvx_t*)malloc(m3d->numvoxel * sizeof(m3dvx_t));
  187. if(!m3d->voxel) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  188. memset(m3d->voxel, 0, m3d->numvoxel * sizeof(m3dvx_t));
  189. m3d->voxel[0].y = g < 0 ? g : 0;
  190. m3d->voxel[0].w = sx;
  191. m3d->voxel[0].h = sy;
  192. m3d->voxel[0].d = sz;
  193. m3d->voxel[0].data = (M3D_VOXEL*)malloc(l * sizeof(M3D_VOXEL));
  194. if(!m3d->voxel[0].data) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  195. for(i = 0; i < l; i++)
  196. m3d->voxel[0].data[i] = tr[blk[i]];
  197. return m3d;
  198. }
  199. /**
  200. * Load a Magicavoxel VOX file
  201. */
  202. m3d_t *vox_load(unsigned char *data, int size)
  203. {
  204. unsigned char *s, *d, *e = data + size;
  205. uint32_t *pal = vox_palette;
  206. int i, j, min_x = 255, min_y = 255, min_z = 255, mi_x, mi_y, mi_z, ma_x, ma_y, ma_z, x, y, z;
  207. int psiz = 256, siz, tr[256];
  208. m3d_t *m3d;
  209. m3d = alloc_voxm3d();
  210. memset(tr, 0, sizeof(tr));
  211. for(s = data + 20; s < e; s++) {
  212. if(!memcmp(s, "RGBA", 4)) {
  213. pal = (uint32_t*)(s + 8); psiz = *((uint32_t*)(s + 4)) / 4;
  214. /* use the children size field as the first (empty) color, and we don't have to mess with palette indices */
  215. pal[0] = 0;
  216. } else
  217. if(!memcmp(s, "XYZI", 4)) {
  218. m3d->numvoxel++;
  219. siz = (*((uint32_t*)(s + 4)) / 4) - 1;
  220. s += 16;
  221. for(i = 0; i < siz; i++, s += 4) {
  222. if(s[3]) {
  223. if(s[0] < min_x) min_x = s[0];
  224. if(s[1] < min_z) min_z = s[1];
  225. if(s[2] < min_y) min_y = s[2];
  226. }
  227. tr[s[3]] = 1;
  228. }
  229. s--;
  230. continue;
  231. }
  232. s += *((uint32_t*)(s + 4)) + 11;
  233. }
  234. if(!m3d->numvoxel) {
  235. free(m3d);
  236. return NULL;
  237. }
  238. if(!m3d->voxtype) {
  239. for(i = 1; i < psiz; i++)
  240. m3d->numvoxtype += tr[i];
  241. m3d->voxtype = (m3dvt_t*)malloc(m3d->numvoxtype * sizeof(m3dvt_t));
  242. if(!m3d->voxtype) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  243. memset(m3d->voxtype, 0, m3d->numvoxtype * sizeof(m3dvt_t));
  244. for(i = j = 0; i < psiz && j < (int)m3d->numvoxtype; i++)
  245. if(i && tr[i]) {
  246. m3d->voxtype[j].color = pal[i];
  247. m3d->voxtype[j].materialid = M3D_UNDEF;
  248. m3d->voxtype[j].skinid = M3D_UNDEF;
  249. tr[i] = j++;
  250. } else
  251. tr[i] = -1;
  252. } else {
  253. for(i = 0; i < psiz; i++)
  254. tr[i] = voxpal && !forcevoxpal ? color2voxtypeid(pal[i], m3d) : i-1;
  255. }
  256. m3d->voxel = (m3dvx_t*)malloc(m3d->numvoxel * sizeof(m3dvx_t));
  257. if(!m3d->voxel) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  258. memset(m3d->voxel, 0, m3d->numvoxel * sizeof(m3dvx_t));
  259. /* read in the layers */
  260. for(j = 0, s = data + 20; s < e; s++) {
  261. if(!memcmp(s, "XYZI", 4)) {
  262. siz = (*((uint32_t*)(s + 4)) / 4) - 1;
  263. s += 16; d = s;
  264. mi_x = mi_y = mi_z = 255; ma_x = ma_y = ma_z = 0;
  265. for(i = 0; i < siz; i++, s += 4)
  266. if(s[3]) {
  267. if(s[0] < mi_x) mi_x = s[0];
  268. if(s[0] > ma_x) ma_x = s[0];
  269. if(s[1] < mi_z) mi_z = s[1];
  270. if(s[1] > ma_z) ma_z = s[1];
  271. if(s[2] < mi_y) mi_y = s[2];
  272. if(s[2] > ma_y) ma_y = s[2];
  273. }
  274. m3d->voxel[j].x = mi_x - min_x;
  275. m3d->voxel[j].y = mi_y - min_y;
  276. m3d->voxel[j].z = mi_z - min_z;
  277. m3d->voxel[j].w = ma_x - mi_x + 1;
  278. m3d->voxel[j].h = ma_y - mi_y + 1;
  279. m3d->voxel[j].d = ma_z - mi_z + 1;
  280. m3d->voxel[j].data = (M3D_VOXEL*)malloc(m3d->voxel[j].w * m3d->voxel[j].h * m3d->voxel[j].d * sizeof(M3D_VOXEL));
  281. if(!m3d->voxel[j].data) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  282. memset(m3d->voxel[j].data, 0xff, m3d->voxel[j].w * m3d->voxel[j].h * m3d->voxel[j].d * sizeof(M3D_VOXEL));
  283. for(s = d, i = 0; i < siz; i++, s += 4)
  284. if(s[3]) {
  285. x = s[0] - mi_x;
  286. z = s[1] - mi_z;
  287. y = s[2] - mi_y;
  288. m3d->voxel[j].data[y*m3d->voxel[j].w*m3d->voxel[j].d + (m3d->voxel[j].d-z-1)*m3d->voxel[j].w + x] =
  289. (M3D_VOXEL)tr[s[3]];
  290. }
  291. j++;
  292. s--;
  293. continue;
  294. }
  295. s += *((uint32_t*)(s + 4)) + 11;
  296. }
  297. return m3d;
  298. }
  299. /**
  300. * Load a BINVOX file
  301. */
  302. m3d_t *binvox_load(unsigned char *data, int size)
  303. {
  304. int i, j, n, sx = 0, sy = 0, sz = 0, x, y, z;
  305. unsigned char *s, *e = data + size;
  306. m3d_t *m3d;
  307. for(s = data; s < e && memcmp(s, "data", 4); s++)
  308. if(!memcmp(s, "dim ", 4)) {
  309. s += 4;
  310. /* accoring to the doc: depth, width and height. Couldn't be worse... */
  311. while(*s == ' ') { s++; } sz = atoi((char*)s); while(*s >= '0' && *s <= '9') { s++; }
  312. while(*s == ' ') { s++; } sx = atoi((char*)s); while(*s >= '0' && *s <= '9') { s++; }
  313. while(*s == ' ') { s++; } sy = atoi((char*)s);
  314. }
  315. if(!sx || !sy || !sz || memcmp(s, "data", 4)) return NULL;
  316. while(*s && *s != '\n') s++;
  317. while(*s == '\n') s++;
  318. m3d = alloc_voxm3d();
  319. m3d->numvoxel = 1;
  320. m3d->voxel = (m3dvx_t*)malloc(m3d->numvoxel * sizeof(m3dvx_t));
  321. if(!m3d->voxel) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  322. memset(m3d->voxel, 0, m3d->numvoxel * sizeof(m3dvx_t));
  323. m3d->voxel[0].w = sx;
  324. m3d->voxel[0].h = sy;
  325. m3d->voxel[0].d = sz;
  326. n = sx * sy * sz;
  327. m3d->voxel[0].data = (M3D_VOXEL*)malloc(n * sizeof(M3D_VOXEL));
  328. if(!m3d->voxel[0].data) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  329. if(!m3d->voxtype) {
  330. m3d->numvoxtype = 1;
  331. m3d->voxtype = (m3dvt_t*)malloc(m3d->numvoxtype * sizeof(m3dvt_t));
  332. if(!m3d->voxtype) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  333. memset(m3d->voxtype, 0, m3d->numvoxtype * sizeof(m3dvt_t));
  334. m3d->voxtype[0].color = 0xFF235580;
  335. m3d->voxtype[0].materialid = M3D_UNDEF;
  336. m3d->voxtype[0].skinid = M3D_UNDEF;
  337. }
  338. for(i = x = y = z = 0; i < n && s < e && x < sx; s += 2)
  339. for(j = 0; j < s[1] && x < sx; j++, i++) {
  340. /* according to the doc: y-coordinate runs fastest, then the z-coordinate, then the x-coordinate */
  341. m3d->voxel[0].data[y*sx*sz + z*sx + x] = s[0] ? 0 : M3D_VOXUNDEF;
  342. y++; if(y >= sy) { y = 0; z++; if(z >= sz) { z = 0; x++; } }
  343. }
  344. return m3d;
  345. }
  346. /**
  347. * Load a Qubicle QB file
  348. */
  349. int _qb_color2voxtypeid(m3d_t *m3d, int cf, unsigned char *s)
  350. {
  351. uint32_t c;
  352. int i, j;
  353. if(!s[3]) return -1;
  354. c = (uint32_t)(0xFF000000 | (cf ? ((uint32_t)s[0] << 16) | ((uint32_t)s[1] << 8) | (uint32_t)s[2] : *((uint32_t*)s)));
  355. if(m3d->voxtype) {
  356. for(i = 0; i < (int)m3d->numvoxtype; i++)
  357. if(m3d->voxtype[i].color == c) return i;
  358. }
  359. if(voxpal)
  360. return forcevoxpal ? -1 : color2voxtypeid(c, m3d);
  361. j = m3d->numvoxtype++;
  362. m3d->voxtype = (m3dvt_t*)realloc(m3d->voxtype, m3d->numvoxtype * sizeof(m3dvt_t));
  363. if(!m3d->voxtype) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  364. memset(&m3d->voxtype[j], 0, sizeof(m3dvt_t));
  365. m3d->voxtype[j].color = c;
  366. m3d->voxtype[j].materialid = M3D_UNDEF;
  367. m3d->voxtype[j].skinid = M3D_UNDEF;
  368. return j;
  369. }
  370. m3d_t *qb_load(unsigned char *data, int size)
  371. {
  372. int cf = data[4], za = data[8], co = data[12], mc = *((int*)(data+20)), i, j, k, l, x, y, z, sx, sy, sz;
  373. unsigned char *s, *e = data + size;
  374. uint32_t c;
  375. m3d_t *m3d;
  376. m3d = alloc_voxm3d();
  377. m3d->numvoxel = mc;
  378. m3d->voxel = (m3dvx_t*)malloc(m3d->numvoxel * sizeof(m3dvx_t));
  379. if(!m3d->voxel) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  380. memset(m3d->voxel, 0, m3d->numvoxel * sizeof(m3dvx_t));
  381. for(s = data + 24, i = 0; i < mc && s < e; i++) {
  382. j = (*s++) + 1;
  383. m3d->voxel[i].name = (char*)malloc(j);
  384. if(!m3d->voxel[i].name) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  385. memcpy(m3d->voxel[i].name, s, j);
  386. s += j;
  387. m3d->voxel[i].w = sx = *((uint32_t*)s); s += 4;
  388. m3d->voxel[i].d = sz = *((uint32_t*)s); s += 4;
  389. m3d->voxel[i].h = sy = *((uint32_t*)s); s += 4;
  390. m3d->voxel[i].x = *((uint32_t*)s); s += 4;
  391. m3d->voxel[i].z = *((uint32_t*)s); s += 4;
  392. m3d->voxel[i].y = *((uint32_t*)s); s += 4;
  393. m3d->voxel[i].data = (M3D_VOXEL*)malloc(sx * sy * sz * sizeof(M3D_VOXEL));
  394. if(!m3d->voxel[i].data) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  395. memset(m3d->voxel[i].data, 0xff, sx * sy * sz * sizeof(M3D_VOXEL));
  396. if(co) {
  397. for(y = 0; y < sy; y++) {
  398. for(i = 0; 1;) {
  399. c = *((uint32_t*)s); s += 4;
  400. if(c == 6 || c == 0x60000) break;
  401. if(c == 2 || c == 0x20000) { l = *((int32_t*)s); s += 4; c = *((uint32_t*)s); s += 4; } else l = 1;
  402. k = _qb_color2voxtypeid(m3d, cf, (unsigned char*)&c);
  403. for(j = 0; j < l; j++, i++) {
  404. x = i % sx; z = i / sx;
  405. m3d->voxel[i].data[y*sx*sz + (za?z:sz-z-1)*sx + x] = k;
  406. }
  407. }
  408. }
  409. } else {
  410. for(y = 0; y < sy; y++)
  411. for(z = 0; z < sz; z++)
  412. for(x = 0; x < sx; x++, s += 4)
  413. m3d->voxel[i].data[y*sx*sz + (za?z:sz-z-1)*sx + x] = _qb_color2voxtypeid(m3d, cf, s);
  414. }
  415. }
  416. return m3d;
  417. }
  418. /**
  419. * Convert surfaces and other parameterized shapes into voxel volume
  420. */
  421. void voxelize_shapes(int n, m3d_t *m3d)
  422. {
  423. if(n <= 0 || !m3d->numshape || !m3d->shape || !m3d->numvertex || !m3d->vertex) return;
  424. /* TODO */
  425. fprintf(stderr,"m3dconv: shape voxelization is under development.\n");
  426. }
  427. /**
  428. * Voxelize a triangle mesh (opposite of tri_voxels() in tri.h)
  429. */
  430. void voxelize_face(int n, m3d_t *m3d)
  431. {
  432. if(n <= 0 || !m3d->numface || !m3d->face || !m3d->numvertex || !m3d->vertex) return;
  433. /* TODO */
  434. fprintf(stderr,"m3dconv: triangle mesh voxelization is under development.\n");
  435. }