diff --git a/GLLara.xcodeproj/project.pbxproj b/GLLara.xcodeproj/project.pbxproj index 0cd7f7ed..2f8cd2f6 100644 --- a/GLLara.xcodeproj/project.pbxproj +++ b/GLLara.xcodeproj/project.pbxproj @@ -230,6 +230,7 @@ 526E0FAC1C169E3500F198BF /* testStaticTRUDiffuseLightmap.png in Resources */ = {isa = PBXBuildFile; fileRef = 526E0F9B1C169E3500F198BF /* testStaticTRUDiffuseLightmap.png */; }; 5272709C2BE77A7D00EE52B5 /* GLLTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5272709A2BE600C300EE52B5 /* GLLTexture.swift */; }; 527270A32BE7E0F100EE52B5 /* GLLItem+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527270A12BE7E0F100EE52B5 /* GLLItem+Extensions.swift */; }; + 527270A52BE8064100EE52B5 /* GLLDataReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52C3AD8D29A2241E002EC334 /* GLLDataReader.swift */; }; 5274446427FCC9C100E5A3FD /* GLLModelMesh.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5274446327FCC9C100E5A3FD /* GLLModelMesh.swift */; }; 5274446627FD64F000E5A3FD /* GLLModelMeshObj.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5274446527FD64F000E5A3FD /* GLLModelMeshObj.swift */; }; 5274446827FD6F7F00E5A3FD /* GLLVertexAttribAccessorSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5274446727FD6F7F00E5A3FD /* GLLVertexAttribAccessorSet.swift */; }; @@ -252,12 +253,12 @@ 528934EB16A332BD00F05312 /* GLLMeshListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 528934EA16A332BC00F05312 /* GLLMeshListController.m */; }; 528934EE16A3593500F05312 /* GLLBoneListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 528934ED16A3593400F05312 /* GLLBoneListController.m */; }; 5291DB9415FBF7BE00ECDBCA /* GLLAmbientLight.m in Sources */ = {isa = PBXBuildFile; fileRef = 5291DB9315FBF7BD00ECDBCA /* GLLAmbientLight.m */; }; - 529692CC15F1568200DF2FA3 /* TRInDataStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 529692C915F1568200DF2FA3 /* TRInDataStream.m */; }; + 529692CC15F1568200DF2FA3 /* TRInDataStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 529692C915F1568200DF2FA3 /* TRInDataStream.swift */; }; 529692CD15F1568200DF2FA3 /* TROutDataStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 529692CB15F1568200DF2FA3 /* TROutDataStream.m */; }; 529692D115F2374F00DF2FA3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 529692D015F2374F00DF2FA3 /* libz.dylib */; }; 529692DA15F2625200DF2FA3 /* GLLItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 529692D915F2625200DF2FA3 /* GLLItem.m */; }; 529692DD15F2759400DF2FA3 /* GLLItemBone.m in Sources */ = {isa = PBXBuildFile; fileRef = 529692DC15F2759400DF2FA3 /* GLLItemBone.m */; }; - 529693F515F2B58B00DF2FA3 /* GLLASCIIScanner.m in Sources */ = {isa = PBXBuildFile; fileRef = 529693F415F2B58B00DF2FA3 /* GLLASCIIScanner.m */; }; + 529693F515F2B58B00DF2FA3 /* GLLASCIIScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 529693F415F2B58B00DF2FA3 /* GLLASCIIScanner.swift */; }; 529693F815F2D02900DF2FA3 /* xnaLaraDefault.modelparams.plist in Resources */ = {isa = PBXBuildFile; fileRef = 529693F715F2D02900DF2FA3 /* xnaLaraDefault.modelparams.plist */; }; 529693FA15F36DDB00DF2FA3 /* lara.modelparams.plist in Resources */ = {isa = PBXBuildFile; fileRef = 529693F915F36DDB00DF2FA3 /* lara.modelparams.plist */; }; 529693FE15F37AAF00DF2FA3 /* lara_dlc_bikini_blue.modelparams.plist in Resources */ = {isa = PBXBuildFile; fileRef = 529693FD15F37AAF00DF2FA3 /* lara_dlc_bikini_blue.modelparams.plist */; }; @@ -704,8 +705,7 @@ 5291DB7F15FB711900ECDBCA /* Model Parameters (english).md */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Model Parameters (english).md"; sourceTree = ""; }; 5291DB9215FBF7BC00ECDBCA /* GLLAmbientLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLLAmbientLight.h; sourceTree = ""; }; 5291DB9315FBF7BD00ECDBCA /* GLLAmbientLight.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLLAmbientLight.m; sourceTree = ""; }; - 529692C815F1568200DF2FA3 /* TRInDataStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRInDataStream.h; sourceTree = ""; }; - 529692C915F1568200DF2FA3 /* TRInDataStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TRInDataStream.m; sourceTree = ""; }; + 529692C915F1568200DF2FA3 /* TRInDataStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TRInDataStream.swift; sourceTree = ""; }; 529692CA15F1568200DF2FA3 /* TROutDataStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TROutDataStream.h; sourceTree = ""; }; 529692CB15F1568200DF2FA3 /* TROutDataStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TROutDataStream.m; sourceTree = ""; }; 529692D015F2374F00DF2FA3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; @@ -716,8 +716,7 @@ 529692DC15F2759400DF2FA3 /* GLLItemBone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLLItemBone.m; sourceTree = ""; }; 529692DF15F27D5900DF2FA3 /* Source Code Overview.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Source Code Overview.md"; sourceTree = ""; }; 529692E515F289EB00DF2FA3 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; - 529693F315F2B58A00DF2FA3 /* GLLASCIIScanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLLASCIIScanner.h; sourceTree = ""; }; - 529693F415F2B58B00DF2FA3 /* GLLASCIIScanner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLLASCIIScanner.m; sourceTree = ""; }; + 529693F415F2B58B00DF2FA3 /* GLLASCIIScanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GLLASCIIScanner.swift; sourceTree = ""; }; 529693F715F2D02900DF2FA3 /* xnaLaraDefault.modelparams.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = xnaLaraDefault.modelparams.plist; sourceTree = ""; }; 529693F915F36DDB00DF2FA3 /* lara.modelparams.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = lara.modelparams.plist; sourceTree = ""; }; 529693FB15F3781100DF2FA3 /* Render parameters.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Render parameters.md"; sourceTree = ""; }; @@ -769,7 +768,7 @@ 52BB21D915FCF02200937450 /* GLLCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLLCamera.h; sourceTree = ""; }; 52BB21DA15FCF02200937450 /* GLLCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLLCamera.m; sourceTree = ""; }; 52C3AD8B29A13DEB002EC334 /* WillinglyBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WillinglyBlock.swift; sourceTree = ""; }; - 52C3AD8D29A2241E002EC334 /* GLLDataReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GLLDataReader.h; sourceTree = ""; }; + 52C3AD8D29A2241E002EC334 /* GLLDataReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLLDataReader.swift; sourceTree = ""; }; 52C3AD8E29A224E2002EC334 /* GLLModelBone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLLModelBone.swift; sourceTree = ""; }; 52C516FE2871998C000EB8C2 /* GLLPipelineStateInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLLPipelineStateInformation.swift; sourceTree = ""; }; 52C517002871CBBB000EB8C2 /* baseData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = baseData.swift; sourceTree = ""; }; @@ -1090,8 +1089,7 @@ 529692CF15F1568700DF2FA3 /* From TR Poser */, 525ACD5215F0F1A700534E7D /* Supporting Files */, 52329F4816C1D63300338A0A /* Drawing infrastructure */, - 529693F315F2B58A00DF2FA3 /* GLLASCIIScanner.h */, - 529693F415F2B58B00DF2FA3 /* GLLASCIIScanner.m */, + 529693F415F2B58B00DF2FA3 /* GLLASCIIScanner.swift */, 52BB217B15F972AB00937450 /* GLLSceneModel.xcdatamodeld */, 52653D8016BAB729001D802F /* GLLPoseExporter.swift */, ); @@ -1114,7 +1112,7 @@ 52232EAD1EFC57D4007FE9AD /* XYAlignedSquare.obj */, 524D3AB628CE151500B50391 /* GLLColorValueTransformer.swift */, 52C3AD8B29A13DEB002EC334 /* WillinglyBlock.swift */, - 52C3AD8D29A2241E002EC334 /* GLLDataReader.h */, + 52C3AD8D29A2241E002EC334 /* GLLDataReader.swift */, ); name = "Supporting Files"; sourceTree = ""; @@ -1168,8 +1166,7 @@ 529692CF15F1568700DF2FA3 /* From TR Poser */ = { isa = PBXGroup; children = ( - 529692C815F1568200DF2FA3 /* TRInDataStream.h */, - 529692C915F1568200DF2FA3 /* TRInDataStream.m */, + 529692C915F1568200DF2FA3 /* TRInDataStream.swift */, 529692CA15F1568200DF2FA3 /* TROutDataStream.h */, 529692CB15F1568200DF2FA3 /* TROutDataStream.m */, ); @@ -1861,14 +1858,14 @@ 52D8DDEC2621D56F0006F0E5 /* GLLRenderParameterDescription.swift in Sources */, 525ACD8415F0F33700534E7D /* GLLModel.swift in Sources */, 5274448428031CA900E5A3FD /* GLLMeshDrawData.swift in Sources */, - 529692CC15F1568200DF2FA3 /* TRInDataStream.m in Sources */, + 529692CC15F1568200DF2FA3 /* TRInDataStream.swift in Sources */, 529692CD15F1568200DF2FA3 /* TROutDataStream.m in Sources */, 5274446427FCC9C100E5A3FD /* GLLModelMesh.swift in Sources */, 52D8DDBE261E06F40006F0E5 /* GLLModelGltf.swift in Sources */, 529692DA15F2625200DF2FA3 /* GLLItem.m in Sources */, 529692DD15F2759400DF2FA3 /* GLLItemBone.m in Sources */, 523BBB052880BCB300B2D52E /* GLLGameControllerManager.swift in Sources */, - 529693F515F2B58B00DF2FA3 /* GLLASCIIScanner.m in Sources */, + 529693F515F2B58B00DF2FA3 /* GLLASCIIScanner.swift in Sources */, 5274448B280606A200E5A3FD /* XnaLaraShader.metal in Sources */, 521102E7288DBF72001BE4BC /* HUD.swift in Sources */, 52C517012871CBBB000EB8C2 /* baseData.swift in Sources */, @@ -1920,6 +1917,7 @@ 52B6C5392BE2EB26005E53CE /* MtlFile.swift in Sources */, 526AB31C1609C7C300940A74 /* GLLItem+OBJExport.swift in Sources */, 525BF29D287A0AE200E30D48 /* GLLView.swift in Sources */, + 527270A52BE8064100EE52B5 /* GLLDataReader.swift in Sources */, 52CDFEE42875B46700BC4298 /* GLLSceneDrawer.swift in Sources */, 52301E352087E71400B3E331 /* GLLOptionalPartViewController.m in Sources */, 52B6C51F2BE28DE7005E53CE /* GLLItemDragDestination.swift in Sources */, diff --git a/GLLara/GLLASCIIScanner.h b/GLLara/GLLASCIIScanner.h deleted file mode 100644 index 2445a3c8..00000000 --- a/GLLara/GLLASCIIScanner.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// GLLASCIIScanner.h -// GLLara -// -// Created by Torsten Kammer on 01.09.12. -// Copyright (c) 2012 Torsten Kammer. All rights reserved. -// - -#import - -#import "GLLDataReader.h" - -/*! - * @abstract Reader for the .mesh.ascii format. - * @discussion It was deliberately designed to have the same interface as the - * TRInDataStream. Thus, it can read integers in different widths, although - * parsing them from an ASCII file is always the same work. - */ -@interface GLLASCIIScanner : NSObject - -- (id)initWithString:(NSString *)string; - -- (uint32_t)readUint32; -- (uint16_t)readUint16; -- (uint8_t)readUint8; -- (Float32)readFloat32; - -- (NSString *)readPascalString; - -// Tries to scan a newline; returns whether that succeeded. If not, newlines are skipped. -- (BOOL)hasNewline; - -@property (nonatomic, readonly) BOOL isValid; - -@end diff --git a/GLLara/GLLASCIIScanner.m b/GLLara/GLLASCIIScanner.m deleted file mode 100644 index 4093fac3..00000000 --- a/GLLara/GLLASCIIScanner.m +++ /dev/null @@ -1,139 +0,0 @@ -// -// GLLASCIIScanner.m -// GLLara -// -// Created by Torsten Kammer on 01.09.12. -// Copyright (c) 2012 Torsten Kammer. All rights reserved. -// - -#import "GLLASCIIScanner.h" - -@interface GLLASCIIScanner () -{ - NSScanner *scanner; -} - -- (NSInteger)_readInteger; -- (void)_skipComments; - -@property (nonatomic, readwrite) BOOL isValid; - -@end - -@implementation GLLASCIIScanner - -- (id)initWithString:(NSString *)string; -{ - if (!(self = [super init])) return nil; - - scanner = [NSScanner scannerWithString:string]; - - // Use american english at all times, because that is the number format used. - scanner.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; - self.isValid = YES; - - return self; -} - -- (uint32_t)readUint32; -{ - return (uint32_t) [self _readInteger]; -} -- (uint16_t)readUint16; -{ - return (uint16_t) [self _readInteger]; -} -- (uint8_t)readUint8; -{ - return (uint8_t) [self _readInteger]; -} -- (Float32)readFloat32; -{ - [self _skipComments]; - if (scanner.isAtEnd) - { - self.isValid = NO; - return 0.0f; - } - - float result; - if (![scanner scanFloat:&result]) - { - if ([scanner scanString:@"NaN" intoString:NULL]) { - // Haha, very funny. Idiots. - return nanf(""); - } else { - self.isValid = NO; - return 0.0f; - } - } - - return result; -} - -- (NSString *)readPascalString; -{ - [self _skipComments]; - if (scanner.isAtEnd) - { - self.isValid = NO; - return nil; - } - - [scanner scanCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:NULL]; - - NSString *result; - if (![scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&result]) - { - self.isValid = NO; - return nil; - } - - return result; -} - - -- (NSInteger)_readInteger; -{ - [self _skipComments]; - if (scanner.isAtEnd) - { - self.isValid = NO; - return 0; - } - - NSInteger result; - if (![scanner scanInteger:&result]) - { - self.isValid = NO; - return 0; - } - - return result; -} - -- (BOOL)hasNewline; -{ - // Skip only whitespace, not newline, because the scanner won't recognize the newline otherwise - scanner.charactersToBeSkipped = [NSCharacterSet whitespaceCharacterSet]; - if ([scanner scanString:@"#" intoString:NULL]) { - // Has a comment, which ends a line. - scanner.charactersToBeSkipped = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:NULL]; - return YES; - } else if ([scanner scanCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:NULL]) { - // Has newline, which obviously ends a line. - scanner.charactersToBeSkipped = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - return YES; - } - scanner.charactersToBeSkipped = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - return NO; -} - -- (void)_skipComments; -{ - while ([scanner scanString:@"#" intoString:NULL]) - [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:NULL]; -} - -@end diff --git a/GLLara/GLLASCIIScanner.swift b/GLLara/GLLASCIIScanner.swift new file mode 100644 index 00000000..42d982d4 --- /dev/null +++ b/GLLara/GLLASCIIScanner.swift @@ -0,0 +1,109 @@ +// +// GLLASCIIScanner.m +// GLLara +// +// Created by Torsten Kammer on 01.09.12. +// Copyright (c) 2012 Torsten Kammer. All rights reserved. +// +import Foundation + +/*! + * @abstract Reader for the .mesh.ascii format. + * @discussion It was deliberately designed to have the same interface as the + * TRInDataStream. Thus, it can read integers in different widths, although + * parsing them from an ASCII file is always the same work. + */ +class GLLASCIIScanner: GLLDataReader { + init(string: String) { + scanner = Scanner(string: string) + // Use american english at all times, because that is the number format used. + scanner.locale = Locale(identifier: "en_US") + } + + private let scanner: Scanner + + func readUint32() -> UInt32 { + return UInt32(readInteger()) + } + + func readUint16() -> UInt16 { + return UInt16(readInteger()) + } + + func readUint8() -> UInt8 { + return UInt8(readInteger()) + } + + func readFloat32() -> Float32 { + skipComments() + if scanner.isAtEnd { + isValid = false + return 0.0 + } + + guard let result = scanner.scanFloat() else { + if (scanner.scanString("NaN") != nil) { + // Haha, very funny. Idiots. + return Float.nan + } else { + isValid = false + return 0.0 + } + } + return result + } + + func readPascalString() -> String { + skipComments() + if scanner.isAtEnd { + isValid = false + return "" + } + + _ = scanner.scanCharacters(from: CharacterSet.whitespacesAndNewlines) + guard let result = scanner.scanUpToCharacters(from: CharacterSet.newlines) else { + isValid = false + return "" + } + return result + } + + func hasNewline() -> Bool { + // Skip only whitespace, not newline, because the scanner won't recognize the newline otherwise + scanner.charactersToBeSkipped = CharacterSet.whitespaces + if scanner.scanString("#") != nil { + // Has a comment, which ends a line. + _ = scanner.scanUpToCharacters(from: CharacterSet.newlines) + scanner.charactersToBeSkipped = CharacterSet.whitespacesAndNewlines + return true + } else if scanner.scanCharacters(from: CharacterSet.newlines) != nil { + // Has newline, which obviously ends a line. + scanner.charactersToBeSkipped = CharacterSet.whitespacesAndNewlines + return true + } + scanner.charactersToBeSkipped = CharacterSet.whitespacesAndNewlines + return false + } + + var isValid: Bool = true + + private func skipComments() { + while scanner.scanString("#") != nil { + _ = scanner.scanUpToCharacters(from: CharacterSet.newlines) + } + } + + private func readInteger() -> Int { + skipComments() + if scanner.isAtEnd { + isValid = false + return 0 + } + + guard let result = scanner.scanInt() else { + isValid = false + return 0 + } + return result + } +} diff --git a/GLLara/GLLDataReader.h b/GLLara/GLLDataReader.h deleted file mode 100644 index 5157c645..00000000 --- a/GLLara/GLLDataReader.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// GLLDataReader.h -// GLLara -// -// Created by Torsten Kammer on 19.02.23. -// Copyright © 2023 Torsten Kammer. All rights reserved. -// - -#ifndef GLLDataReader_h -#define GLLDataReader_h - -#import - -@protocol GLLDataReader - -- (uint32_t)readUint32; -- (uint16_t)readUint16; -- (uint8_t)readUint8; -- (Float32)readFloat32; - -- (NSString *)readPascalString; - -@property (nonatomic, readonly) BOOL isValid; - -@end - -#endif /* GLLDataReader_h */ diff --git a/GLLara/GLLDataReader.swift b/GLLara/GLLDataReader.swift new file mode 100644 index 00000000..cf0c7234 --- /dev/null +++ b/GLLara/GLLDataReader.swift @@ -0,0 +1,17 @@ +// +// GLLDataReader.swift +// GLLara +// +// Created by Torsten Kammer on 19.02.23. +// Copyright © 2023 Torsten Kammer. All rights reserved. +// + +protocol GLLDataReader { + func readUint32() -> UInt32 + func readUint16() -> UInt16 + func readUint8() -> UInt8 + func readFloat32() -> Float32 + + func readPascalString() -> String + var isValid: Bool { get } +} diff --git a/GLLara/GLLItem.m b/GLLara/GLLItem.m index 92eb2232..faf18354 100644 --- a/GLLara/GLLItem.m +++ b/GLLara/GLLItem.m @@ -11,7 +11,6 @@ #import "GLLItemBone.h" #import "GLLItemMesh.h" #import "simd_matrix.h" -#import "TRInDataStream.h" #import "TROutDataStream.h" #import "NSArray+Map.h" diff --git a/GLLara/GLLItemBone.m b/GLLara/GLLItemBone.m index 7a11c9a4..ea25e067 100644 --- a/GLLara/GLLItemBone.m +++ b/GLLara/GLLItemBone.m @@ -10,7 +10,6 @@ #import "GLLItem.h" #import "simd_matrix.h" -#import "TRInDataStream.h" #import "TROutDataStream.h" #import "GLLara-Swift.h" diff --git a/GLLara/GLLModelMesh.swift b/GLLara/GLLModelMesh.swift index 3ec06b05..71141d5d 100644 --- a/GLLara/GLLModelMesh.swift +++ b/GLLara/GLLModelMesh.swift @@ -37,7 +37,7 @@ import simd for i in 0.. -#import "GLLASCIIScanner.h" #import "GLLAmbientLight.h" #import "GLLCamera.h" #import "GLLConnexionManager.h" @@ -25,5 +24,4 @@ #import "HUDShared.h" #import "NSColor+Color32Bit.h" #import "simd_matrix.h" -#import "TRInDataStream.h" #import "TROutDataStream.h" diff --git a/GLLara/MtlFile.swift b/GLLara/MtlFile.swift index faf4fdf0..bdebe9dd 100644 --- a/GLLara/MtlFile.swift +++ b/GLLara/MtlFile.swift @@ -25,6 +25,8 @@ class MtlFile { init(from location: URL) throws { let contents = try String(contentsOf: location) let scanner = Scanner(string: contents) + // Use american english at all times, because that is the number format used. + scanner.locale = Locale(identifier: "en_US") var hasFirstMaterial = false var currentMaterial = Material() diff --git a/GLLara/TRInDataStream.h b/GLLara/TRInDataStream.h deleted file mode 100644 index e9a30358..00000000 --- a/GLLara/TRInDataStream.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// TRDataStream.h -// TR Poser -// -// Created by Torsten Kammer on 13.08.12. -// Copyright (c) 2012 Torsten Kammer. All rights reserved. -// - -#import - -#import "GLLDataReader.h" - -@interface TRInDataStream : NSObject - -- (id)initWithData:(NSData *)data; - -- (uint32_t)readUint32; -- (uint16_t)readUint16; -- (uint8_t)readUint8; -- (Float32)readFloat32; -- (int32_t)readInt32; -- (int16_t)readInt16; -- (int8_t)readInt8; - -- (void)readUint32Array:(uint32_t *)array count:(NSUInteger)count; -- (void)readUint16Array:(uint16_t *)array count:(NSUInteger)count; -- (void)readUint8Array:(uint8_t *)array count:(NSUInteger)count; -- (void)readFloat32Array:(Float32 *)array count:(NSUInteger)count; - -- (NSString *)readPascalString; - -- (void)skipBytes:(NSUInteger)count; -- (void)skipField16:(NSUInteger)elementWidth; -- (void)skipField32:(NSUInteger)elementWidth; - -- (TRInDataStream *)decompressStreamCompressedLength:(NSUInteger)actualBytes uncompressedLength:(NSUInteger)originalBytes error:(NSError *__autoreleasing*)error; -- (TRInDataStream *)substreamWithLength:(NSUInteger)bytes; -- (NSData *)dataWithLength:(NSInteger)bytes; - -@property (nonatomic, assign) NSUInteger position; -@property (nonatomic, copy, readonly) NSData *levelData; -@property (nonatomic, assign, readonly) BOOL isAtEnd; -@property (nonatomic, assign, readonly) BOOL isValid; - -@end diff --git a/GLLara/TRInDataStream.m b/GLLara/TRInDataStream.m deleted file mode 100644 index ddc2c20c..00000000 --- a/GLLara/TRInDataStream.m +++ /dev/null @@ -1,220 +0,0 @@ -// -// TRDataStream.m -// TR Poser -// -// Created by Torsten Kammer on 13.08.12. -// Copyright (c) 2012 Torsten Kammer. All rights reserved. -// - -#import "TRInDataStream.h" - -#import - -@interface TRInDataStream () - -@property (nonatomic, copy, readwrite) NSData *levelData; - -@end - -@implementation TRInDataStream - -- (id)initWithData:(NSData *)data; -{ - if (!(self = [super init])) return nil; - - assert(data != nil); - - _levelData = data; - _position = 0; - - return self; -} - -- (uint32_t)readUint32; -{ - uint32_t result = 0; - [self readUint32Array:&result count:1]; - return result; -} -- (uint16_t)readUint16; -{ - uint16_t result = 0; - [self readUint16Array:&result count:1]; - return result; -} -- (uint8_t)readUint8; -{ - uint8_t result = 0; - [self readUint8Array:&result count:1]; - return result; -} -- (Float32)readFloat32; -{ - Float32 result = 0.0f; - [self readFloat32Array:&result count:1]; - return result; -} -- (int32_t)readInt32; -{ - int32_t result = 0; - [self readUint32Array:(uint32_t *) &result count:1]; - return result; -} - -- (int16_t)readInt16; -{ - int16_t result = 0; - [self readUint16Array:(uint16_t *) &result count:1]; - return result; -} - -- (int8_t)readInt8; -{ - int8_t result = 0; - [self readUint8Array:(uint8_t *) &result count:1]; - return result; -} - -- (void)readUint32Array:(uint32_t *)array count:(NSUInteger)count; -{ - [self readUint8Array:(uint8_t *)array count:4*count]; -} - -- (void)readUint16Array:(uint16_t *)array count:(NSUInteger)count; -{ - [self readUint8Array:(uint8_t *)array count:2*count]; -} - -- (void)readUint8Array:(uint8_t *)array count:(NSUInteger)count; -{ - if (self.isValid && _position + count <= self.levelData.length) - [_levelData getBytes:array range:NSMakeRange(_position, count)]; - else - bzero(array, count); - - _position += count; -} - -- (void)readFloat32Array:(Float32 *)array count:(NSUInteger)count; -{ - uint32_t *uint32array = (uint32_t *) array; - [self readUint32Array:uint32array count:count]; -} - -- (NSString *)readPascalString; -{ - NSUInteger length = 0; - uint8_t lengthByte = 0; - NSUInteger shiftAmount = 0; - do { - lengthByte = [self readUint8]; - length += (lengthByte & 0x7F) << (7*shiftAmount); - shiftAmount += 1; - } while (lengthByte & 0x80); - if (!self.isValid) return nil; - if (length == 0) return @""; - - uint8_t buffer[length]; - [self readUint8Array:buffer count:length]; - if (!self.isValid) return nil; - return [[NSString alloc] initWithBytes:buffer length:length encoding:NSUTF8StringEncoding]; -} - -- (void)skipBytes:(NSUInteger)count; -{ - _position += count; -} -- (void)skipField16:(NSUInteger)elementWidth; -{ - NSUInteger fieldLength = (NSUInteger) [self readUint16]; - - [self skipBytes:fieldLength * elementWidth]; -} -- (void)skipField32:(NSUInteger)elementWidth; -{ - NSUInteger fieldLength = (NSUInteger) [self readUint32]; - - [self skipBytes:fieldLength * elementWidth]; -} - -- (TRInDataStream *)decompressStreamCompressedLength:(NSUInteger)actualBytes uncompressedLength:(NSUInteger)originalBytes error:(NSError *__autoreleasing*)error; -{ - if (!self.isValid) return nil; - if (_position + actualBytes> _levelData.length) - { - _position += actualBytes; - return nil; - } - - uint8_t *uncompressedData = malloc(originalBytes); - uint8_t *compressedData = malloc(actualBytes); - [self readUint8Array:compressedData count:actualBytes]; - - NSUInteger uncompressedLength = originalBytes; - - int result = uncompress(uncompressedData, (uLongf *) &uncompressedLength, compressedData, actualBytes); - free(compressedData); - if (result != Z_OK) - { - if (error) - *error = [NSError errorWithDomain:@"TRInDataStream" code:result userInfo:@{ - NSLocalizedDescriptionKey : NSLocalizedString(@"Could not decompress part of the data.", @"uncompress failed"), - NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString(@"The compressed parts of the file could not be processed. The file may be damaged.", @"uncompress failed") - }]; - free(uncompressedData); - return nil; - } - if (uncompressedLength < originalBytes) - { - if (error) - *error = [NSError errorWithDomain:@"TRInDataStream" code:result userInfo:@{ - NSLocalizedDescriptionKey : NSLocalizedString(@"Could not decompress part of the data.", @"uncompress failed"), - NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString(@"A piece of compressed data was shorter than it should have been. The file may be damaged", @"uncompress failed") - }]; - free(uncompressedData); - return nil; - } - - NSData *data = [NSData dataWithBytesNoCopy:uncompressedData length:uncompressedLength freeWhenDone:YES]; - id resultLevelData = [[[self class] alloc] initWithData:data]; - - return resultLevelData; -} -- (TRInDataStream *)substreamWithLength:(NSUInteger)count; -{ - if (count == 0) return [[TRInDataStream alloc] initWithData:[NSData data]]; - if (!self.isValid) return nil; - - if (_position + count > _levelData.length) - { - _position += count; - return nil; - } - - NSData *underlyingData = [_levelData subdataWithRange:NSMakeRange(_position, count)]; - TRInDataStream *result = [[[self class] alloc] initWithData:underlyingData]; - _position += count; - return result; -} - -- (NSData *)dataWithLength:(NSInteger)count -{ - if (count == 0) return [NSData data]; - if (!self.isValid) return nil; - - NSData *underlyingData = (_position + count <= _levelData.length) ? [_levelData subdataWithRange:NSMakeRange(_position, count)] : nil; - _position += count; - - return underlyingData; -} - -- (BOOL)isAtEnd; -{ - return _position >= _levelData.length; -} -- (BOOL)isValid -{ - return _position <= _levelData.length; -} - -@end diff --git a/GLLara/TRInDataStream.swift b/GLLara/TRInDataStream.swift new file mode 100644 index 00000000..0511a5c4 --- /dev/null +++ b/GLLara/TRInDataStream.swift @@ -0,0 +1,159 @@ +// +// TRDataStream.m +// TR Poser +// +// Created by Torsten Kammer on 13.08.12. +// Copyright (c) 2012 Torsten Kammer. All rights reserved. +// +import Foundation +import zlib + +class TRInDataStream: GLLDataReader { + var levelData: Data + var position: Int = 0 + + init(data: Data) { + levelData = data + } + + func readUint32() -> UInt32 { + return readInts(count: 1, type: UInt32.self)[0] + } + + func readUint16() -> UInt16 { + return readInts(count: 1, type: UInt16.self)[0] + } + + func readUint8() -> UInt8 { + return readInts(count: 1, type: UInt8.self)[0] + } + + func readFloat32() -> Float32 { + return readFloats(count: 1, type: Float32.self)[0] + } + + func readInt32() -> Int32 { + return readInts(count: 1, type: Int32.self)[0] + } + + func readInt16() -> Int16 { + return readInts(count: 1, type: Int16.self)[0] + } + + func readInt8() -> Int8 { + return readInts(count: 1, type: Int8.self)[0] + } + + func readInts(count: Int, type: T.Type) -> [T] { + // This only works if input data has same endianness as CPU + // Luckily (sadly, but lucky in this case), all big endian CPUs have died out ages ago. + var result = Array(repeating: 0, count: count) + readItems(count: count, into: &result) + return result + } + + func readFloats(count: Int, type: T.Type) -> [T] { + // This only works if input data has same endianness as CPU + // Luckily (sadly, but lucky in this case), all big endian CPUs have died out ages ago. + var result = Array(repeating: 0, count: count) + readItems(count: count, into: &result) + return result + } + + func readItems(count: Int, into result: inout [T]) { + if isAtEnd { + return + } + let rangeEnd = min(levelData.count, position + count * MemoryLayout.stride) + _ = result.withUnsafeMutableBytes { output in + levelData.copyBytes(to: output, from: position ..< rangeEnd) + } + position = rangeEnd + } + + func skip(bytes: Int) { + position += bytes + } + + func skipField16(elementWidth: Int) { + let count = readUint16() + skip(bytes: Int(count) * elementWidth) + } + + func skipField32(elementWidth: Int) { + let count = readUint16() + skip(bytes: Int(count) * elementWidth) + } + + func data(length: Int) -> Data? { + if isAtEnd || position + length > levelData.count { + return nil + } + let data = levelData.subdata(in: position ..< position + length) + position += length + return data + } + + func substream(length: Int) -> TRInDataStream? { + guard let data = data(length: length) else { + return nil + } + return TRInDataStream(data: data) + } + + var isAtEnd: Bool { + return position >= levelData.count + } + + var isValid: Bool { + return position <= levelData.count + } + + func readPascalString() -> String { + var length = 0 + var lengthByte = 0 + var bytesRead = 0 + repeat { + lengthByte = Int(readUint8()) + length += (lengthByte & 0x7F) << (7*bytesRead) + bytesRead += 1 + } while isValid && (lengthByte & 0x80 != 0) + if !isValid || length == 0 { + return "" + } + + let result = readInts(count: length, type: UInt8.self) + return String(bytes: result, encoding: .utf8) ?? "" + } + + func decompressStream(compressedLength: Int, uncompressedLength: Int) throws -> TRInDataStream? { + if position + compressedLength > levelData.count { + position += compressedLength + return nil + } + + var uncompressedData = Data(count: uncompressedLength) + var actualUncompressedLength: uLongf = uLongf(uncompressedLength) + + let uncompressResult = levelData.withUnsafeBytes { (levelDataBytes: UnsafeRawBufferPointer) in + uncompressedData.withUnsafeMutableBytes { (uncompressedBytes: UnsafeMutableRawBufferPointer) in + uncompress(uncompressedBytes.bindMemory(to: UInt8.self).baseAddress, &actualUncompressedLength, levelDataBytes.bindMemory(to: UInt8.self).baseAddress!.advanced(by: position), uLong(compressedLength)) + } + } + if uncompressResult != Z_OK { + throw NSError(domain: "TRInDataStream", code: Int(uncompressResult), userInfo: [ + NSLocalizedDescriptionKey : NSLocalizedString("Could not decompress part of the data.", comment: "uncompress failed"), + NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString("The compressed parts of the file could not be processed. The file may be damaged.", comment: "uncompress failed") + ]) + } + if actualUncompressedLength < uncompressedLength { + throw NSError(domain: "TRInDataStream", code: Int(uncompressResult), userInfo: [ + NSLocalizedDescriptionKey : NSLocalizedString("Could not decompress part of the data.", comment: "uncompress failed"), + NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString("A piece of compressed data was shorter than it should have been. The file may be damaged.", comment: "uncompress failed") + ]) + } + + position += compressedLength + return TRInDataStream(data: uncompressedData) + } +}