ModelDatabase.hx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package h3d.prim;
  2. typedef ModelDataInput = {
  3. var resourceDirectory : String;
  4. var resourceName : String;
  5. var objectName : String;
  6. var hmd : HMDModel;
  7. var skin : h3d.scene.Skin;
  8. }
  9. class ModelDatabase {
  10. public static var db : Map<String, Dynamic> = new Map();
  11. var baseDir(get, never) : String;
  12. static var FILE_NAME = "model.props";
  13. static var LOD_CONFIG = "lodConfig";
  14. static var LOD_CONFIG_FIELD = "lods.screenRatio";
  15. static var DYN_BONES_CONFIG = "dynamicBones";
  16. #if (sys || nodejs)
  17. static var defaultLodConfigs : Map<String, hxd.fs.FileConverter.ConvertConfig> = new Map();
  18. #end
  19. static var baseLodConfig = [ 0.5, 0.2, 0.01];
  20. public static dynamic function customizeLodConfig(c : Array<Float>) {
  21. return c;
  22. }
  23. function new() {
  24. }
  25. function get_baseDir() return '';
  26. function getFilePath( directory : String ) {
  27. return directory == null || directory == "" ? FILE_NAME : directory + "/" + FILE_NAME;
  28. }
  29. function getRootData( directory : String ) {
  30. if( directory == null )
  31. return null;
  32. var cached = ModelDatabase.db.get(directory);
  33. if( cached != null )
  34. return cached;
  35. var file = getFilePath(directory);
  36. var value = try haxe.Json.parse(hxd.res.Loader.currentInstance.load(file).toText()) catch( e : hxd.res.NotFound ) {};
  37. ModelDatabase.db.set(directory, value);
  38. return value;
  39. }
  40. function getModelData( directory : String, resourceName : String, modelName : String ) {
  41. var key = resourceName + "/" + modelName;
  42. var rootData = getRootData(directory);
  43. cleanOldModelData(rootData, key);
  44. return Reflect.field(rootData, key);
  45. }
  46. function saveModelData( directory : String, resourceName : String, modelName : String, data : Dynamic ) {
  47. var file = getFilePath(directory);
  48. var rootData = getRootData(directory);
  49. var key = resourceName + "/" + modelName;
  50. if (data == null || Reflect.fields(data).length == 0)
  51. Reflect.deleteField(rootData, key);
  52. else
  53. Reflect.setField(rootData, key, data);
  54. #if ((sys || nodejs) && !usesys)
  55. var fs = Std.downcast(hxd.res.Loader.currentInstance.fs, hxd.fs.LocalFileSystem);
  56. if( fs != null && !haxe.io.Path.isAbsolute(file) )
  57. file = fs.baseDir + file;
  58. if( rootData == null || Reflect.fields(rootData).length == 0 )
  59. (try sys.FileSystem.deleteFile(file) catch( e : Dynamic ) {});
  60. else
  61. sys.io.File.saveContent(file, haxe.Json.stringify(rootData, "\t"));
  62. #else
  63. throw "Can't save model props database " + file;
  64. #end
  65. }
  66. function getDefaultLodConfig( dir : String ) : Array<Float> {
  67. var fs = Std.downcast(hxd.res.Loader.currentInstance.fs, hxd.fs.LocalFileSystem);
  68. var c = baseLodConfig;
  69. #if (sys || nodejs)
  70. if (fs != null) {
  71. var conf : hxd.fs.FileConverter.ConvertConfig = null;
  72. function getConvertConf(obj : Dynamic) : hxd.fs.FileConverter.ConvertConfig {
  73. var defObj = {};
  74. Reflect.setField(defObj, LOD_CONFIG_FIELD, obj);
  75. return @:privateAccess fs.convert.makeConfig(defObj);
  76. }
  77. conf = @:privateAccess fs.convert.getConfig(defaultLodConfigs, getConvertConf(baseLodConfig), dir, function(fullObj) {
  78. return fs.convert.makeConfig(fullObj);
  79. });
  80. c = Reflect.field(conf.obj, LOD_CONFIG_FIELD);
  81. }
  82. #end
  83. c = customizeLodConfig(c);
  84. return c;
  85. }
  86. // Used to clean previous version of modelDatabase, should be removed after some time
  87. function cleanOldModelData( rootData : Dynamic, key : String) {
  88. var oldLodConfig = Reflect.field(rootData, LOD_CONFIG);
  89. if (oldLodConfig != null) {
  90. for (f in Reflect.fields(oldLodConfig)) {
  91. if (key.indexOf(f) < 0 && '${key}_LOD0'.indexOf(f) < 0)
  92. continue;
  93. var c = Reflect.field(oldLodConfig, f);
  94. var newData = { "lodConfig" : c };
  95. Reflect.setField(rootData, key, newData);
  96. // Remove old entry
  97. Reflect.deleteField(oldLodConfig, f);
  98. Reflect.setField(rootData, LOD_CONFIG, oldLodConfig);
  99. }
  100. if (oldLodConfig == null || Reflect.fields(oldLodConfig).length == 0)
  101. Reflect.deleteField(rootData, LOD_CONFIG);
  102. }
  103. }
  104. function loadLodConfig( input : ModelDataInput, data : Dynamic ) {
  105. var c = Reflect.field(data, LOD_CONFIG);
  106. if (c == null || input.hmd == null)
  107. return;
  108. @:privateAccess input.hmd.lodConfig = c;
  109. }
  110. function loadDynamicBonesConfig( input : ModelDataInput, data : Dynamic) {
  111. var c : Array<Dynamic> = Reflect.field(data, DYN_BONES_CONFIG);
  112. if (c == null || input.skin == null)
  113. return;
  114. function getJointConf(j: h3d.anim.Skin.Joint) {
  115. for (jConf in c)
  116. if (jConf.name == j.name)
  117. return jConf;
  118. return null;
  119. }
  120. var skinData = input.skin.getSkinData();
  121. for (j in skinData.allJoints) {
  122. var jConf = getJointConf(j);
  123. if (jConf == null)
  124. continue;
  125. var newJ = new h3d.anim.Skin.DynamicJoint();
  126. newJ.index = j.index;
  127. newJ.name = j.name;
  128. newJ.bindIndex = j.bindIndex;
  129. newJ.splitIndex = j.splitIndex;
  130. newJ.defMat = j.defMat;
  131. newJ.transPos = j.transPos;
  132. newJ.parent = j.parent;
  133. newJ.follow = j.follow;
  134. newJ.subs = j.subs;
  135. newJ.offsets = j.offsets;
  136. newJ.offsetRay = j.offsetRay;
  137. newJ.retargetAnim = j.retargetAnim;
  138. newJ.damping = jConf.damping;
  139. newJ.resistance = jConf.resistance;
  140. newJ.slackness = jConf.slackness;
  141. newJ.stiffness = jConf.stiffness;
  142. newJ.additive = jConf.additive;
  143. newJ.lockAxis = jConf.lockAxis == null ? new Vector(0, 0, 0): new Vector(jConf.lockAxis?.x, jConf.lockAxis?.y, jConf.lockAxis?.z);
  144. newJ.globalForce = new Vector(jConf.globalForce.x, jConf.globalForce.y, jConf.globalForce.z);
  145. skinData.allJoints[j.index] = newJ;
  146. j.parent?.subs.push(newJ);
  147. j.parent?.subs.remove(j);
  148. if (newJ.subs != null) {
  149. for (s in newJ.subs)
  150. s.parent = newJ;
  151. }
  152. }
  153. input.skin.setSkinData(skinData);
  154. }
  155. function saveLodConfig( input : ModelDataInput, data : Dynamic ) @:privateAccess {
  156. var isDefaultConfig = true;
  157. var defaultConfig = getDefaultLodConfig(input.resourceDirectory);
  158. if (input.hmd.lodConfig != null) {
  159. if (defaultConfig.length != input.hmd.lodConfig.length)
  160. isDefaultConfig = false;
  161. for (idx in 0...input.hmd.lodConfig.length) {
  162. if (defaultConfig[idx] != input.hmd.lodConfig[idx]) {
  163. isDefaultConfig = false;
  164. break;
  165. }
  166. }
  167. }
  168. if (!isDefaultConfig) {
  169. var c = [];
  170. for (idx in 0...input.hmd.lodCount()) {
  171. if (idx >= input.hmd.lodConfig.length)
  172. c[idx] = 0.;
  173. else
  174. c[idx] = input.hmd.lodConfig[idx];
  175. }
  176. Reflect.setField(data, LOD_CONFIG, c);
  177. }
  178. else
  179. Reflect.deleteField(data, LOD_CONFIG);
  180. }
  181. function saveDynamicBonesConfig( input : ModelDataInput, data : Dynamic ) {
  182. if (input.skin == null)
  183. return;
  184. var dynamicJoints = [];
  185. for (j in input.skin.getSkinData().allJoints) {
  186. var dynJ = Std.downcast(j, h3d.anim.Skin.DynamicJoint);
  187. if (dynJ == null)
  188. continue;
  189. dynamicJoints.push({
  190. name: dynJ.name,
  191. slackness: dynJ.slackness,
  192. stiffness: dynJ.stiffness,
  193. resistance: dynJ.resistance,
  194. damping: dynJ.damping,
  195. additive: dynJ.additive,
  196. globalForce: dynJ.globalForce,
  197. lockAxis: dynJ.lockAxis });
  198. }
  199. if (dynamicJoints.length == 0) {
  200. Reflect.deleteField(data, DYN_BONES_CONFIG);
  201. return;
  202. }
  203. Reflect.setField(data, DYN_BONES_CONFIG, dynamicJoints);
  204. }
  205. public function loadModelProps( input : ModelDataInput ) {
  206. var data : Dynamic = getModelData(input.resourceDirectory, input.resourceName, input.objectName);
  207. if (data == null)
  208. return;
  209. loadLodConfig(input, data);
  210. loadDynamicBonesConfig(input, data);
  211. }
  212. public function saveModelProps( input : ModelDataInput ) {
  213. var data : Dynamic = getModelData(input.resourceDirectory, input.resourceName, input.objectName);
  214. if( data == null )
  215. data = {};
  216. saveLodConfig(input, data);
  217. saveDynamicBonesConfig(input, data);
  218. saveModelData(input.resourceDirectory, input.resourceName, input.objectName, data);
  219. }
  220. public static var current = new ModelDatabase();
  221. }