catalog.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. <?php
  2. /*
  3. * tools/catalog.php
  4. *
  5. * Copyright (C) 2019 bzt (bztsrc@gitlab)
  6. *
  7. * Permission is hereby granted, free of charge, to any person
  8. * obtaining a copy of this software and associated documentation
  9. * files (the "Software"), to deal in the Software without
  10. * restriction, including without limitation the rights to use, copy,
  11. * modify, merge, publish, distribute, sublicense, and/or sell copies
  12. * of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be
  16. * included in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  22. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  23. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  25. * DEALINGS IN THE SOFTWARE.
  26. *
  27. * @brief Tool to generate Model 3D homepage and model catalog
  28. * https://gitlab.com/bztsrc/model3d
  29. *
  30. */
  31. /* helper function to convert models and get its properties */
  32. function convertmodel($line, $in, $dir) {
  33. $path = pathinfo($line[0]);
  34. $m3d = $dir."/models/".$path['filename'].".m3d";
  35. $png = escapeshellarg($dir."/models/".$path['filename'].".png");
  36. $cmd = "";
  37. if(!file_exists($in."/".$line[0])) { echo("File not found '".$in."/".$line[0]."'\n"); return; }
  38. if(!file_exists($m3d) || filemtime($in."/".$line[0]) > @filemtime($m3d)) {
  39. if($path['extension'] == "m3d") {
  40. copy($in."/".$line[0], $m3d);
  41. } else
  42. $cmd = "../m3dconv/m3dconv -i".$line[1]." ".
  43. "-n ".escapeshellarg($line[2])." -l ".escapeshellarg($line[3])." -a ".escapeshellarg($line[4])." ".
  44. escapeshellarg($in."/".$line[0])." ".escapeshellarg($m3d)." && ";
  45. }
  46. $p = popen($cmd."../m3dview/m3dview ".escapeshellarg($m3d)." ".$png, "r");
  47. $n = trim(fgets($p));
  48. $l = trim(fgets($p));
  49. $d = explode(",",trim(fgets($p)));
  50. pclose($p);
  51. $t = [$line[5]];
  52. for($i=6;$i<count($line);$i++) $t = array_merge($t, explode(",", $line[$i]));
  53. for($i=0;$i<count($t);$i++) $t[$i] = trim(mb_strtolower($t[$i]));
  54. if($d[0] < 1024 && !in_array("lowpoly", $t)) $t[] = "lowpoly";
  55. if($d[0] > 65535 && !in_array("highres", $t)) $t[] = "highres";
  56. if($d[12]) $d[0] = $d[2] = $d[6] = 0;
  57. return ["n"=>$n,"p"=>$path['filename'],"s"=>filesize($dir."/models/".$path['filename'].".m3d"),
  58. "l"=>$l==","?"Public Domain":$l,"f"=>$d[0],"u"=>$d[1],"o"=>$d[2],"h"=>$d[3],"U"=>$d[4],"O"=>$d[5],"v"=>$d[6],
  59. "m"=>$d[7],"t"=>$d[8],"b"=>$d[9],"a"=>$d[10],"L"=>$d[11],"V"=>$d[12],"c"=>$t];
  60. }
  61. function safename($n)
  62. {
  63. if(mb_substr($n,1,1) == " ") $n = mb_substr($n, 2);
  64. return htmlspecialchars(mb_strtolower($n));
  65. }
  66. function nicename($n)
  67. {
  68. if(mb_substr($n,1,1) == " ") { $p = mb_substr($n, 0, 2); $n = mb_substr($n, 2); }
  69. else { $p = ""; }
  70. return htmlspecialchars($p.mb_strtoupper(mb_substr($n, 0, 1)).mb_substr($n, 1));
  71. }
  72. /* check arguments */
  73. if(empty($_SERVER['argv'][2])) {
  74. die("Model 3D Homepage and Model Catalog Generator\n\nphp catalog.php <source csv> <output dir>\n\n".
  75. "CSV: file,convopts,name,license,author,category,tags\n");
  76. }
  77. /* parse input csv and convert models */
  78. $models = []; $cat = [];
  79. if(($f = fopen($_SERVER['argv'][1], "r")) !== FALSE) {
  80. for($n = 0; fgets($f) !== FALSE && !feof($f); $n++);
  81. fseek($f, 0);
  82. $l = 0;
  83. @mkdir($_SERVER['argv'][2]."/models");
  84. mb_internal_encoding("UTF-8");
  85. while(($line = fgetcsv($f)) !== FALSE && count($line) > 5) {
  86. echo("\r".round(++$l*100/$n, 2)."% -i".$line[1]." ".$line[0]." ");
  87. if($line[0][0]=='#') continue;
  88. $data = convertmodel($line, dirname($_SERVER['argv'][1]), $_SERVER['argv'][2]);
  89. $models[] = $data;
  90. $cat[$data["c"][0]] = 1;
  91. }
  92. fclose($f);
  93. echo("\r ");
  94. echo("\rDone. ".count($models)." models in ".count($cat)." categories.\n");
  95. }
  96. if(empty($models)) die();
  97. usort($models, function($a, $b){ return strnatcasecmp($a["n"], $b["n"]); });
  98. $cat = array_keys($cat);
  99. /* generate index.html */
  100. $f = fopen($_SERVER['argv'][2]."/index.html", "w");
  101. fwrite($f, '<!DOCTYPE html>
  102. <html lang="en">
  103. <head>
  104. <meta charset="utf-8">
  105. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  106. <meta name="description" content="Model 3D, file format, triangle mesh, Assimp, Blender, SDK, C, C++">
  107. <meta name="author" content="bzt">
  108. <title>Model 3D</title>
  109. <link href="logo.png" rel="shortcut icon">
  110. <link href="bootstrap.min.css" rel="stylesheet">
  111. <style>
  112. body { padding-top: 64px; }
  113. .card { height: 100%; }
  114. .headerbg {background: #333 url(images/headerbg.png) center;background-size: cover;}
  115. .headerbg p {text-shadow: 2px 2px 2px #000;}
  116. .headerbg h1 {text-shadow: 3px 3px 5px #000;}
  117. .headerbg div {padding-bottom:5px;}
  118. .headerbg img { height: 30px; margin-right: 20px;}
  119. #content, #results { padding-bottom: 25px; }
  120. #menuchk:checked ~ .navbar-collapse { display:block; }
  121. .nav-link { cursor:pointer; }
  122. .nav-link:hover { border-color: #888; }
  123. .nav-tabs { border-bottom: 1px solid #888; }
  124. .nav-tabs li { position: relative; bottom: -1px; }
  125. .nav-tabs li label { margin-bottom: 0px !important; cursor: inherit; }
  126. .tabcol { border-bottom: 1px solid #888; }
  127. .webdemo img { margin: 10px; }
  128. #results .row { padding: 10px; border: 1px solid #dee2e6; border-radius: .25rem; margin: 10px; }
  129. #results .row div > img { width: 320px; height: 240px; cursor:pointer; background:url(images/bg.png) 50% 0px no-repeat; }
  130. #results .row small { cursor:pointer; }
  131. #results .row a { margin-top: 5px; width: 320px; }
  132. #results .row a img { margin-right:10px; }
  133. #results .row th, .filename { font-size:80% }
  134. #results .row td { text-align: right; }
  135. #results .row .card-text { display: none; }
  136. #results .card { width: 170px; padding:5px; margin:5px; display:inline-block; text-align:center; }
  137. #results .card img { width:160px; height:120px; cursor:pointer; }
  138. #results .card .col-lg-5 { max-width:100%!important;padding:0px!important; }
  139. #results .card a, #results .card .col-lg-7, #results .hidden { display:none; }
  140. ');
  141. for($i = 0; $i < count($cat); $i++)
  142. fwrite($f, '#tab'.$i.':checked ~ ul li[rel="tab'.$i.'"]'.($i == count($cat)-1 ? '' : ",\n"));
  143. fwrite($f, ' { border-color: #888 #888 #fff; cursor: default; }
  144. input[name="tab"], div[rel^="tab"] { display: none; }
  145. </style>
  146. </head>
  147. <body>
  148. <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
  149. <div class="container">
  150. <a class="navbar-brand" href="/model3d/"><img src="images/model3dhdr.png" height="30" alt="Model 3D"> Model 3D</a>
  151. <input type="checkbox" id="menuchk" style="display:none;"><label for="menuchk" class="navbar-toggler">
  152. <span class="navbar-toggler-icon"></span>
  153. </label>
  154. <div class="collapse navbar-collapse" id="navbarResponsive">
  155. <ul class="navbar-nav ml-auto">
  156. <li class="nav-item">
  157. <a class="nav-link" href="/model3d/">Home</a>
  158. </li>
  159. <li class="nav-item">
  160. <a class="nav-link" href="#features" onclick="changedivs(0);">Features</a>
  161. </li>
  162. <li class="nav-item">
  163. <a class="nav-link" href="#sdk" onclick="changedivs(0);">Usage</a>
  164. </li>
  165. <li class="nav-item">
  166. <a class="nav-link" href="#models" onclick="changedivs(1);">Models</a>
  167. </li>
  168. <li class="nav-item">
  169. <a class="nav-link" href="https://gitlab.com/bztsrc/model3d/issues">Issues</a>
  170. </li>
  171. </ul>
  172. </div>
  173. </div>
  174. </nav>
  175. <div style="display:none;"><img src="images/headerbg.png" alt=""></div>
  176. <div class="container" id="content" style="display:block;">
  177. <header class="jumbotron my-4 headerbg" id="home">
  178. <h1 class="display-3 text-white">Welcome to Model 3D!</h1>
  179. <p class="lead text-white">Model 3D is an application and engine neutral, universal 3D model format to store CAD models, meshes, skeletal animations and voxel images. It comes with a dependency-free, single header ANSI C/C++ SDK.</p>
  180. <div class="row text-center">
  181. <div class="col-lg-6"><a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md" class="btn btn-primary btn-lg btn-block" target="new"><img src="images/download.png" alt="Specification">Specification</a></div>
  182. <div class="col-lg-6"><a href="https://gitlab.com/bztsrc/model3d/" class="btn btn-primary btn-lg btn-block" target="new"><img src="images/gitlab.png" alt="GitLab">Browse the Source</a></div>
  183. </div>
  184. </header>
  185. <div class="card text-white bg-secondary my-4" id="features">
  186. <div class="card-body">
  187. <p class="text-white text-center m-0">The file format and the SDK is Open Source and free as in free beer! Licensed under <a href="https://gitlab.com/bztsrc/model3d/blob/master/LICENSE" class="text-white" target="new"><b>MIT license</b></a>.</p>
  188. </div>
  189. </div>
  190. <div class="row text-center">
  191. <div class="col-lg-3 col-md-6 mb-4">
  192. <div class="card">
  193. <h4 class="card-header">Compact</h4>
  194. <div class="card-body">
  195. <small class="card-text">The format has the best data density of all the available 3D model formats (including <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/CAD.md" target="new">CAD</a>), easy on network traffic. Parsing is painless and lightning fast.</small>
  196. </div>
  197. <div class="card-footer">
  198. <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/performance.md" class="btn btn-primary" target="new">Find Out More!</a>
  199. </div>
  200. </div>
  201. </div>
  202. <div class="col-lg-3 col-md-6 mb-4">
  203. <div class="card">
  204. <h4 class="card-header">Animations</h4>
  205. <div class="card-body">
  206. <small class="card-text">It can store multiple skeleton-based animations in a model file (so called actions). The SDK makes it easy to get the animation-pose for each.</small>
  207. </div>
  208. <div class="card-footer">
  209. <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/usage.md" class="btn btn-primary" target="new">Find Out More!</a>
  210. </div>
  211. </div>
  212. </div>
  213. <div class="col-lg-3 col-md-6 mb-4">
  214. <div class="card">
  215. <h4 class="card-header">Procedural</h4>
  216. <div class="card-body">
  217. <small class="card-text">Model 3D is capable of storing procedural textures and faces. Any scripting language can be used, the SDK ships <a href="https://gitlab.com/bztsrc/model3d/blob/master/m3d_lua.h" target="new">Lua binding</a> as a Proof of Concept.</small>
  218. </div>
  219. <div class="card-footer">
  220. <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/procedural.md" class="btn btn-primary" target="new">Find Out More!</a>
  221. </div>
  222. </div>
  223. </div>
  224. <div class="col-lg-3 col-md-6 mb-4">
  225. <div class="card">
  226. <h4 class="card-header">Integration</h4>
  227. <div class="card-body">
  228. <small class="card-text">Extremely easy to integrate into any project and any workflow. A command line tool can convert from any format, and a <a href="https://blender.org" target="new">Blender</a> plugin is provided to export M3D models.</small>
  229. </div>
  230. <div class="card-footer">
  231. <a href="https://gitlab.com/bztsrc/model3d/tree/master/blender/" class="btn btn-primary" target="new">Find Out More!</a>
  232. </div>
  233. </div>
  234. </div>
  235. </div>
  236. <hr>
  237. <div class="row">
  238. <div class="col-lg-12">
  239. <h2>Embeddable on webpages</h2>
  240. <p>With the <a href="https://gitlab.com/bztsrc/model3d/tree/master/webgl-js/" target="new">WebGL polyfill</a>, you can include Model 3D files in webpages just like normal 2D images! Hint: drag the images below!</p>
  241. </div>
  242. </div>
  243. <div class="row text-center">
  244. <div class="col-lg-4 webdemo">
  245. <img src="models/cube_with_vertexcolors.m3d" width="300" height="300" alt="demo"><br><small><samp>&lt;img src="cube.m3d" width="300" height="300"&gt;</samp></small>
  246. </div>
  247. <div class="col-lg-4 webdemo">
  248. <img src="models/suzanne.m3d" width="300" height="300" alt="demo"><br><small><samp>&lt;img src="suzanne.m3d" width="300" height="300"&gt;</samp></small>
  249. </div>
  250. <div class="col-lg-4 webdemo">
  251. <img src="models/voxelimg.m3d" width="300" height="300" alt="demo"><br><small><samp>&lt;img src="voxelimg.m3d" width="300" height="300"&gt;</samp></small>
  252. </div>
  253. </div>
  254. <hr id="sdk">
  255. <div class="row">
  256. <div class="col-lg-12">
  257. <h2>Easy to use Software Development Kit</h2>
  258. <ul>
  259. <li>The M3D SDK is an stb-style, dependency-free <a href="https://gitlab.com/bztsrc/model3d/blob/master/m3d.h" target="new">single header</a> file written in ANSI C89, licensed under MIT.</li>
  260. <li>If you prefer, the SDK can provide a C++11 wrapper class around the C API, or you can write your own.</li>
  261. <li>You can configure the SDK using defines to add <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/a3d_format.md" target="new">ASCII format</a> support or model exporting functionality.</li>
  262. <li>You don\'t have to worry about the textures, the SDK will decompress PNG textures for you on its own (no library needed).</li>
  263. <li>Unlike other 3D model SDKs, the in-memory format is simple, your code that interfaces with it can be extremely simple.</li>
  264. <li>Follows the K.I.S.S. principle, there\'re only <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/API.md" target="new">5 functions in the API</a>.</li>
  265. <li>The <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/usage.md" target="new">API manual</a> provides you with detailed description and SDK usage examples.</li>
  266. <li>You can integrate the <a href="https://gitlab.com/bztsrc/model3d/tree/master/m3dconv" target="new">m3dconv</a> utility into your build environment to convert foreign models in compilation time.</li>
  267. <li>There\'s a <a href="https://gitlab.com/bztsrc/model3d/tree/master/m3dview" target="new">simple model viewer</a>, which demonstrates how to display animated models using the M3D SDK (also available as a <a href="viewer">web service</a>).</li>
  268. </ul>
  269. </div>
  270. </div>
  271. <hr>
  272. <div class="row">
  273. <div class="col-lg-12">
  274. <h2>Convert Anything into Model 3D</h2>
  275. <ul>
  276. <li>The <a href="https://gitlab.com/bztsrc/model3d/tree/master/blender/" target="new">Blender plugin</a> makes it possible to directly save models into Model 3D format.</li>
  277. <!--
  278. <li>A similar <a href="https://gitlab.com/bztsrc/model3d/tree/master/maya/" target="new">Maya plugin</a> exists for AutoDesk Maya.</li>
  279. <li>As well as a <a href="https://gitlab.com/bztsrc/model3d/tree/master/lw3d/" target="new">LW3D plugin</a> for Lightwave 3D.</li>
  280. -->
  281. <li>With the <a href="https://gitlab.com/bztsrc/model3d/tree/master/m3dconv" target="new">m3dconv</a> command line tool you can convert almost any existing model into Model 3D easily:</li>
  282. <li>Fully supports <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/obj_spec.md" target="new">Wavefront OBJ</a> (including negative indices, Bezier curves / surfaces, B-spline and NURBS), and a <a href="https://webstore.ansi.org/Standards/ISO/ISO10303212016" target="new">STEP</a> (ISO-10303-21-4 / ISO-10303-24-2) file importer is on the way.</li>
  283. <li>Simple text files with skeletal animations using <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/ms3d.md" target="new">Milkshape 3D</a> (this is a very simple format, similar to OBJ, widely supported and damn easy to create programatically).</li>
  284. <li>Simple binary files with <a href="https://gitlab.com/bztsrc/model3d/blob/master/docs/pmx_format.md" target="new">Polygon Model eXtended</a> (PMX, used by the Miku Miku Dance software and many others, popular exchange format for its features and relative simplicity).</li>
  285. <li>Voxel images, like <a href="http://www.patrickmin.com/binvox/binvox.html" target="new">BINVOX</a> files, <a href="https://minecraft.gamepedia.com/Schematic_file_format" target="new">Minecraft Schematic</a> files, <a href="https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt" target="new">Magicavoxel VOX</a> files and <a href="https://getqubicle.com/qubicle/documentation/docs/file/qb" target="new">Qubicle QB</a> files can be converted too efficiently.</li>
  286. <li>FBX support via the <a href="https://github.com/bqqbarbhg/ufbx" target="new">uFBX</a> library (included).</li>
  287. <li>Other supported formats via <a href="http://assimp.org" target="new">Assimp</a> (not included, dinamically linked): GLTF, GLB, 3DS, 3DS MAX, X, ASE, BLEND, COLLADA (DAE), B3D, MS3D, MD5, MESH, STL, PLY and many many more...</li>
  288. <li>When running into problems with loading a specific model, you can use the web based <a href="validator">Model 3D file validator</a>, or run <samp>m3dconv -D</samp> natively on your local computer.</li>
  289. </ul>
  290. </div>
  291. </div>
  292. <hr>
  293. <div class="row">
  294. <div class="col-lg-12">
  295. <h2>Projects using Model 3D</h2>
  296. <ul>
  297. <li><a href="https://www.raylib.com/" target="new">raylib</a> a multiplatform, simple and easy-to-use programming library to enjoy videogames programming.</li>
  298. <li><a href="https://gitlab.com/bztsrc/mtsedit" target="new">mtsedit</a> a Minetest Schematic editor, which can import Model 3D voxel files.</li>
  299. <li><a href="https://tirnanog.codeberg.page" target="new">TirNanoG</a> an Action and Adventure RPG creation suite, which can generate 2D sprite sheets from Model 3D files.</li>
  300. <li><a href="https://machengine.org/" target="new">Mach</a> game engine and graphics toolkit for the future.</li>
  301. </ul>
  302. <small>(Open an <a href="https://gitlab.com/bztsrc/model3d/issues" target="new">issue</a> if you want your project to be listed here.)</small>
  303. </div>
  304. </div>
  305. </div>
  306. <div class="container" id="models" style="display:block;">
  307. <div id="modelsearch" style="display:none;margin-bottom:10px;">
  308. <div class="row">
  309. <div class="col-lg-12">
  310. <h2>Search Model 3D Samples</h2>
  311. </div>
  312. </div>
  313. <div class="row">
  314. <div class="col-lg-2 tabcol">
  315. <input class="form-control" id="srch" type="text" placeholder="Search..." onkeyup="dosearch();">
  316. <input type="hidden" id="last" value="">
  317. <input type="hidden" id="tag" value="">
  318. </div>
  319. <div class="col-lg-10" style="padding-left:0px;">
  320. ');
  321. for($i = 0; $i < count($cat); $i++)
  322. fwrite($f, '<input type="radio" name="tab" id="tab'.$i.'" onchange="dosearch(this.value);" value="'.safename($cat[$i]).'"'.(!$i?" checked":"").'>'."\n");
  323. fwrite($f, ' <ul class="nav nav-tabs">');
  324. for($i = 0; $i < count($cat); $i++)
  325. fwrite($f, ' <li class="nav-link" rel="tab'.$i.'"><label for="tab'.$i.'">'.nicename($cat[$i]).'</label></li>'."\n");
  326. fwrite($f, ' </ul>
  327. </div>
  328. </div>
  329. </div>
  330. <div id="modelhdr" class="row" style="display:block;">
  331. <hr>
  332. <div class="col-lg-12">
  333. <h2>Model 3D Samples</h2>
  334. </div>
  335. </div>
  336. <div id="results">
  337. ');
  338. for($i = 0; $i < count($models); $i++) {
  339. $s = $models[$i]["s"]; $u = " bytes";
  340. if($s < 8) continue;
  341. if($s > 1023) { $s = floor(($s + 1023)/1024); $u = " Kib"; }
  342. fwrite($f, ' <div class="row">
  343. <div class="col-lg-5 text-center"><img src="models/'.$models[$i]["p"].'.png" alt="" onclick="togglediv(this);"><div class="card-text">'.htmlspecialchars($models[$i]["n"]).'</div>
  344. <a href="models/'.$models[$i]["p"].'.m3d" class="btn btn-primary" target="new"><img src="images/download.png" alt="Download">Download</a></div>
  345. <div class="col-lg-7">
  346. <h5>'.htmlspecialchars($models[$i]["n"]).'</h5>
  347. <p>'.htmlspecialchars($models[$i]["l"]).'</p>
  348. <table class="table table-sm table-striped">
  349. <tr><th>File</th><td class="filename">'.htmlspecialchars($models[$i]["p"]).'.m3d ('.number_format($s,0,""," ").$u.')</td></tr>
  350. <tr><th>Polygons'.($models[$i]["u"]?' <span class="badge badge-dark">UV</span>':'').($models[$i]["o"]?' <span class="badge badge-dark">Normals</span>':'').'</th><td>'.number_format($models[$i]["f"],0,""," ").'</td></tr>
  351. <tr><th>Shapes'.($models[$i]["U"]?' <span class="badge badge-dark">UV</span>':'').($models[$i]["O"]?' <span class="badge badge-dark">Normals</span>':'').'</th><td>'.number_format($models[$i]["h"],0,""," ").'</td></tr>
  352. <tr><th>Vertices</th><td>'.number_format($models[$i]["v"],0,""," ").'</td></tr>
  353. <tr><th>Voxels</th><td>'.number_format($models[$i]["V"],0,""," ").'</td></tr>
  354. <tr><th>Materials</th><td><span class="badge badge-'.($models[$i]["m"]>0?'success">Yes':'danger">No').'</span></td></tr>
  355. <tr><th>Textures inlined</th><td><span class="badge badge-'.($models[$i]["t"]>0?'success">Yes':'danger">No').'</span></td></tr>
  356. <tr><th>Rigged (bones + skin)</th><td><span class="badge badge-'.($models[$i]["b"]>0?'success">Yes':'danger">No').'</span></td></tr>
  357. <tr><th>Animated</th><td><span class="badge badge-'.($models[$i]["a"]>0?'success">Yes':'danger">No').'</span></td></tr>
  358. </table>
  359. ');
  360. foreach($models[$i]["c"] as $c)
  361. fwrite($f, ' <small class="badge badge-pill badge-secondary" onclick="dosearch(this.innerText);">'.safename($c).'</small>'."\n");
  362. fwrite($f, ' </div>
  363. </div>
  364. ');
  365. }
  366. fwrite($f, ' </div>
  367. </div>
  368. <footer class="py-5 bg-dark">
  369. <div class="container">
  370. <p class="text-center text-white">Copyright &copy; bzt (bztsrc@gitlab) 2019.</p>
  371. </div>
  372. </footer>
  373. <script>
  374. function changedivs(isModels) {
  375. document.getElementById("content").style.display = isModels? "none" : "block";
  376. document.getElementById("models").style.display = isModels? "block" : "none";
  377. if(isModels) window.scrollTo(0,0);
  378. }
  379. function togglediv(div) {
  380. var divs = document.querySelectorAll("#results .row");
  381. var i, pdiv = div != undefined ? div.parentNode.parentNode : undefined;
  382. var pclose = pdiv != undefined ? pdiv.className == "row" : 0;
  383. for(i = 0; i < divs.length; i++) divs[i].className = "card";
  384. if(!pclose && pdiv != undefined) pdiv.className = "row";
  385. }
  386. function dosearch(newtag) {
  387. var srch = document.getElementById("srch"), last = document.getElementById("last"), tag = document.getElementById("tag");
  388. var i, j, fnd, divs = document.getElementById("results").childNodes, srchval;
  389. if(newtag != undefined && newtag != null) { tag.value = newtag; last.value = srch.value + "a"; }
  390. else if(tag.value == "") tag.value = document.getElementById("tab0").value;
  391. if(last.value != srch.value) {
  392. last.value = srch.value;
  393. srchval = srch.value.toLowerCase();
  394. for(i = 0; i < divs.length; i++) {
  395. if(divs[i].tagName != "DIV") continue;
  396. var tags = divs[i].getElementsByTagName("div")[2].getElementsByTagName("small");
  397. var name = divs[i].getElementsByTagName("h5")[0].innerText.toLowerCase();
  398. fnd = 0;
  399. for(j = 0; j < tags.length; j++)
  400. if(tags[j].innerText == tag.value) { fnd = 1; break; }
  401. if(fnd && srchval != "" && !name.includes(srchval)) fnd = 0;
  402. divs[i].className = fnd ? "card" : "hidden";
  403. }
  404. }
  405. }
  406. /* replace model ist with searchable cards if we have javascript */
  407. document.addEventListener("DOMContentLoaded", function(e) {
  408. changedivs(document.location.href.split("#")[1] == "models");
  409. document.getElementById("modelhdr").style.display = "none";
  410. document.getElementById("modelsearch").style.display = "block";
  411. togglediv();
  412. dosearch(document.getElementById("tab0").value);
  413. });
  414. </script>
  415. <script src="m3d.min.js"></script>
  416. </body>
  417. </html>
  418. ');
  419. fclose($f);