@@ -1088,6 +1088,363 @@ public void SaveToFile(string filePath, Action<bool, string> loggingFunction = n
1088
1088
ModelModifiers . MakeImportReady ( this , loggingFunction ) ;
1089
1089
}
1090
1090
1091
+ /// <summary>
1092
+ /// Saves a TTModel to a .DB file for use with external importers/exporters.
1093
+ /// </summary>
1094
+ /// <param name="filePath"></param>
1095
+ /// <param name="loggingFunction"></param>
1096
+ public void SaveFullToFile ( string filePath , Action < bool , string > loggingFunction = null )
1097
+ {
1098
+ if ( loggingFunction == null )
1099
+ {
1100
+ loggingFunction = ModelModifiers . NoOp ;
1101
+ }
1102
+
1103
+ var directory = Path . GetDirectoryName ( filePath ) ;
1104
+
1105
+ ModelModifiers . MakeExportReady ( this , loggingFunction ) ;
1106
+
1107
+ var connectionString = "Data Source=" + filePath + ";Pooling=False;" ;
1108
+ try
1109
+ {
1110
+ var boneDict = ResolveBoneHeirarchy ( ) ;
1111
+
1112
+ // Spawn a DB connection to do the raw queries.
1113
+ // Using statements help ensure we don't accidentally leave any connections open and lock the file handle.
1114
+ using ( var db = new SQLiteConnection ( connectionString ) )
1115
+ {
1116
+ db . Open ( ) ;
1117
+
1118
+ // Write the Data.
1119
+ using ( var transaction = db . BeginTransaction ( ) )
1120
+ {
1121
+ // Get the model Ids already in the DB
1122
+ var modelList = new List < int > ( ) ;
1123
+ var getModelQuery = "SELECT model FROM models" ;
1124
+ using ( var cmd = new SQLiteCommand ( getModelQuery , db ) )
1125
+ {
1126
+ var sqReader = cmd . ExecuteReader ( ) ;
1127
+
1128
+ while ( sqReader . Read ( ) )
1129
+ {
1130
+ modelList . Add ( sqReader . GetInt32 ( 0 ) ) ;
1131
+ }
1132
+ }
1133
+
1134
+ var modelIdx = modelList . Any ( ) ? modelList . Max ( ) + 1 : 0 ;
1135
+ var modelName = Path . GetFileNameWithoutExtension ( Source ) ;
1136
+
1137
+ //Models
1138
+ var query = @"insert into models (model, name) values ($model, $name);" ;
1139
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1140
+ {
1141
+ cmd . Parameters . AddWithValue ( "model" , modelIdx ) ;
1142
+ cmd . Parameters . AddWithValue ( "name" , modelName ) ;
1143
+
1144
+ cmd . ExecuteScalar ( ) ;
1145
+ }
1146
+
1147
+ // Get the skeleton names already in the DB
1148
+ var skelList = new List < string > ( ) ;
1149
+ var getSkelQuery = "SELECT name FROM skeleton" ;
1150
+ using ( var cmd = new SQLiteCommand ( getSkelQuery , db ) )
1151
+ {
1152
+ var sqReader = cmd . ExecuteReader ( ) ;
1153
+
1154
+ while ( sqReader . Read ( ) )
1155
+ {
1156
+ skelList . Add ( sqReader . GetString ( 0 ) ) ;
1157
+ }
1158
+ }
1159
+
1160
+ // Skeleton
1161
+ query = @"insert into skeleton (name, parent, matrix_0, matrix_1, matrix_2, matrix_3, matrix_4, matrix_5, matrix_6, matrix_7, matrix_8, matrix_9, matrix_10, matrix_11, matrix_12, matrix_13, matrix_14, matrix_15)
1162
+ values ($name, $parent, $matrix_0, $matrix_1, $matrix_2, $matrix_3, $matrix_4, $matrix_5, $matrix_6, $matrix_7, $matrix_8, $matrix_9, $matrix_10, $matrix_11, $matrix_12, $matrix_13, $matrix_14, $matrix_15);" ;
1163
+
1164
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1165
+ {
1166
+ foreach ( var b in boneDict )
1167
+ {
1168
+ // Skip the bone if it's already in the DB
1169
+ if ( skelList . Contains ( b . Value . BoneName ) ) continue ;
1170
+
1171
+ var parent = boneDict . FirstOrDefault ( x => x . Value . BoneNumber == b . Value . BoneParent ) ;
1172
+ var parentName = parent . Key == null ? null : parent . Key ;
1173
+ cmd . Parameters . AddWithValue ( "name" , b . Value . BoneName ) ;
1174
+ cmd . Parameters . AddWithValue ( "parent" , parentName ) ;
1175
+
1176
+ for ( int i = 0 ; i < 16 ; i ++ )
1177
+ {
1178
+ cmd . Parameters . AddWithValue ( "matrix_" + i . ToString ( ) , b . Value . PoseMatrix [ i ] ) ;
1179
+ }
1180
+
1181
+ cmd . ExecuteScalar ( ) ;
1182
+ }
1183
+ }
1184
+
1185
+ // Get the material ids already in the DB
1186
+ var matIdList = new List < int > ( ) ;
1187
+ var getMatIdQuery = "SELECT material_id FROM materials" ;
1188
+ using ( var cmd = new SQLiteCommand ( getMatIdQuery , db ) )
1189
+ {
1190
+ var sqReader = cmd . ExecuteReader ( ) ;
1191
+
1192
+ while ( sqReader . Read ( ) )
1193
+ {
1194
+ matIdList . Add ( sqReader . GetInt32 ( 0 ) ) ;
1195
+ }
1196
+ }
1197
+
1198
+ // Start from the last material ID in the DB
1199
+ var matIdx = matIdList . Any ( ) ? matIdList . Max ( ) + 1 : 0 ;
1200
+ var tempMatDict = new Dictionary < string , int > ( ) ;
1201
+ foreach ( var material in Materials )
1202
+ {
1203
+ // Materials
1204
+ query = @"insert into materials (material_id, name, diffuse, normal, specular, opacity, emissive) values ($material_id, $name, $diffuse, $normal, $specular, $opacity, $emissive);" ;
1205
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1206
+ {
1207
+ var mtrl_prefix = directory + "\\ " + Path . GetFileNameWithoutExtension ( material . Substring ( 1 ) ) + "_" ;
1208
+ var mtrl_suffix = ".png" ;
1209
+ var name = material ;
1210
+ try
1211
+ {
1212
+ name = Path . GetFileNameWithoutExtension ( material ) ;
1213
+ }
1214
+ catch
1215
+ {
1216
+
1217
+ }
1218
+ cmd . Parameters . AddWithValue ( "material_id" , matIdx ) ;
1219
+ cmd . Parameters . AddWithValue ( "name" , name ) ;
1220
+ cmd . Parameters . AddWithValue ( "diffuse" , mtrl_prefix + "d" + mtrl_suffix ) ;
1221
+ cmd . Parameters . AddWithValue ( "normal" , mtrl_prefix + "n" + mtrl_suffix ) ;
1222
+ cmd . Parameters . AddWithValue ( "specular" , mtrl_prefix + "s" + mtrl_suffix ) ;
1223
+ cmd . Parameters . AddWithValue ( "emissive" , mtrl_prefix + "e" + mtrl_suffix ) ;
1224
+ cmd . Parameters . AddWithValue ( "opacity" , mtrl_prefix + "o" + mtrl_suffix ) ;
1225
+ cmd . ExecuteScalar ( ) ;
1226
+ }
1227
+ tempMatDict . Add ( Path . GetFileNameWithoutExtension ( material ) , matIdx ) ;
1228
+ matIdx ++ ;
1229
+ }
1230
+
1231
+ // Get the mesh ids already in the DB for Bones
1232
+ var meshIdList = new List < int > ( ) ;
1233
+ var getMeshIdQuery = "SELECT mesh FROM bones" ;
1234
+ using ( var cmd = new SQLiteCommand ( getMeshIdQuery , db ) )
1235
+ {
1236
+ var sqReader = cmd . ExecuteReader ( ) ;
1237
+
1238
+ while ( sqReader . Read ( ) )
1239
+ {
1240
+ meshIdList . Add ( sqReader . GetInt32 ( 0 ) ) ;
1241
+ }
1242
+ }
1243
+
1244
+ // Start from the last mesh ID in the DB
1245
+ var meshIdx = meshIdList . Any ( ) ? meshIdList . Max ( ) + 1 : 0 ;
1246
+ foreach ( var m in MeshGroups )
1247
+ {
1248
+ // Bones
1249
+ query = @"insert into bones (mesh, bone_id, name) values ($mesh, $bone_id, $name);" ;
1250
+ var bIdx = 0 ;
1251
+ foreach ( var b in m . Bones )
1252
+ {
1253
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1254
+ {
1255
+ cmd . Parameters . AddWithValue ( "name" , b ) ;
1256
+ cmd . Parameters . AddWithValue ( "bone_id" , bIdx ) ;
1257
+ cmd . Parameters . AddWithValue ( "parent_id" , null ) ;
1258
+ cmd . Parameters . AddWithValue ( "mesh" , meshIdx ) ;
1259
+ cmd . ExecuteScalar ( ) ;
1260
+ }
1261
+ bIdx ++ ;
1262
+ }
1263
+
1264
+ // Meshes
1265
+ query = @"insert into meshes (mesh, model, name, material_id) values ($mesh, $model, $name, $material_id);" ;
1266
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1267
+ {
1268
+ cmd . Parameters . AddWithValue ( "name" , m . Name ) ;
1269
+ cmd . Parameters . AddWithValue ( "model" , modelIdx ) ;
1270
+ cmd . Parameters . AddWithValue ( "mesh" , meshIdx ) ;
1271
+ cmd . Parameters . AddWithValue ( "material_id" , tempMatDict [ Path . GetFileNameWithoutExtension ( m . Material ) ] ) ;
1272
+ cmd . ExecuteScalar ( ) ;
1273
+ }
1274
+
1275
+
1276
+ // Parts
1277
+ var partIdx = 0 ;
1278
+ foreach ( var p in m . Parts )
1279
+ {
1280
+ // Parts
1281
+ query = @"insert into parts (mesh, part, name) values ($mesh, $part, $name);" ;
1282
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1283
+ {
1284
+ cmd . Parameters . AddWithValue ( "name" , p . Name ) ;
1285
+ cmd . Parameters . AddWithValue ( "part" , partIdx ) ;
1286
+ cmd . Parameters . AddWithValue ( "mesh" , meshIdx ) ;
1287
+ cmd . ExecuteScalar ( ) ;
1288
+ }
1289
+
1290
+ // Vertices
1291
+ var vIdx = 0 ;
1292
+ foreach ( var v in p . Vertices )
1293
+ {
1294
+ query = @"insert into vertices ( mesh, part, vertex_id, position_x, position_y, position_z, normal_x, normal_y, normal_z, color_r, color_g, color_b, color_a, uv_1_u, uv_1_v, uv_2_u, uv_2_v, bone_1_id, bone_1_weight, bone_2_id, bone_2_weight, bone_3_id, bone_3_weight, bone_4_id, bone_4_weight)
1295
+ values ($mesh, $part, $vertex_id, $position_x, $position_y, $position_z, $normal_x, $normal_y, $normal_z, $color_r, $color_g, $color_b, $color_a, $uv_1_u, $uv_1_v, $uv_2_u, $uv_2_v, $bone_1_id, $bone_1_weight, $bone_2_id, $bone_2_weight, $bone_3_id, $bone_3_weight, $bone_4_id, $bone_4_weight);" ;
1296
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1297
+ {
1298
+ cmd . Parameters . AddWithValue ( "part" , partIdx ) ;
1299
+ cmd . Parameters . AddWithValue ( "mesh" , meshIdx ) ;
1300
+ cmd . Parameters . AddWithValue ( "vertex_id" , vIdx ) ;
1301
+
1302
+ cmd . Parameters . AddWithValue ( "position_x" , v . Position . X ) ;
1303
+ cmd . Parameters . AddWithValue ( "position_y" , v . Position . Y ) ;
1304
+ cmd . Parameters . AddWithValue ( "position_z" , v . Position . Z ) ;
1305
+
1306
+ cmd . Parameters . AddWithValue ( "normal_x" , v . Normal . X ) ;
1307
+ cmd . Parameters . AddWithValue ( "normal_y" , v . Normal . Y ) ;
1308
+ cmd . Parameters . AddWithValue ( "normal_z" , v . Normal . Z ) ;
1309
+
1310
+ cmd . Parameters . AddWithValue ( "color_r" , v . VertexColor [ 0 ] / 255f ) ;
1311
+ cmd . Parameters . AddWithValue ( "color_g" , v . VertexColor [ 1 ] / 255f ) ;
1312
+ cmd . Parameters . AddWithValue ( "color_b" , v . VertexColor [ 2 ] / 255f ) ;
1313
+ cmd . Parameters . AddWithValue ( "color_a" , v . VertexColor [ 3 ] / 255f ) ;
1314
+
1315
+ cmd . Parameters . AddWithValue ( "uv_1_u" , v . UV1 . X ) ;
1316
+ cmd . Parameters . AddWithValue ( "uv_1_v" , v . UV1 . Y ) ;
1317
+ cmd . Parameters . AddWithValue ( "uv_2_u" , v . UV2 . X ) ;
1318
+ cmd . Parameters . AddWithValue ( "uv_2_v" , v . UV2 . Y ) ;
1319
+
1320
+
1321
+ cmd . Parameters . AddWithValue ( "bone_1_id" , v . BoneIds [ 0 ] ) ;
1322
+ cmd . Parameters . AddWithValue ( "bone_1_weight" , v . Weights [ 0 ] / 255f ) ;
1323
+
1324
+ cmd . Parameters . AddWithValue ( "bone_2_id" , v . BoneIds [ 1 ] ) ;
1325
+ cmd . Parameters . AddWithValue ( "bone_2_weight" , v . Weights [ 1 ] / 255f ) ;
1326
+
1327
+ cmd . Parameters . AddWithValue ( "bone_3_id" , v . BoneIds [ 2 ] ) ;
1328
+ cmd . Parameters . AddWithValue ( "bone_3_weight" , v . Weights [ 2 ] / 255f ) ;
1329
+
1330
+ cmd . Parameters . AddWithValue ( "bone_4_id" , v . BoneIds [ 3 ] ) ;
1331
+ cmd . Parameters . AddWithValue ( "bone_4_weight" , v . Weights [ 3 ] / 255f ) ;
1332
+
1333
+ cmd . ExecuteScalar ( ) ;
1334
+ vIdx ++ ;
1335
+ }
1336
+ }
1337
+
1338
+ // Indices
1339
+ for ( var i = 0 ; i < p . TriangleIndices . Count ; i ++ )
1340
+ {
1341
+ query = @"insert into indices (mesh, part, index_id, vertex_id) values ($mesh, $part, $index_id, $vertex_id);" ;
1342
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1343
+ {
1344
+ cmd . Parameters . AddWithValue ( "part" , partIdx ) ;
1345
+ cmd . Parameters . AddWithValue ( "mesh" , meshIdx ) ;
1346
+ cmd . Parameters . AddWithValue ( "index_id" , i ) ;
1347
+ cmd . Parameters . AddWithValue ( "vertex_id" , p . TriangleIndices [ i ] ) ;
1348
+ cmd . ExecuteScalar ( ) ;
1349
+ }
1350
+ }
1351
+
1352
+ partIdx ++ ;
1353
+ }
1354
+
1355
+ meshIdx ++ ;
1356
+
1357
+
1358
+ }
1359
+ transaction . Commit ( ) ;
1360
+ }
1361
+ }
1362
+ }
1363
+ catch ( Exception Ex )
1364
+ {
1365
+ ModelModifiers . MakeImportReady ( this , loggingFunction ) ;
1366
+ throw Ex ;
1367
+ }
1368
+
1369
+ // Undo the export ready at the start.
1370
+ ModelModifiers . MakeImportReady ( this , loggingFunction ) ;
1371
+ }
1372
+
1373
+ /// <summary>
1374
+ /// Create the DB and set the Meta Data for the full model
1375
+ /// </summary>
1376
+ /// <param name="filePath">The DB file path</param>
1377
+ /// <param name="fullModelName">The name of the full model</param>
1378
+ public void SetFullModelDBMetaData ( string filePath , string fullModelName )
1379
+ {
1380
+ var connectionString = "Data Source=" + filePath + ";Pooling=False;" ;
1381
+
1382
+ try
1383
+ {
1384
+ const string creationScript = "CreateImportDB.sql" ;
1385
+
1386
+ using ( var db = new SQLiteConnection ( connectionString ) )
1387
+ {
1388
+ db . Open ( ) ;
1389
+
1390
+ // Create the DB
1391
+ var lines = File . ReadAllLines ( "Resources\\ SQL\\ " + creationScript ) ;
1392
+ var sqlCmd = String . Join ( "\n " , lines ) ;
1393
+
1394
+ using ( var cmd = new SQLiteCommand ( sqlCmd , db ) )
1395
+ {
1396
+ cmd . ExecuteScalar ( ) ;
1397
+ }
1398
+
1399
+ using ( var transaction = db . BeginTransaction ( ) )
1400
+ {
1401
+ // Metadata.
1402
+ var query = @"insert into meta (key, value) values ($key, $value)" ;
1403
+ using ( var cmd = new SQLiteCommand ( query , db ) )
1404
+ {
1405
+ // FFXIV stores stuff in Meters.
1406
+ cmd . Parameters . AddWithValue ( "key" , "unit" ) ;
1407
+ cmd . Parameters . AddWithValue ( "value" , "meter" ) ;
1408
+ cmd . ExecuteScalar ( ) ;
1409
+
1410
+ // Application that created the db.
1411
+ cmd . Parameters . AddWithValue ( "key" , "application" ) ;
1412
+ cmd . Parameters . AddWithValue ( "value" , "ffxiv_tt" ) ;
1413
+ cmd . ExecuteScalar ( ) ;
1414
+
1415
+ // Does the framework NOT have a version identifier? I couldn't find one, so the Cache version works.
1416
+ cmd . Parameters . AddWithValue ( "key" , "version" ) ;
1417
+ cmd . Parameters . AddWithValue ( "value" , XivCache . CacheVersion ) ;
1418
+ cmd . ExecuteScalar ( ) ;
1419
+
1420
+ // Axis information
1421
+ cmd . Parameters . AddWithValue ( "key" , "up" ) ;
1422
+ cmd . Parameters . AddWithValue ( "value" , "y" ) ;
1423
+ cmd . ExecuteScalar ( ) ;
1424
+
1425
+ cmd . Parameters . AddWithValue ( "key" , "front" ) ;
1426
+ cmd . Parameters . AddWithValue ( "value" , "z" ) ;
1427
+ cmd . ExecuteScalar ( ) ;
1428
+
1429
+ cmd . Parameters . AddWithValue ( "key" , "handedness" ) ;
1430
+ cmd . Parameters . AddWithValue ( "value" , "r" ) ;
1431
+ cmd . ExecuteScalar ( ) ;
1432
+
1433
+ // FFXIV stores stuff in Meters.
1434
+ cmd . Parameters . AddWithValue ( "key" , "name" ) ;
1435
+ cmd . Parameters . AddWithValue ( "value" , fullModelName ) ;
1436
+ cmd . ExecuteScalar ( ) ;
1437
+ }
1438
+ transaction . Commit ( ) ;
1439
+ }
1440
+ }
1441
+ }
1442
+ catch ( Exception ex )
1443
+ {
1444
+
1445
+ }
1446
+ }
1447
+
1091
1448
/// <summary>
1092
1449
/// Creates and populates a TTModel object from a raw XivMdl
1093
1450
/// </summary>
0 commit comments