1162 :(NSString *)
filename scaleFactor:(float)scale
1163{
1165
1166 NSScanner *scanner;
1167 NSDictionary *cacheData =
nil;
1168 BOOL failFlag = NO;
1169 NSString *failString = @"***** ";
1170 unsigned i, j;
1171 NSMutableDictionary *texFileName2Idx =
nil;
1172 NSString *cacheKey =
nil;
1173 BOOL using_preloaded = NO;
1174
1175 cacheKey = [NSString stringWithFormat:@"%@:%u:%.3f", filename, _normalMode, scale];
1177 if (cacheData !=
nil)
1178 {
1179 if ([
self setModelFromModelData:cacheData name:
filename])
1180 {
1181 using_preloaded = YES;
1182 PROFILE(
@"loaded from cache");
1183 OOLog(
@"mesh.load.cached",
@"Retrieved mesh \"%@\
" from cache.",
filename);
1184 }
1185 }
1186
1187 if (!using_preloaded)
1188 {
1189 OOLog(
@"mesh.load.uncached",
@"Mesh \"%@\
" is not in cache, loading.", cacheKey);
1190
1191 NSCharacterSet *whitespaceCharSet = [NSCharacterSet whitespaceCharacterSet];
1192 NSCharacterSet *whitespaceAndNewlineCharSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
1193#if OOLITE_MAC_OS_X
1194 NSCharacterSet *newlineCharSet = [NSCharacterSet newlineCharacterSet];
1195#else
1196 static NSCharacterSet *newlineCharSet =
nil;
1197 if (newlineCharSet ==
nil)
1198 {
1199 NSMutableCharacterSet *temp = [[whitespaceAndNewlineCharSet mutableCopy] autorelease];
1200 [temp formIntersectionWithCharacterSet:[whitespaceCharSet invertedSet]];
1201 newlineCharSet = [temp copy];
1202 }
1203#endif
1204
1205 texFileName2Idx = [NSMutableDictionary dictionary];
1206
1207 {
1208 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1211 {
1212
1215 return NO;
1216 }
1217
1218
1219 NSMutableArray *lines = [NSMutableArray arrayWithArray:[data componentsSeparatedByString:@"\n"]];
1220 for (i = 0; i < [lines count]; i++)
1221 {
1222 NSString *line = [lines objectAtIndex:i];
1223 NSArray *parts;
1224
1225
1226
1227 parts = [line componentsSeparatedByString:@"#"];
1228 line = [parts objectAtIndex:0];
1229 parts = [line componentsSeparatedByString:@"//"];
1230 line = [parts objectAtIndex:0];
1231
1232
1233
1234 line = [[line componentsSeparatedByString:@","] componentsJoinedByString:@" "];
1235
1236 [lines replaceObjectAtIndex:i withObject:line];
1237 }
1238
1239 data = [lines componentsJoinedByString:@"\n"];
1240 scanner = [NSScanner scannerWithString:data];
1241
1242 [scanner retain];
1243 [pool release];
1244 [scanner autorelease];
1245 }
1246
1247 PROFILE(
@"finished preprocessing");
1248
1249
1250
1251 [scanner setScanLocation:0];
1252 if ([scanner scanString:@"NVERTS" intoString:NULL])
1253 {
1254 int n_v;
1255 if ([scanner scanInt:&n_v])
1256 vertexCount = n_v;
1257 else
1258 {
1259 failFlag = YES;
1260 failString = [NSString stringWithFormat:@"%@Failed to read value of NVERTS\n",failString];
1261 }
1262 }
1263 else
1264 {
1265 failFlag = YES;
1266 failString = [NSString stringWithFormat:@"%@Failed to read NVERTS\n",failString];
1267 }
1268
1269 if (![self allocateVertexBuffersWithCount:vertexCount])
1270 {
1272 return NO;
1273 }
1274
1275
1276 if ([scanner scanString:@"NFACES" intoString:NULL])
1277 {
1278 int n_f;
1279 if ([scanner scanInt:&n_f])
1280 {
1281 faceCount = n_f;
1282 }
1283 else
1284 {
1285 failFlag = YES;
1286 failString = [NSString stringWithFormat:@"%@Failed to read value of NFACES\n",failString];
1287 }
1288 }
1289 else
1290 {
1291 failFlag = YES;
1292 failString = [NSString stringWithFormat:@"%@Failed to read NFACES\n",failString];
1293 }
1294
1295
1298 if (faceRefs != NULL)
1299 {
1300
1301 NSData *faceRefHolder = [NSData dataWithBytesNoCopy:faceRefs length:faceRefSize freeWhenDone:YES];
1302 if (faceRefHolder ==
nil)
1303 {
1304 free(faceRefs);
1305 faceRefs = NULL;
1306 }
1307 }
1308
1309 if (faceRefs == NULL || ![self allocateFaceBuffersWithCount:faceCount])
1310 {
1312 return NO;
1313 }
1314
1315
1316 if ([scanner scanString:@"VERTEX" intoString:NULL])
1317 {
1318 for (j = 0; j < vertexCount; j++)
1319 {
1321 if (!failFlag)
1322 {
1323 if (![scanner scanFloat:&
x]) failFlag = YES;
1324 if (![scanner scanFloat:&
y]) failFlag = YES;
1325 if (![scanner scanFloat:&z]) failFlag = YES;
1326 if (!failFlag)
1327 {
1328 _vertices[j] = make_vector(
x*scale,
y*scale, z*scale);
1329 }
1330 else
1331 {
1332 failString = [NSString stringWithFormat:@"%@Failed to read a value for vertex[%d] in %@\n", failString, j, @"VERTEX"];
1333 }
1334 }
1335 }
1336 }
1337 else
1338 {
1339 failFlag = YES;
1340 failString = [NSString stringWithFormat:@"%@Failed to find VERTEX data\n",failString];
1341 }
1342
1343
1344 if ([scanner scanString:@"FACES" intoString:NULL])
1345 {
1346 for (j = 0; j < faceCount; j++)
1347 {
1348 int r, g, b;
1349 float nx, ny, nz;
1350 int n_v;
1351 if (!failFlag)
1352 {
1353
1354 if (![scanner scanInt:&r]) failFlag = YES;
1355 if (![scanner scanInt:&g]) failFlag = YES;
1356 if (![scanner scanInt:&b]) failFlag = YES;
1357 if (!failFlag)
1358 {
1359 _faces[j].smoothGroup = r;
1360 }
1361 else
1362 {
1363 failString = [NSString stringWithFormat:@"%@Failed to read a color for face[%d] in FACES\n", failString, j];
1364 }
1365
1366
1367 if (![scanner scanFloat:&nx]) failFlag = YES;
1368 if (![scanner scanFloat:&ny]) failFlag = YES;
1369 if (![scanner scanFloat:&nz]) failFlag = YES;
1370 if (!failFlag)
1371 {
1372 _faces[j].normal = vector_normal(make_vector(nx, ny, nz));
1373 }
1374 else
1375 {
1376 failString = [NSString stringWithFormat:@"%@Failed to read a normal for face[%d] in FACES\n", failString, j];
1377 }
1378
1379
1380 if ([scanner scanInt:&n_v])
1381 {
1382 if (n_v < 3)
1383 {
1384 failFlag = YES;
1385 failString = [NSString stringWithFormat:@"%@Face[%u] has fewer than three vertices.\n", failString, j];
1386 }
1387 else if (n_v > 3)
1388 {
1389 OOLogWARN(
@"mesh.load.warning.nonTriangular",
@"Face[%u] of %@ has %u vertices specified. Only the first three will be used.", j, baseFile, n_v);
1390 n_v = 3;
1391 }
1392 }
1393 else
1394 {
1395 failFlag = YES;
1396 failString = [NSString stringWithFormat:@"%@Failed to read number of vertices for face[%d] in FACES\n", failString, j];
1397 }
1398
1399 if (!failFlag)
1400 {
1401 int vi;
1402 for (i = 0; (
int)i < n_v; i++)
1403 {
1404 if ([scanner scanInt:&vi])
1405 {
1406 _faces[j].vertex[i] = vi;
1407 if (faceRefs != NULL)
VFRAddFace(&faceRefs[vi], j);
1408 }
1409 else
1410 {
1411 failFlag = YES;
1412 failString = [NSString stringWithFormat:@"%@Failed to read vertex[%d] for face[%d] in FACES\n", failString, i, j];
1413 }
1414 }
1415 }
1416 }
1417 }
1418 }
1419 else
1420 {
1421 failFlag = YES;
1422 failString = [NSString stringWithFormat:@"%@Failed to find FACES data\n",failString];
1423 }
1424
1425
1426 if ([scanner scanString:@"TEXTURES" intoString:NULL])
1427 {
1428 for (j = 0; j < faceCount; j++)
1429 {
1430 NSString *materialKey;
1431 float max_x, max_y;
1432 float s, t;
1433 if (!failFlag)
1434 {
1435
1436
1437 [scanner scanCharactersFromSet:whitespaceAndNewlineCharSet intoString:NULL];
1438 if (![scanner scanUpToCharactersFromSet:whitespaceCharSet intoString:&materialKey])
1439 {
1440 failFlag = YES;
1441 failString = [NSString stringWithFormat:@"%@Failed to read texture filename for face[%d] in TEXTURES\n", failString, j];
1442 }
1443 else
1444 {
1445 NSNumber *index = [texFileName2Idx objectForKey:materialKey];
1447 {
1448 _faces[j].materialIndex = [index unsignedIntValue];
1449 }
1450 else
1451 {
1453 {
1455 return NO;
1456 }
1457 _faces[j].materialIndex = materialCount;
1458 materialKeys[materialCount] = [materialKey retain];
1459 index = [NSNumber numberWithUnsignedInt:materialCount];
1460 [texFileName2Idx setObject:index forKey:materialKey];
1461 ++materialCount;
1462 }
1463 }
1464
1465
1466
1467 if (!failFlag)
1468 {
1469 if (![scanner scanFloat:&max_x]) failFlag = YES;
1470 if (![scanner scanFloat:&max_y]) failFlag = YES;
1471 if (failFlag)
1472 failString = [NSString stringWithFormat:@"%@Failed to read texture size for max_x and max_y in face[%d] in TEXTURES\n", failString, j];
1473 }
1474
1475
1476
1477 if (!failFlag)
1478 {
1479 for (i = 0; i < 3; i++)
1480 {
1481 if (![scanner scanFloat:&s]) failFlag = YES;
1482 if (![scanner scanFloat:&t]) failFlag = YES;
1483 if (!failFlag)
1484 {
1485 _faces[j].s[i] = s / max_x;
1486 _faces[j].t[i] = t / max_y;
1487 }
1488 else
1489 failString = [NSString stringWithFormat:@"%@Failed to read s t coordinates for vertex[%d] in face[%d] in TEXTURES\n", failString, i, j];
1490 }
1491 }
1492 }
1493 }
1494 }
1495 else
1496 {
1497 failFlag = YES;
1498 failString = [failString stringByAppendingString:@"Failed to find TEXTURES data (will use placeholder material)\n"];
1499 materialKeys[0] = @"_oo_placeholder_material";
1500 materialCount = 1;
1501
1502 for (j = 0; j < faceCount; j++)
1503 {
1504 _faces[j].materialIndex = 0;
1505 }
1506 }
1507
1508 if ([scanner scanString:@"NAMES" intoString:NULL])
1509 {
1511 if (![scanner scanInt:(
int *)&
count])
1512 {
1513 failFlag = YES;
1514 failString = [failString stringByAppendingString:@"Expected count after NAMES\n"];
1515 }
1516 else
1517 {
1518 for (j = 0; j <
count; j++)
1519 {
1520 NSString *name =
nil;
1521 [scanner scanCharactersFromSet:whitespaceAndNewlineCharSet intoString:NULL];
1522 if (![scanner scanUpToCharactersFromSet:newlineCharSet intoString:&name])
1523 {
1524 failFlag = YES;
1525 failString = [failString stringByAppendingString:@"Expected file name\n"];
1526 }
1527 else
1528 {
1529 [self renameTexturesFrom:[NSString stringWithFormat:@"%u", j] to:name];
1530 }
1531 }
1532 }
1533 }
1534
1535 BOOL explicitTangents = NO;
1536
1537
1538 if ([scanner scanString:@"NORMALS" intoString:NULL])
1539 {
1541 if (![self allocateNormalBuffersWithCount:vertexCount])
1542 {
1544 return NO;
1545 }
1546
1547 for (j = 0; j < vertexCount; j++)
1548 {
1550 if (!failFlag)
1551 {
1552 if (![scanner scanFloat:&
x]) failFlag = YES;
1553 if (![scanner scanFloat:&
y]) failFlag = YES;
1554 if (![scanner scanFloat:&z]) failFlag = YES;
1555 if (!failFlag)
1556 {
1557 _normals[j] = vector_normal(make_vector(
x,
y, z));
1558 }
1559 else
1560 {
1561 failString = [NSString stringWithFormat:@"%@Failed to read a value for vertex[%d] in %@\n", failString, j, @"NORMALS"];
1562 }
1563 }
1564 }
1565
1566
1567 if ([scanner scanString:@"TANGENTS" intoString:NULL])
1568 {
1569 for (j = 0; j < vertexCount; j++)
1570 {
1572 if (!failFlag)
1573 {
1574 if (![scanner scanFloat:&
x]) failFlag = YES;
1575 if (![scanner scanFloat:&
y]) failFlag = YES;
1576 if (![scanner scanFloat:&z]) failFlag = YES;
1577 if (!failFlag)
1578 {
1579 _tangents[j] = vector_normal(make_vector(
x,
y, z));
1580 }
1581 else
1582 {
1583 failString = [NSString stringWithFormat:@"%@Failed to read a value for vertex[%d] in %@\n", failString, j, @"TANGENTS"];
1584 }
1585 }
1586 }
1587 }
1588 }
1589
1591
1593 {
1594 [self checkNormalsAndAdjustWinding];
1595 PROFILE(
@"finished checkNormalsAndAdjustWinding");
1596 }
1597 if (!explicitTangents)
1598 {
1599 [self generateFaceTangents];
1600 PROFILE(
@"finished generateFaceTangents");
1601 }
1602
1603
1605 {
1606 if (![self allocateNormalBuffersWithCount:vertexCount])
1607 {
1609 return NO;
1610 }
1611 [self calculateVertexNormalsAndTangentsWithFaceRefs:faceRefs];
1612 PROFILE(
@"finished calculateVertexNormalsAndTangents");
1613
1614 }
1616 {
1617 [self calculateVertexTangentsWithFaceRefs:faceRefs];
1618 PROFILE(
@"finished calculateVertexTangents");
1619 }
1620
1621
1622 if (
EXPECT(_cacheWriteable))
1623 {
1626 }
1627
1628 if (failFlag)
1629 {
1630 OOLog(
@"mesh.error",
@"%@ ..... from %@ %@", failString,
filename, (using_preloaded)?
@"(from preloaded data)" :
@"(from file)");
1631 }
1632 }
1633
1634 [self calculateBoundingVolumes];
1635 PROFILE(
@"finished calculateBoundingVolumes");
1636
1637
1639 PROFILE(
@"finished setUpVertexArrays");
1640
1641 return YES;
1642
1644}
void OOStandardsError(NSString *message)
#define OOLogWARN(class, format,...)
NSString *const kOOLogAllocationFailure
static void VFRAddFace(VertexFaceRef *vfr, NSUInteger index)
static BOOL IsLegacyNormalMode(OOMeshNormalMode mode)
static NSString *const kOOLogMeshTooManyMaterials
static NSString *const kOOLogMeshDataNotFound
struct VertexFaceRef VertexFaceRef
static BOOL IsPerVertexNormalMode(OOMeshNormalMode mode)
void setMeshData:forName:(NSDictionary *inData,[forName] NSString *inShipName)
NSDictionary * meshDataForName:(NSString *inShipName)
NSString * stringFromFilesNamed:inFolder:cache:(NSString *fileName,[inFolder] NSString *folderName,[cache] BOOL useCache)
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque