ASTC experiment

This commit is contained in:
Peter 2019-06-26 15:26:19 +03:00
parent 0fd1a50d7f
commit b4e7528e3a
61 changed files with 6508 additions and 2591 deletions

View File

@ -280,6 +280,7 @@
<key>NSUserActivityTypes</key> <key>NSUserActivityTypes</key>
<array> <array>
<string>INSendMessageIntent</string> <string>INSendMessageIntent</string>
<string>RemindAboutChatIntent</string>
</array> </array>
<key>UIAppFonts</key> <key>UIAppFonts</key>
<array> <array>

View File

@ -4454,3 +4454,7 @@ Any member of this group will be able to see messages in the channel.";
"CreateGroup.ErrorLocatedGroupsTooMuch" = "Sorry, you have too many location-based groups already. Please delete one of your existing ones first."; "CreateGroup.ErrorLocatedGroupsTooMuch" = "Sorry, you have too many location-based groups already. Please delete one of your existing ones first.";
"GroupInfo.LabelOwner" = "owner"; "GroupInfo.LabelOwner" = "owner";
"Activity.RemindAboutGroup" = "Send message to %@";
"Activity.RemindAboutUser" = "Send message to %@";
"Activity.RemindAboutChannel" = "Read %@";

View File

@ -149,6 +149,8 @@ func experimentalConvertCompressedLottieToCombinedMp4(data: Data, size: CGSize,
let appendStartTime = CACurrentMediaTime() let appendStartTime = CACurrentMediaTime()
//compressRGBAToBC1(currentFrameData.assumingMemoryBound(to: UInt8.self), Int32(size.width), Int32(size.height), yuvaFrameData.assumingMemoryBound(to: UInt8.self))
encodeRGBAToYUVA(yuvaFrameData.assumingMemoryBound(to: UInt8.self), currentFrameData.assumingMemoryBound(to: UInt8.self), Int32(size.width), Int32(size.height)) encodeRGBAToYUVA(yuvaFrameData.assumingMemoryBound(to: UInt8.self), currentFrameData.assumingMemoryBound(to: UInt8.self), Int32(size.width), Int32(size.height))
//decodeYUVAToRGBA(yuvaFrameData.assumingMemoryBound(to: UInt8.self), singleContext.bytes.assumingMemoryBound(to: UInt8.self), Int32(size.width), Int32(size.height)) //decodeYUVAToRGBA(yuvaFrameData.assumingMemoryBound(to: UInt8.self), singleContext.bytes.assumingMemoryBound(to: UInt8.self), Int32(size.width), Int32(size.height))

View File

@ -196,6 +196,8 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
private var historyNavigationStack = ChatHistoryNavigationStack() private var historyNavigationStack = ChatHistoryNavigationStack()
let canReadHistory = ValuePromise<Bool>(true, ignoreRepeated: true) let canReadHistory = ValuePromise<Bool>(true, ignoreRepeated: true)
private var reminderActivity: NSUserActivity?
private var isReminderActivityEnabled: Bool = false
private var canReadHistoryValue = false private var canReadHistoryValue = false
private var canReadHistoryDisposable: Disposable? private var canReadHistoryDisposable: Disposable?
@ -1646,13 +1648,15 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
} }
strongSelf.updateChatPresentationInterfaceState(animated: animated, interactive: false, { strongSelf.updateChatPresentationInterfaceState(animated: animated, interactive: false, {
return $0.updatedPeer { _ in return renderedPeer return $0.updatedPeer { _ in
return renderedPeer
}.updatedIsNotAccessible(isNotAccessible).updatedContactStatus(contactStatus).updatedHasBots(hasBots).updatedIsArchived(isArchived).updatedPeerIsMuted(peerIsMuted).updatedPeerDiscussionId(peerDiscussionId).updatedPeerGeoLocation(peerGeoLocation).updatedExplicitelyCanPinMessages(explicitelyCanPinMessages) }.updatedIsNotAccessible(isNotAccessible).updatedContactStatus(contactStatus).updatedHasBots(hasBots).updatedIsArchived(isArchived).updatedPeerIsMuted(peerIsMuted).updatedPeerDiscussionId(peerDiscussionId).updatedPeerGeoLocation(peerGeoLocation).updatedExplicitelyCanPinMessages(explicitelyCanPinMessages)
}) })
if !strongSelf.didSetChatLocationInfoReady { if !strongSelf.didSetChatLocationInfoReady {
strongSelf.didSetChatLocationInfoReady = true strongSelf.didSetChatLocationInfoReady = true
strongSelf._chatLocationInfoReady.set(.single(true)) strongSelf._chatLocationInfoReady.set(.single(true))
} }
strongSelf.updateReminderActivity()
if let upgradedToPeerId = upgradedToPeerId { if let upgradedToPeerId = upgradedToPeerId {
if let navigationController = strongSelf.navigationController as? NavigationController { if let navigationController = strongSelf.navigationController as? NavigationController {
var viewControllers = navigationController.viewControllers var viewControllers = navigationController.viewControllers
@ -1898,6 +1902,8 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
if let strongSelf = self, strongSelf.canReadHistoryValue != value { if let strongSelf = self, strongSelf.canReadHistoryValue != value {
strongSelf.canReadHistoryValue = value strongSelf.canReadHistoryValue = value
strongSelf.raiseToListen?.enabled = value strongSelf.raiseToListen?.enabled = value
strongSelf.isReminderActivityEnabled = value
strongSelf.updateReminderActivity()
} }
}) })
@ -1963,6 +1969,7 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
self.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeTarget(self) self.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeTarget(self)
self.preloadHistoryPeerIdDisposable.dispose() self.preloadHistoryPeerIdDisposable.dispose()
self.reportIrrelvantGeoDisposable?.dispose() self.reportIrrelvantGeoDisposable?.dispose()
self.reminderActivity?.invalidate()
} }
public func updatePresentationMode(_ mode: ChatControllerPresentationMode) { public func updatePresentationMode(_ mode: ChatControllerPresentationMode) {
@ -6935,4 +6942,32 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
}) })
} }
} }
private func updateReminderActivity() {
if (self.isReminderActivityEnabled) {
if #available(iOS 9.0, *) {
if self.reminderActivity == nil, case let .peer(peerId) = self.chatLocation, let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer {
let reminderActivity = NSUserActivity(activityType: "RemindAboutChatIntent")
self.reminderActivity = reminderActivity
if peer is TelegramGroup {
reminderActivity.title = self.presentationData.strings.Activity_RemindAboutGroup(peer.displayTitle).0
} else if let channel = peer as? TelegramChannel {
if case .broadcast = channel.info {
reminderActivity.title = self.presentationData.strings.Activity_RemindAboutChannel(peer.displayTitle).0
} else {
reminderActivity.title = self.presentationData.strings.Activity_RemindAboutGroup(peer.displayTitle).0
}
} else {
reminderActivity.title = self.presentationData.strings.Activity_RemindAboutUser(peer.displayTitle).0
}
reminderActivity.userInfo = ["peerId": peerId.toInt64(), "peerTitle": peer.displayTitle]
reminderActivity.isEligibleForHandoff = true
reminderActivity.becomeCurrent()
}
}
} else if let reminderActivity = self.reminderActivity {
self.reminderActivity = nil
reminderActivity.invalidate()
}
}
} }

View File

@ -545,6 +545,42 @@
D0AEAE272080D6970013176E /* PaneSearchBarNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AEAE262080D6970013176E /* PaneSearchBarNode.swift */; }; D0AEAE272080D6970013176E /* PaneSearchBarNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AEAE262080D6970013176E /* PaneSearchBarNode.swift */; };
D0AEAE292080FD660013176E /* StickerPaneSearchGlobaltem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AEAE282080FD660013176E /* StickerPaneSearchGlobaltem.swift */; }; D0AEAE292080FD660013176E /* StickerPaneSearchGlobaltem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AEAE282080FD660013176E /* StickerPaneSearchGlobaltem.swift */; };
D0AF323A1FB1D8D60097362B /* ChatOverlayNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AF32391FB1D8D60097362B /* ChatOverlayNavigationBar.swift */; }; D0AF323A1FB1D8D60097362B /* ChatOverlayNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AF32391FB1D8D60097362B /* ChatOverlayNavigationBar.swift */; };
D0AF796E22C2E26500CECCB8 /* astc.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0AF793622C2E26500CECCB8 /* astc.cc */; };
D0AF796F22C2E26500CECCB8 /* compress_texture.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF793822C2E26500CECCB8 /* compress_texture.h */; };
D0AF797022C2E26500CECCB8 /* integer_sequence_encoding.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF793922C2E26500CECCB8 /* integer_sequence_encoding.h */; };
D0AF797122C2E26500CECCB8 /* range.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF793A22C2E26500CECCB8 /* range.h */; };
D0AF797222C2E26500CECCB8 /* misc.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF793B22C2E26500CECCB8 /* misc.h */; };
D0AF797322C2E26500CECCB8 /* tables_data_size.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF793C22C2E26500CECCB8 /* tables_data_size.h */; };
D0AF797422C2E26500CECCB8 /* matrix.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF793D22C2E26500CECCB8 /* matrix.h */; };
D0AF797522C2E26500CECCB8 /* colors.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF793E22C2E26500CECCB8 /* colors.h */; };
D0AF797622C2E26500CECCB8 /* endpoints_principal_components.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0AF793F22C2E26500CECCB8 /* endpoints_principal_components.cc */; };
D0AF797722C2E26500CECCB8 /* data_size.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794022C2E26500CECCB8 /* data_size.h */; };
D0AF797822C2E26500CECCB8 /* meson.build in Resources */ = {isa = PBXBuildFile; fileRef = D0AF794122C2E26500CECCB8 /* meson.build */; };
D0AF797922C2E26500CECCB8 /* endpoints_bounding_box.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794222C2E26500CECCB8 /* endpoints_bounding_box.h */; };
D0AF797A22C2E26500CECCB8 /* tables_color_quantization.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794322C2E26500CECCB8 /* tables_color_quantization.h */; };
D0AF797B22C2E26500CECCB8 /* tables_integer_sequence_encoding.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794422C2E26500CECCB8 /* tables_integer_sequence_encoding.h */; };
D0AF797C22C2E26500CECCB8 /* constants.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794522C2E26500CECCB8 /* constants.h */; };
D0AF797D22C2E26500CECCB8 /* endpoints_min_max.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794622C2E26500CECCB8 /* endpoints_min_max.h */; };
D0AF797E22C2E26500CECCB8 /* dcheck.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794722C2E26500CECCB8 /* dcheck.h */; };
D0AF797F22C2E26500CECCB8 /* weights_quantize_table.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794822C2E26500CECCB8 /* weights_quantize_table.h */; };
D0AF798022C2E26500CECCB8 /* compress_block.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0AF794922C2E26500CECCB8 /* compress_block.cc */; };
D0AF798122C2E26500CECCB8 /* endpoints_principal_components.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794A22C2E26500CECCB8 /* endpoints_principal_components.h */; };
D0AF798222C2E26500CECCB8 /* bitmanip.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794B22C2E26500CECCB8 /* bitmanip.h */; };
D0AF798322C2E26500CECCB8 /* endpoints.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794C22C2E26500CECCB8 /* endpoints.h */; };
D0AF798422C2E26500CECCB8 /* compress_block.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794D22C2E26500CECCB8 /* compress_block.h */; };
D0AF798522C2E26500CECCB8 /* endpoints_encode.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794E22C2E26500CECCB8 /* endpoints_encode.h */; };
D0AF798622C2E26500CECCB8 /* weights_quantize.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF794F22C2E26500CECCB8 /* weights_quantize.h */; };
D0AF798722C2E26500CECCB8 /* compress_texture.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0AF795022C2E26500CECCB8 /* compress_texture.cc */; };
D0AF798822C2E26500CECCB8 /* matrix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0AF795122C2E26500CECCB8 /* matrix.cc */; };
D0AF798922C2E26500CECCB8 /* vector.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF795222C2E26500CECCB8 /* vector.h */; };
D0AF798A22C2E26500CECCB8 /* endpoints_quantize.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF795322C2E26500CECCB8 /* endpoints_quantize.h */; };
D0AF798B22C2E26500CECCB8 /* store_block.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF795422C2E26500CECCB8 /* store_block.h */; };
D0AF798C22C2E26500CECCB8 /* color.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF795622C2E26500CECCB8 /* color.h */; };
D0AF798D22C2E26500CECCB8 /* bgra.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0AF795722C2E26500CECCB8 /* bgra.cc */; };
D0AF798E22C2E26500CECCB8 /* compressed.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF795822C2E26500CECCB8 /* compressed.h */; };
D0AF798F22C2E26500CECCB8 /* compressed.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0AF795922C2E26500CECCB8 /* compressed.cc */; };
D0AF799022C2E26500CECCB8 /* bgra.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF795A22C2E26500CECCB8 /* bgra.h */; };
D0AF79A322C2E36400CECCB8 /* astc.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AF79A222C2E36400CECCB8 /* astc.h */; };
D0AFCC791F4C8D2C000720C6 /* InstantPageSlideshowItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AFCC781F4C8D2C000720C6 /* InstantPageSlideshowItem.swift */; }; D0AFCC791F4C8D2C000720C6 /* InstantPageSlideshowItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AFCC781F4C8D2C000720C6 /* InstantPageSlideshowItem.swift */; };
D0AFCC7B1F4C8D39000720C6 /* InstantPageSlideshowItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AFCC7A1F4C8D39000720C6 /* InstantPageSlideshowItemNode.swift */; }; D0AFCC7B1F4C8D39000720C6 /* InstantPageSlideshowItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AFCC7A1F4C8D39000720C6 /* InstantPageSlideshowItemNode.swift */; };
D0B21B13220D6E8C003F741D /* ActionSheetPeerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */; }; D0B21B13220D6E8C003F741D /* ActionSheetPeerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */; };
@ -1950,6 +1986,42 @@
D0AEAE262080D6970013176E /* PaneSearchBarNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaneSearchBarNode.swift; sourceTree = "<group>"; }; D0AEAE262080D6970013176E /* PaneSearchBarNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaneSearchBarNode.swift; sourceTree = "<group>"; };
D0AEAE282080FD660013176E /* StickerPaneSearchGlobaltem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerPaneSearchGlobaltem.swift; sourceTree = "<group>"; }; D0AEAE282080FD660013176E /* StickerPaneSearchGlobaltem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerPaneSearchGlobaltem.swift; sourceTree = "<group>"; };
D0AF32391FB1D8D60097362B /* ChatOverlayNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatOverlayNavigationBar.swift; sourceTree = "<group>"; }; D0AF32391FB1D8D60097362B /* ChatOverlayNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatOverlayNavigationBar.swift; sourceTree = "<group>"; };
D0AF793622C2E26500CECCB8 /* astc.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = astc.cc; sourceTree = "<group>"; };
D0AF793822C2E26500CECCB8 /* compress_texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compress_texture.h; sourceTree = "<group>"; };
D0AF793922C2E26500CECCB8 /* integer_sequence_encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = integer_sequence_encoding.h; sourceTree = "<group>"; };
D0AF793A22C2E26500CECCB8 /* range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = range.h; sourceTree = "<group>"; };
D0AF793B22C2E26500CECCB8 /* misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = "<group>"; };
D0AF793C22C2E26500CECCB8 /* tables_data_size.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tables_data_size.h; sourceTree = "<group>"; };
D0AF793D22C2E26500CECCB8 /* matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = matrix.h; sourceTree = "<group>"; };
D0AF793E22C2E26500CECCB8 /* colors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = colors.h; sourceTree = "<group>"; };
D0AF793F22C2E26500CECCB8 /* endpoints_principal_components.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = endpoints_principal_components.cc; sourceTree = "<group>"; };
D0AF794022C2E26500CECCB8 /* data_size.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = data_size.h; sourceTree = "<group>"; };
D0AF794122C2E26500CECCB8 /* meson.build */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = meson.build; sourceTree = "<group>"; };
D0AF794222C2E26500CECCB8 /* endpoints_bounding_box.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endpoints_bounding_box.h; sourceTree = "<group>"; };
D0AF794322C2E26500CECCB8 /* tables_color_quantization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tables_color_quantization.h; sourceTree = "<group>"; };
D0AF794422C2E26500CECCB8 /* tables_integer_sequence_encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tables_integer_sequence_encoding.h; sourceTree = "<group>"; };
D0AF794522C2E26500CECCB8 /* constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = constants.h; sourceTree = "<group>"; };
D0AF794622C2E26500CECCB8 /* endpoints_min_max.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endpoints_min_max.h; sourceTree = "<group>"; };
D0AF794722C2E26500CECCB8 /* dcheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dcheck.h; sourceTree = "<group>"; };
D0AF794822C2E26500CECCB8 /* weights_quantize_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = weights_quantize_table.h; sourceTree = "<group>"; };
D0AF794922C2E26500CECCB8 /* compress_block.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compress_block.cc; sourceTree = "<group>"; };
D0AF794A22C2E26500CECCB8 /* endpoints_principal_components.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endpoints_principal_components.h; sourceTree = "<group>"; };
D0AF794B22C2E26500CECCB8 /* bitmanip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitmanip.h; sourceTree = "<group>"; };
D0AF794C22C2E26500CECCB8 /* endpoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endpoints.h; sourceTree = "<group>"; };
D0AF794D22C2E26500CECCB8 /* compress_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compress_block.h; sourceTree = "<group>"; };
D0AF794E22C2E26500CECCB8 /* endpoints_encode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endpoints_encode.h; sourceTree = "<group>"; };
D0AF794F22C2E26500CECCB8 /* weights_quantize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = weights_quantize.h; sourceTree = "<group>"; };
D0AF795022C2E26500CECCB8 /* compress_texture.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compress_texture.cc; sourceTree = "<group>"; };
D0AF795122C2E26500CECCB8 /* matrix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = matrix.cc; sourceTree = "<group>"; };
D0AF795222C2E26500CECCB8 /* vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector.h; sourceTree = "<group>"; };
D0AF795322C2E26500CECCB8 /* endpoints_quantize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endpoints_quantize.h; sourceTree = "<group>"; };
D0AF795422C2E26500CECCB8 /* store_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = store_block.h; sourceTree = "<group>"; };
D0AF795622C2E26500CECCB8 /* color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = color.h; sourceTree = "<group>"; };
D0AF795722C2E26500CECCB8 /* bgra.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bgra.cc; sourceTree = "<group>"; };
D0AF795822C2E26500CECCB8 /* compressed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compressed.h; sourceTree = "<group>"; };
D0AF795922C2E26500CECCB8 /* compressed.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compressed.cc; sourceTree = "<group>"; };
D0AF795A22C2E26500CECCB8 /* bgra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bgra.h; sourceTree = "<group>"; };
D0AF79A222C2E36400CECCB8 /* astc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = astc.h; sourceTree = "<group>"; };
D0AFCC781F4C8D2C000720C6 /* InstantPageSlideshowItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageSlideshowItem.swift; sourceTree = "<group>"; }; D0AFCC781F4C8D2C000720C6 /* InstantPageSlideshowItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageSlideshowItem.swift; sourceTree = "<group>"; };
D0AFCC7A1F4C8D39000720C6 /* InstantPageSlideshowItemNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageSlideshowItemNode.swift; sourceTree = "<group>"; }; D0AFCC7A1F4C8D39000720C6 /* InstantPageSlideshowItemNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageSlideshowItemNode.swift; sourceTree = "<group>"; };
D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetPeerItem.swift; sourceTree = "<group>"; }; D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetPeerItem.swift; sourceTree = "<group>"; };
@ -2828,6 +2900,7 @@
D01590A922BD46690017C33E /* Animation */ = { D01590A922BD46690017C33E /* Animation */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D0AF793422C2E26500CECCB8 /* astc */,
D01590B622BDAEBC0017C33E /* BC1Compression.cpp */, D01590B622BDAEBC0017C33E /* BC1Compression.cpp */,
D01590B122BDAEBB0017C33E /* BC1Compression.h */, D01590B122BDAEBB0017C33E /* BC1Compression.h */,
D01590B922BDAEBC0017C33E /* BMPImage.cpp */, D01590B922BDAEBC0017C33E /* BMPImage.cpp */,
@ -3688,6 +3761,74 @@
path = "Bridge Audio"; path = "Bridge Audio";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D0AF793422C2E26500CECCB8 /* astc */ = {
isa = PBXGroup;
children = (
D0AF793522C2E26500CECCB8 /* compress */,
D0AF793722C2E26500CECCB8 /* astc */,
D0AF795522C2E26500CECCB8 /* image */,
);
name = astc;
path = "third-party/astc";
sourceTree = SOURCE_ROOT;
};
D0AF793522C2E26500CECCB8 /* compress */ = {
isa = PBXGroup;
children = (
D0AF79A222C2E36400CECCB8 /* astc.h */,
D0AF793622C2E26500CECCB8 /* astc.cc */,
);
path = compress;
sourceTree = "<group>";
};
D0AF793722C2E26500CECCB8 /* astc */ = {
isa = PBXGroup;
children = (
D0AF793822C2E26500CECCB8 /* compress_texture.h */,
D0AF793922C2E26500CECCB8 /* integer_sequence_encoding.h */,
D0AF793A22C2E26500CECCB8 /* range.h */,
D0AF793B22C2E26500CECCB8 /* misc.h */,
D0AF793C22C2E26500CECCB8 /* tables_data_size.h */,
D0AF793D22C2E26500CECCB8 /* matrix.h */,
D0AF793E22C2E26500CECCB8 /* colors.h */,
D0AF793F22C2E26500CECCB8 /* endpoints_principal_components.cc */,
D0AF794022C2E26500CECCB8 /* data_size.h */,
D0AF794122C2E26500CECCB8 /* meson.build */,
D0AF794222C2E26500CECCB8 /* endpoints_bounding_box.h */,
D0AF794322C2E26500CECCB8 /* tables_color_quantization.h */,
D0AF794422C2E26500CECCB8 /* tables_integer_sequence_encoding.h */,
D0AF794522C2E26500CECCB8 /* constants.h */,
D0AF794622C2E26500CECCB8 /* endpoints_min_max.h */,
D0AF794722C2E26500CECCB8 /* dcheck.h */,
D0AF794822C2E26500CECCB8 /* weights_quantize_table.h */,
D0AF794922C2E26500CECCB8 /* compress_block.cc */,
D0AF794A22C2E26500CECCB8 /* endpoints_principal_components.h */,
D0AF794B22C2E26500CECCB8 /* bitmanip.h */,
D0AF794C22C2E26500CECCB8 /* endpoints.h */,
D0AF794D22C2E26500CECCB8 /* compress_block.h */,
D0AF794E22C2E26500CECCB8 /* endpoints_encode.h */,
D0AF794F22C2E26500CECCB8 /* weights_quantize.h */,
D0AF795022C2E26500CECCB8 /* compress_texture.cc */,
D0AF795122C2E26500CECCB8 /* matrix.cc */,
D0AF795222C2E26500CECCB8 /* vector.h */,
D0AF795322C2E26500CECCB8 /* endpoints_quantize.h */,
D0AF795422C2E26500CECCB8 /* store_block.h */,
);
path = astc;
sourceTree = "<group>";
};
D0AF795522C2E26500CECCB8 /* image */ = {
isa = PBXGroup;
children = (
D0AF795622C2E26500CECCB8 /* color.h */,
D0AF795722C2E26500CECCB8 /* bgra.cc */,
D0AF795822C2E26500CECCB8 /* compressed.h */,
D0AF795922C2E26500CECCB8 /* compressed.cc */,
D0AF795A22C2E26500CECCB8 /* bgra.h */,
);
path = image;
sourceTree = "<group>";
};
D0AF7C441ED84BB000CD8E0F /* Language Selection */ = { D0AF7C441ED84BB000CD8E0F /* Language Selection */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -4909,7 +5050,9 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D0E9BA221F05577700F079A4 /* STPCard.h in Headers */, D0E9BA221F05577700F079A4 /* STPCard.h in Headers */,
D0AF798622C2E26500CECCB8 /* weights_quantize.h in Headers */,
D0E9BA591F055A2200F079A4 /* STPWeakStrongMacros.h in Headers */, D0E9BA591F055A2200F079A4 /* STPWeakStrongMacros.h in Headers */,
D0AF799022C2E26500CECCB8 /* bgra.h in Headers */,
D0E9BADE1F0574D800F079A4 /* STPBackendAPIAdapter.h in Headers */, D0E9BADE1F0574D800F079A4 /* STPBackendAPIAdapter.h in Headers */,
D0E9BAD11F0573C000F079A4 /* STPToken.h in Headers */, D0E9BAD11F0573C000F079A4 /* STPToken.h in Headers */,
D01590C222BDAEBC0017C33E /* TypeDefinitions.h in Headers */, D01590C222BDAEBC0017C33E /* TypeDefinitions.h in Headers */,
@ -4917,8 +5060,12 @@
D0E9BAE71F0574FF00F079A4 /* STPCustomer.h in Headers */, D0E9BAE71F0574FF00F079A4 /* STPCustomer.h in Headers */,
D0208AD51FA33D14001F0D5F /* RaiseToListenActivator.h in Headers */, D0208AD51FA33D14001F0D5F /* RaiseToListenActivator.h in Headers */,
D00817DA22B47A14008A895F /* TGPresentationAutoNightPreferences.h in Headers */, D00817DA22B47A14008A895F /* TGPresentationAutoNightPreferences.h in Headers */,
D0AF797D22C2E26500CECCB8 /* endpoints_min_max.h in Headers */,
D0E9BAE31F0574D800F079A4 /* STPBankAccountParams.h in Headers */, D0E9BAE31F0574D800F079A4 /* STPBankAccountParams.h in Headers */,
D0AF797222C2E26500CECCB8 /* misc.h in Headers */,
D0AF798222C2E26500CECCB8 /* bitmanip.h in Headers */,
D0E9BA361F05585000F079A4 /* STPPhoneNumberValidator.h in Headers */, D0E9BA361F05585000F079A4 /* STPPhoneNumberValidator.h in Headers */,
D0AF797C22C2E26500CECCB8 /* constants.h in Headers */,
D0E9BA511F0559DA00F079A4 /* STPImageLibrary.h in Headers */, D0E9BA511F0559DA00F079A4 /* STPImageLibrary.h in Headers */,
D0E9BA4C1F0559C700F079A4 /* NSString+Stripe_CardBrands.h in Headers */, D0E9BA4C1F0559C700F079A4 /* NSString+Stripe_CardBrands.h in Headers */,
D00817E022B47A14008A895F /* UIImage+ImageEffects.h in Headers */, D00817E022B47A14008A895F /* UIImage+ImageEffects.h in Headers */,
@ -4926,6 +5073,8 @@
D0E9BAE11F0574D800F079A4 /* STPBankAccount.h in Headers */, D0E9BAE11F0574D800F079A4 /* STPBankAccount.h in Headers */,
D0E9BACE1F0573AF00F079A4 /* STPBlocks.h in Headers */, D0E9BACE1F0573AF00F079A4 /* STPBlocks.h in Headers */,
D0E9BA2A1F0557A600F079A4 /* STPFormEncoder.h in Headers */, D0E9BA2A1F0557A600F079A4 /* STPFormEncoder.h in Headers */,
D0AF797422C2E26500CECCB8 /* matrix.h in Headers */,
D0AF79A322C2E36400CECCB8 /* astc.h in Headers */,
D0E9BA321F05583A00F079A4 /* STPPostalCodeValidator.h in Headers */, D0E9BA321F05583A00F079A4 /* STPPostalCodeValidator.h in Headers */,
D0E9BADC1F0574D800F079A4 /* PKPayment+Stripe.h in Headers */, D0E9BADC1F0574D800F079A4 /* PKPayment+Stripe.h in Headers */,
D0E9BA491F0559B600F079A4 /* STPPaymentMethod.h in Headers */, D0E9BA491F0559B600F079A4 /* STPPaymentMethod.h in Headers */,
@ -4936,10 +5085,20 @@
D008177B22B46B7E008A895F /* TGContactModel.h in Headers */, D008177B22B46B7E008A895F /* TGContactModel.h in Headers */,
D0E9BA291F0557A600F079A4 /* STPFormEncodable.h in Headers */, D0E9BA291F0557A600F079A4 /* STPFormEncodable.h in Headers */,
D0E9BA141F05574500F079A4 /* STPCardValidationState.h in Headers */, D0E9BA141F05574500F079A4 /* STPCardValidationState.h in Headers */,
D0AF797922C2E26500CECCB8 /* endpoints_bounding_box.h in Headers */,
D00701A12029F6D0006B9E34 /* TGMimeTypeMap.h in Headers */, D00701A12029F6D0006B9E34 /* TGMimeTypeMap.h in Headers */,
D0E9BA461F0559A500F079A4 /* NSDictionary+Stripe.h in Headers */, D0E9BA461F0559A500F079A4 /* NSDictionary+Stripe.h in Headers */,
D0AF798A22C2E26500CECCB8 /* endpoints_quantize.h in Headers */,
D0AF797322C2E26500CECCB8 /* tables_data_size.h in Headers */,
D0AF797E22C2E26500CECCB8 /* dcheck.h in Headers */,
D0AF797F22C2E26500CECCB8 /* weights_quantize_table.h in Headers */,
D0208AD91FA34017001F0D5F /* DeviceProximityManager.h in Headers */, D0208AD91FA34017001F0D5F /* DeviceProximityManager.h in Headers */,
D0AF798B22C2E26500CECCB8 /* store_block.h in Headers */,
D0AF797122C2E26500CECCB8 /* range.h in Headers */,
D0AF797722C2E26500CECCB8 /* data_size.h in Headers */,
D0AE303722B1D3620058D3BC /* TGBridgeAudioEncoder.h in Headers */, D0AE303722B1D3620058D3BC /* TGBridgeAudioEncoder.h in Headers */,
D0AF798422C2E26500CECCB8 /* compress_block.h in Headers */,
D0AF798E22C2E26500CECCB8 /* compressed.h in Headers */,
D0E9BAC61F05738600F079A4 /* STPAPIClient.h in Headers */, D0E9BAC61F05738600F079A4 /* STPAPIClient.h in Headers */,
D0E9BA531F0559DA00F079A4 /* STPImageLibrary+Private.h in Headers */, D0E9BA531F0559DA00F079A4 /* STPImageLibrary+Private.h in Headers */,
D0E9BA601F055A4300F079A4 /* STPDelegateProxy.h in Headers */, D0E9BA601F055A4300F079A4 /* STPDelegateProxy.h in Headers */,
@ -4948,26 +5107,36 @@
D0E9BACB1F05738600F079A4 /* STPAPIPostRequest.h in Headers */, D0E9BACB1F05738600F079A4 /* STPAPIPostRequest.h in Headers */,
D0E9BA561F055A0B00F079A4 /* STPFormTextField.h in Headers */, D0E9BA561F055A0B00F079A4 /* STPFormTextField.h in Headers */,
D01590C122BDAEBC0017C33E /* DDSImage.h in Headers */, D01590C122BDAEBC0017C33E /* DDSImage.h in Headers */,
D0AF798122C2E26500CECCB8 /* endpoints_principal_components.h in Headers */,
D008177C22B46B7E008A895F /* TGItemProviderSignals.h in Headers */, D008177C22B46B7E008A895F /* TGItemProviderSignals.h in Headers */,
D0AF798322C2E26500CECCB8 /* endpoints.h in Headers */,
D0E9BABE1F05735F00F079A4 /* STPPaymentConfiguration+Private.h in Headers */, D0E9BABE1F05735F00F079A4 /* STPPaymentConfiguration+Private.h in Headers */,
D01590BB22BDAEBC0017C33E /* BC1Compression.h in Headers */, D01590BB22BDAEBC0017C33E /* BC1Compression.h in Headers */,
D0E9BACA1F05738600F079A4 /* STPAPIClient+Private.h in Headers */, D0E9BACA1F05738600F079A4 /* STPAPIClient+Private.h in Headers */,
D01590BC22BDAEBC0017C33E /* BMPImage.h in Headers */, D01590BC22BDAEBC0017C33E /* BMPImage.h in Headers */,
D0E9BA251F05578900F079A4 /* STPCardBrand.h in Headers */, D0E9BA251F05578900F079A4 /* STPCardBrand.h in Headers */,
D0AF797522C2E26500CECCB8 /* colors.h in Headers */,
D0E9BAC81F05738600F079A4 /* STPAPIClient+ApplePay.h in Headers */, D0E9BAC81F05738600F079A4 /* STPAPIClient+ApplePay.h in Headers */,
D0E9BA451F0559A500F079A4 /* STPAPIResponseDecodable.h in Headers */, D0E9BA451F0559A500F079A4 /* STPAPIResponseDecodable.h in Headers */,
D0E9BA201F05577700F079A4 /* STPCardParams.h in Headers */, D0E9BA201F05577700F079A4 /* STPCardParams.h in Headers */,
D0E9BA151F05574500F079A4 /* STPCardValidator.h in Headers */, D0E9BA151F05574500F079A4 /* STPCardValidator.h in Headers */,
D0AF797B22C2E26500CECCB8 /* tables_integer_sequence_encoding.h in Headers */,
D0AF798C22C2E26500CECCB8 /* color.h in Headers */,
D00817D722B47A14008A895F /* TGBridgeServer.h in Headers */, D00817D722B47A14008A895F /* TGBridgeServer.h in Headers */,
D0AF796F22C2E26500CECCB8 /* compress_texture.h in Headers */,
D0AF798922C2E26500CECCB8 /* vector.h in Headers */,
D00817CE22B47A14008A895F /* TGProxyItem.h in Headers */, D00817CE22B47A14008A895F /* TGProxyItem.h in Headers */,
D0E9BA401F0558FE00F079A4 /* StripeError.h in Headers */, D0E9BA401F0558FE00F079A4 /* StripeError.h in Headers */,
D01590C922BE62C40017C33E /* TextureCompression.h in Headers */, D01590C922BE62C40017C33E /* TextureCompression.h in Headers */,
D0E9BA191F05574500F079A4 /* STPPaymentCardTextField.h in Headers */, D0E9BA191F05574500F079A4 /* STPPaymentCardTextField.h in Headers */,
D0E9BA3F1F0558FE00F079A4 /* STPSource.h in Headers */, D0E9BA3F1F0558FE00F079A4 /* STPSource.h in Headers */,
D0AF797A22C2E26500CECCB8 /* tables_color_quantization.h in Headers */,
D008177A22B46B7E008A895F /* TGShareLocationSignals.h in Headers */, D008177A22B46B7E008A895F /* TGShareLocationSignals.h in Headers */,
D0AF798522C2E26500CECCB8 /* endpoints_encode.h in Headers */,
D0E9BABC1F05735F00F079A4 /* STPPaymentConfiguration.h in Headers */, D0E9BABC1F05735F00F079A4 /* STPPaymentConfiguration.h in Headers */,
D01590BF22BDAEBC0017C33E /* Image.h in Headers */, D01590BF22BDAEBC0017C33E /* Image.h in Headers */,
D0E9BA2E1F0557D400F079A4 /* STPAddress.h in Headers */, D0E9BA2E1F0557D400F079A4 /* STPAddress.h in Headers */,
D0AF797022C2E26500CECCB8 /* integer_sequence_encoding.h in Headers */,
D0E9BA5C1F055A3300F079A4 /* STPBINRange.h in Headers */, D0E9BA5C1F055A3300F079A4 /* STPBINRange.h in Headers */,
D0E9BA3A1F0558E800F079A4 /* NSString+Stripe.h in Headers */, D0E9BA3A1F0558E800F079A4 /* NSString+Stripe.h in Headers */,
); );
@ -5130,6 +5299,7 @@
D0E9BA981F056F4C00F079A4 /* stp_card_applepay_template@3x.png in Resources */, D0E9BA981F056F4C00F079A4 /* stp_card_applepay_template@3x.png in Resources */,
D0E9BAA51F056F4C00F079A4 /* stp_card_form_applepay@2x.png in Resources */, D0E9BAA51F056F4C00F079A4 /* stp_card_form_applepay@2x.png in Resources */,
D0E9BAB81F056F4C00F079A4 /* stp_card_visa_template@3x.png in Resources */, D0E9BAB81F056F4C00F079A4 /* stp_card_visa_template@3x.png in Resources */,
D0AF797822C2E26500CECCB8 /* meson.build in Resources */,
D0E9BA9B1F056F4C00F079A4 /* stp_card_cvc_amex@2x.png in Resources */, D0E9BA9B1F056F4C00F079A4 /* stp_card_cvc_amex@2x.png in Resources */,
D0E9BAB61F056F4C00F079A4 /* stp_card_visa@3x.png in Resources */, D0E9BAB61F056F4C00F079A4 /* stp_card_visa@3x.png in Resources */,
D0E9BAA61F056F4C00F079A4 /* stp_card_form_applepay@3x.png in Resources */, D0E9BAA61F056F4C00F079A4 /* stp_card_form_applepay@3x.png in Resources */,
@ -5172,6 +5342,7 @@
D079FCDD1F05C4F20038FADE /* LocalAuth.swift in Sources */, D079FCDD1F05C4F20038FADE /* LocalAuth.swift in Sources */,
09DD5D5221ED175300D7007A /* WallpaperColorPickerNode.swift in Sources */, 09DD5D5221ED175300D7007A /* WallpaperColorPickerNode.swift in Sources */,
D0B2F76820528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift in Sources */, D0B2F76820528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift in Sources */,
D0AF798D22C2E26500CECCB8 /* bgra.cc in Sources */,
09F79A0321C8225600820234 /* WebSearchVideoGalleryItem.swift in Sources */, 09F79A0321C8225600820234 /* WebSearchVideoGalleryItem.swift in Sources */,
D0E9BA631F055AD200F079A4 /* BotPaymentCardInputItemNode.swift in Sources */, D0E9BA631F055AD200F079A4 /* BotPaymentCardInputItemNode.swift in Sources */,
D01848E821A03BDA00B6DEBD /* ChatSearchState.swift in Sources */, D01848E821A03BDA00B6DEBD /* ChatSearchState.swift in Sources */,
@ -5212,6 +5383,7 @@
D0EC6CC71EB9F58800EBF1C3 /* PeerNotificationSoundStrings.swift in Sources */, D0EC6CC71EB9F58800EBF1C3 /* PeerNotificationSoundStrings.swift in Sources */,
D01C06C01FBF118A001561AB /* MessageUtils.swift in Sources */, D01C06C01FBF118A001561AB /* MessageUtils.swift in Sources */,
D0104F281F47171F004E4881 /* InstantPageGalleryController.swift in Sources */, D0104F281F47171F004E4881 /* InstantPageGalleryController.swift in Sources */,
D0AF798F22C2E26500CECCB8 /* compressed.cc in Sources */,
D0EC6CC81EB9F58800EBF1C3 /* ProgressiveImage.swift in Sources */, D0EC6CC81EB9F58800EBF1C3 /* ProgressiveImage.swift in Sources */,
D081E108217F583F003CD921 /* LanguageLinkPreviewContentNode.swift in Sources */, D081E108217F583F003CD921 /* LanguageLinkPreviewContentNode.swift in Sources */,
D0EC6CC91EB9F58800EBF1C3 /* WebP.swift in Sources */, D0EC6CC91EB9F58800EBF1C3 /* WebP.swift in Sources */,
@ -5552,6 +5724,7 @@
D099D7511EEFF91E00A3128C /* GameControllerTitleView.swift in Sources */, D099D7511EEFF91E00A3128C /* GameControllerTitleView.swift in Sources */,
D0EC6D711EB9F58800EBF1C3 /* AuthorizationSequencePasswordEntryController.swift in Sources */, D0EC6D711EB9F58800EBF1C3 /* AuthorizationSequencePasswordEntryController.swift in Sources */,
D0EC6D721EB9F58800EBF1C3 /* AuthorizationSequencePasswordEntryControllerNode.swift in Sources */, D0EC6D721EB9F58800EBF1C3 /* AuthorizationSequencePasswordEntryControllerNode.swift in Sources */,
D0AF797622C2E26500CECCB8 /* endpoints_principal_components.cc in Sources */,
D0EC6D731EB9F58800EBF1C3 /* AuthorizationSequenceSignUpController.swift in Sources */, D0EC6D731EB9F58800EBF1C3 /* AuthorizationSequenceSignUpController.swift in Sources */,
0979787C210642CB0077D77F /* WebEmbedPlayerNode.swift in Sources */, 0979787C210642CB0077D77F /* WebEmbedPlayerNode.swift in Sources */,
D0C12EB01F9A8D1300600BB2 /* ListMessageDateHeader.swift in Sources */, D0C12EB01F9A8D1300600BB2 /* ListMessageDateHeader.swift in Sources */,
@ -5897,6 +6070,8 @@
D0208AD61FA33D14001F0D5F /* RaiseToListenActivator.m in Sources */, D0208AD61FA33D14001F0D5F /* RaiseToListenActivator.m in Sources */,
D0EC6E061EB9F58900EBF1C3 /* ChatDocumentGalleryItem.swift in Sources */, D0EC6E061EB9F58900EBF1C3 /* ChatDocumentGalleryItem.swift in Sources */,
D0EC6E071EB9F58900EBF1C3 /* ChatExternalFileGalleryItem.swift in Sources */, D0EC6E071EB9F58900EBF1C3 /* ChatExternalFileGalleryItem.swift in Sources */,
D0AF798022C2E26500CECCB8 /* compress_block.cc in Sources */,
D0AF798722C2E26500CECCB8 /* compress_texture.cc in Sources */,
D0EC6E081EB9F58900EBF1C3 /* ChatImageGalleryItem.swift in Sources */, D0EC6E081EB9F58900EBF1C3 /* ChatImageGalleryItem.swift in Sources */,
D048EA891F4F297500188713 /* InstantPageSettingsFontFamilyItemNode.swift in Sources */, D048EA891F4F297500188713 /* InstantPageSettingsFontFamilyItemNode.swift in Sources */,
09DD88F321BF907C000766BC /* WebSearchRecentQueryItem.swift in Sources */, 09DD88F321BF907C000766BC /* WebSearchRecentQueryItem.swift in Sources */,
@ -5999,12 +6174,14 @@
D0EC6E3C1EB9F58900EBF1C3 /* ItemListPeerActionItem.swift in Sources */, D0EC6E3C1EB9F58900EBF1C3 /* ItemListPeerActionItem.swift in Sources */,
D0EC6E3D1EB9F58900EBF1C3 /* ItemListMultilineInputItem.swift in Sources */, D0EC6E3D1EB9F58900EBF1C3 /* ItemListMultilineInputItem.swift in Sources */,
D0CE8CE71F6F35A300AA2DB0 /* ChatTextInputPanelState.swift in Sources */, D0CE8CE71F6F35A300AA2DB0 /* ChatTextInputPanelState.swift in Sources */,
D0AF796E22C2E26500CECCB8 /* astc.cc in Sources */,
D0CE6F70213EEE5000BCD44B /* CreatePasswordController.swift in Sources */, D0CE6F70213EEE5000BCD44B /* CreatePasswordController.swift in Sources */,
D0EC6E3E1EB9F58900EBF1C3 /* ItemListSectionHeaderItem.swift in Sources */, D0EC6E3E1EB9F58900EBF1C3 /* ItemListSectionHeaderItem.swift in Sources */,
D0EC6E3F1EB9F58900EBF1C3 /* ItemListTextItem.swift in Sources */, D0EC6E3F1EB9F58900EBF1C3 /* ItemListTextItem.swift in Sources */,
D0EC6E401EB9F58900EBF1C3 /* ItemListActivityTextItem.swift in Sources */, D0EC6E401EB9F58900EBF1C3 /* ItemListActivityTextItem.swift in Sources */,
0958FBB9218AD6AF00E0CBD8 /* InstantPageFeedbackItem.swift in Sources */, 0958FBB9218AD6AF00E0CBD8 /* InstantPageFeedbackItem.swift in Sources */,
D00817D022B47A14008A895F /* WakeupManager.swift in Sources */, D00817D022B47A14008A895F /* WakeupManager.swift in Sources */,
D0AF798822C2E26500CECCB8 /* matrix.cc in Sources */,
D0EC6E411EB9F58900EBF1C3 /* ItemListEditableItem.swift in Sources */, D0EC6E411EB9F58900EBF1C3 /* ItemListEditableItem.swift in Sources */,
D0EC6E421EB9F58900EBF1C3 /* ItemListRevealOptionsNode.swift in Sources */, D0EC6E421EB9F58900EBF1C3 /* ItemListRevealOptionsNode.swift in Sources */,
D0E8175920122FE100B82BBB /* ChatRecentActionsFilterController.swift in Sources */, D0E8175920122FE100B82BBB /* ChatRecentActionsFilterController.swift in Sources */,

View File

@ -0,0 +1,168 @@
#ifndef ASTC_BITMANIP_H_
#define ASTC_BITMANIP_H_
#include <cstddef>
#include <cstdint>
#include "dcheck.h"
inline bool getbit(size_t number, size_t n) {
return (number >> n) & 1;
}
inline uint8_t getbits(uint8_t number, uint8_t msb, uint8_t lsb) {
int count = msb - lsb + 1;
return static_cast<uint8_t>((number >> lsb) & ((1 << count) - 1));
}
inline size_t getbits(size_t number, size_t msb, size_t lsb) {
size_t count = msb - lsb + 1;
return (number >> lsb) & (static_cast<size_t>(1 << count) - 1);
}
inline void orbits8_ptr(uint8_t* ptr,
size_t bitoffset,
size_t number,
size_t bitcount) {
DCHECK(bitcount <= 8);
DCHECK((number >> bitcount) == 0);
size_t index = bitoffset / 8;
size_t shift = bitoffset % 8;
// Depending on the offset we might have to consider two bytes when
// writing, for instance if we are writing 8 bits and the offset is 4,
// then we have to write 4 bits to the first byte (ptr[index]) and 4 bits
// to the second byte (ptr[index+1]).
//
// FIXME: Writing to the last byte when the number of bytes is a multiple of 2
// will write past the allocated memory.
uint8_t* p = ptr + index;
size_t mask = number << shift;
DCHECK((p[0] & mask) == 0);
DCHECK((p[1] & (mask >> 8)) == 0);
p[0] |= static_cast<uint8_t>(mask & 0xFF);
p[1] |= static_cast<uint8_t>((mask >> 8) & 0xFF);
}
inline void orbits16_ptr(uint8_t* ptr,
size_t bitoffset,
size_t number,
size_t bitcount) {
DCHECK(bitcount > 8 && bitcount <= 16);
size_t index = bitoffset / 8;
size_t shift = bitoffset % 8;
uint8_t* p = ptr + index;
size_t mask = number << shift;
p[0] |= static_cast<uint8_t>(mask & 0xFF);
p[1] |= static_cast<uint8_t>((mask >> 8) & 0xFF);
p[2] |= static_cast<uint8_t>((mask >> 16) & 0xFF);
p[3] |= static_cast<uint8_t>((mask >> 24) & 0xFF);
}
inline uint16_t getbytes2(const uint8_t* ptr, size_t byteoffset) {
const uint8_t* p = ptr + byteoffset;
return static_cast<uint16_t>((p[1] << 8) | p[0]);
}
inline void setbytes2(uint8_t* ptr, size_t byteoffset, uint16_t bytes) {
ptr[byteoffset + 0] = static_cast<uint8_t>(bytes & 0xFF);
ptr[byteoffset + 1] = static_cast<uint8_t>((bytes >> 8) & 0xFF);
}
inline void split_high_low(uint8_t n, size_t i, uint8_t& high, uint8_t& low) {
DCHECK(i < 8);
uint8_t low_mask = static_cast<uint8_t>((1 << i) - 1);
low = n & low_mask;
high = static_cast<uint8_t>(n >> i);
}
class bitwriter {
public:
explicit bitwriter(uint8_t* ptr) : ptr_(ptr), bitoffset_(0) {
// assumption that all bits in ptr are zero after the offset
// writing beyound the bounds of the allocated memory is undefined
// behaviour
}
// Specialized function that can't write more than 8 bits.
void write8(uint8_t number, size_t bitcount) {
orbits8_ptr(ptr_, bitoffset_, number, bitcount);
bitoffset_ += bitcount;
}
size_t offset() const { return bitoffset_; }
private:
uint8_t* ptr_;
size_t bitoffset_; // in bits
};
const uint8_t bit_reverse_table[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4,
0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA,
0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1,
0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
0x3F, 0xBF, 0x7F, 0xFF};
/**
* Reverse a byte, total function.
*/
inline uint8_t reverse_byte(uint8_t number) {
return bit_reverse_table[number];
}
/**
* Reverse a sequence of bytes.
*
* Assumes that the bits written to (using bitwise or) are zero and that they
* will not clash with bits already written to target sequence. That is it is
* possible to write to a non-zero byte as long as the bits that are actually
* written to are zero.
*/
inline void reverse_bytes(const uint8_t* source,
size_t bytecount,
uint8_t* target) {
for (int i = 0; i < static_cast<int>(bytecount); ++i) {
DCHECK((reverse_byte(source[i]) & target[-i]) == 0);
target[-i] = target[-i] | reverse_byte(source[i]);
}
}
inline void copy_bytes(const uint8_t* source,
size_t bytecount,
uint8_t* target,
size_t bitoffset) {
for (size_t i = 0; i < bytecount; ++i) {
orbits8_ptr(target, bitoffset + i * 8, source[i], 8);
}
}
#endif // ASTC_BITMANIP_H_

View File

@ -0,0 +1,132 @@
#ifndef ASTC_COLORS_H_
#define ASTC_COLORS_H_
#include <math.h>
#include <cstdint>
#include "misc.h"
#include "vector.h"
const int APPROX_COLOR_EPSILON = 50;
union unorm8_t {
struct RgbaColorType {
uint8_t b, g, r, a;
} channels;
uint8_t components[4];
uint32_t bits;
};
union unorm16_t {
struct RgbaColorType {
uint16_t b, g, r, a;
} channels;
uint16_t components[4];
uint64_t bits;
};
inline bool is_greyscale(vec3i_t color) {
// integer equality is transitive
return color.r == color.g && color.g == color.b;
}
inline int luminance(vec3i_t color) {
return (color.r + color.g + color.b) / 3;
}
inline bool approx_equal(vec3i_t a, vec3i_t b) {
return quadrance(a - b) <= APPROX_COLOR_EPSILON;
}
inline vec3i_t clamp_rgb(vec3i_t color) {
vec3i_t result;
result.r = clamp(0, 255, color.r);
result.g = clamp(0, 255, color.g);
result.b = clamp(0, 255, color.b);
return result;
}
inline vec3f_t clamp_rgb(vec3f_t color) {
vec3f_t result;
result.r = clamp(0.0f, 255.0f, color.r);
result.g = clamp(0.0f, 255.0f, color.g);
result.b = clamp(0.0f, 255.0f, color.b);
return result;
}
inline bool is_rgb(float color) {
return color >= 0.0f && color <= 255.0f;
}
inline bool is_rgb(vec3f_t color) {
return is_rgb(color.r) && is_rgb(color.g) && is_rgb(color.b);
}
inline vec3i_t floor(vec3f_t color) {
vec3i_t result;
result.r = static_cast<int>(floor(color.r));
result.g = static_cast<int>(floor(color.g));
result.b = static_cast<int>(floor(color.b));
return result;
}
inline vec3i_t round(vec3f_t color) {
vec3i_t result;
result.r = static_cast<int>(round(color.r));
result.g = static_cast<int>(round(color.g));
result.b = static_cast<int>(round(color.b));
return result;
}
inline vec3i_t to_vec3i(unorm8_t color) {
vec3i_t result;
result.r = color.channels.r;
result.g = color.channels.g;
result.b = color.channels.b;
return result;
}
inline vec3i_t to_vec3i(vec3f_t color) {
vec3i_t result;
result.r = static_cast<int>(color.r);
result.g = static_cast<int>(color.g);
result.b = static_cast<int>(color.b);
return result;
}
inline vec3f_t to_vec3f(unorm8_t color) {
vec3f_t result;
result.r = color.channels.r;
result.g = color.channels.g;
result.b = color.channels.b;
return result;
}
inline vec3f_t to_vec3f(vec3i_t color) {
vec3f_t result;
result.r = static_cast<float>(color.r);
result.g = static_cast<float>(color.g);
result.b = static_cast<float>(color.b);
return result;
}
inline unorm8_t to_unorm8(vec3i_t color) {
unorm8_t result;
result.channels.r = static_cast<uint8_t>(color.r);
result.channels.g = static_cast<uint8_t>(color.g);
result.channels.b = static_cast<uint8_t>(color.b);
result.channels.a = 255;
return result;
}
inline unorm16_t unorm8_to_unorm16(unorm8_t c8) {
// (x / 255) * (2^16-1) = x * 65535 / 255 = x * 257
unorm16_t result;
result.channels.r = static_cast<uint16_t>(c8.channels.r * 257);
result.channels.g = static_cast<uint16_t>(c8.channels.g * 257);
result.channels.b = static_cast<uint16_t>(c8.channels.b * 257);
result.channels.a = static_cast<uint16_t>(c8.channels.a * 257);
return result;
}
#endif // ASTC_COLORS_H_

View File

@ -0,0 +1,155 @@
#include "compress_block.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include "colors.h"
#include "constants.h"
#include "data_size.h"
#include "endpoints.h"
#include "endpoints_encode.h"
#include "endpoints_min_max.h"
#include "endpoints_principal_components.h"
#include "integer_sequence_encoding.h"
#include "misc.h"
#include "range.h"
#include "store_block.h"
#include "vector.h"
#include "weights_quantize.h"
/**
* Write void extent block bits for LDR mode and unused extent coordinates.
*/
void encode_void_extent(vec3i_t color, PhysicalBlock* physical_block) {
void_extent_to_physical(unorm8_to_unorm16(to_unorm8(color)), physical_block);
}
void encode_luminance(const uint8_t texels[BLOCK_TEXEL_COUNT],
PhysicalBlock* physical_block) {
size_t partition_count = 1;
size_t partition_index = 0;
color_endpoint_mode_t color_endpoint_mode = CEM_LDR_LUMINANCE_DIRECT;
range_t weight_quant = RANGE_32;
range_t endpoint_quant =
endpoint_quantization(partition_count, weight_quant, color_endpoint_mode);
uint8_t l0 = 255;
uint8_t l1 = 0;
for (size_t i = 0; i < BLOCK_TEXEL_COUNT; ++i) {
l0 = std::min(l0, texels[i]);
l1 = std::max(l1, texels[i]);
}
uint8_t endpoint_unquantized[2];
uint8_t endpoint_quantized[2];
encode_luminance_direct(endpoint_quant, l0, l1, endpoint_quantized,
endpoint_unquantized);
uint8_t weights_quantized[BLOCK_TEXEL_COUNT];
calculate_quantized_weights_luminance(
texels, weight_quant, endpoint_unquantized[0], endpoint_unquantized[1],
weights_quantized);
uint8_t endpoint_ise[MAXIMUM_ENCODED_COLOR_ENDPOINT_BYTES] = {0};
integer_sequence_encode(endpoint_quantized, 2, RANGE_256, endpoint_ise);
uint8_t weights_ise[MAXIMUM_ENCODED_WEIGHT_BYTES + 1] = {0};
integer_sequence_encode(weights_quantized, BLOCK_TEXEL_COUNT, RANGE_32,
weights_ise);
symbolic_to_physical(color_endpoint_mode, endpoint_quant, weight_quant,
partition_count, partition_index, endpoint_ise,
weights_ise, physical_block);
}
void encode_rgb_single_partition(const unorm8_t texels[BLOCK_TEXEL_COUNT],
vec3f_t e0,
vec3f_t e1,
PhysicalBlock* physical_block) {
size_t partition_index = 0;
size_t partition_count = 1;
color_endpoint_mode_t color_endpoint_mode = CEM_LDR_RGB_DIRECT;
range_t weight_quant = RANGE_12;
range_t endpoint_quant =
endpoint_quantization(partition_count, weight_quant, color_endpoint_mode);
vec3i_t endpoint_unquantized[2];
uint8_t endpoint_quantized[6];
encode_rgb_direct(endpoint_quant, round(e0), round(e1), endpoint_quantized,
endpoint_unquantized);
uint8_t weights_quantized[BLOCK_TEXEL_COUNT];
calculate_quantized_weights_rgb(texels, weight_quant, endpoint_unquantized[0],
endpoint_unquantized[1], weights_quantized);
uint8_t endpoint_ise[MAXIMUM_ENCODED_COLOR_ENDPOINT_BYTES] = {0};
integer_sequence_encode(endpoint_quantized, 6, endpoint_quant, endpoint_ise);
uint8_t weights_ise[MAXIMUM_ENCODED_WEIGHT_BYTES + 1] = {0};
integer_sequence_encode(weights_quantized, BLOCK_TEXEL_COUNT, weight_quant,
weights_ise);
symbolic_to_physical(color_endpoint_mode, endpoint_quant, weight_quant,
partition_count, partition_index, endpoint_ise,
weights_ise, physical_block);
}
bool is_solid(const unorm8_t texels[BLOCK_TEXEL_COUNT],
size_t count,
unorm8_t* color) {
for (size_t i = 0; i < count; ++i) {
if (!approx_equal(to_vec3i(texels[i]), to_vec3i(texels[0]))) {
return false;
}
}
// TODO: Calculate average color?
*color = texels[0];
return true;
}
bool is_greyscale(const unorm8_t texels[BLOCK_TEXEL_COUNT],
size_t count,
uint8_t luminances[BLOCK_TEXEL_COUNT]) {
for (size_t i = 0; i < count; ++i) {
vec3i_t color = to_vec3i(texels[i]);
luminances[i] = static_cast<uint8_t>(luminance(color));
vec3i_t lum(luminances[i], luminances[i], luminances[i]);
if (!approx_equal(color, lum)) {
return false;
}
}
return true;
}
void compress_block(const unorm8_t texels[BLOCK_TEXEL_COUNT],
PhysicalBlock* physical_block) {
{
unorm8_t color;
if (is_solid(texels, BLOCK_TEXEL_COUNT, &color)) {
encode_void_extent(to_vec3i(color), physical_block);
/* encode_void_extent(vec3i_t(0, 0, 0), physical_block); */
return;
}
}
{
uint8_t luminances[BLOCK_TEXEL_COUNT];
if (is_greyscale(texels, BLOCK_TEXEL_COUNT, luminances)) {
encode_luminance(luminances, physical_block);
/* encode_void_extent(vec3i_t(255, 0, 0), physical_block); */
return;
}
}
vec3f_t k, m;
principal_component_analysis_block(texels, k, m);
vec3f_t e0, e1;
find_min_max_block(texels, k, m, e0, e1);
encode_rgb_single_partition(texels, e0, e1, physical_block);
/* encode_void_extent(vec3i_t(0, 255, 0), physical_block); */
}

View File

@ -0,0 +1,12 @@
#ifndef ASTC_COMPRESS_BLOCK_H_
#define ASTC_COMPRESS_BLOCK_H_
#include "constants.h"
union unorm8_t;
struct PhysicalBlock;
void compress_block(const unorm8_t texels[BLOCK_TEXEL_COUNT],
PhysicalBlock* physical_block);
#endif // ASTC_COMPRESS_BLOCK_H_

View File

@ -0,0 +1,68 @@
#include <cstddef>
#include "colors.h"
#include "compress_block.h"
#include "compress_texture.h"
#include "constants.h"
#include "store_block.h"
namespace {
void fetch_image_block(const unorm8_t* source,
size_t image_width,
size_t xpos,
size_t ypos,
unorm8_t texels[BLOCK_TEXEL_COUNT]) {
size_t topleft_index = ypos * image_width + xpos;
const unorm8_t* row0 = source + topleft_index;
const unorm8_t* row1 = row0 + image_width;
const unorm8_t* row2 = row0 + 2 * image_width;
const unorm8_t* row3 = row0 + 3 * image_width;
texels[0] = row0[0];
texels[1] = row0[1];
texels[2] = row0[2];
texels[3] = row0[3];
texels[4] = row1[0];
texels[5] = row1[1];
texels[6] = row1[2];
texels[7] = row1[3];
texels[8] = row2[0];
texels[9] = row2[1];
texels[10] = row2[2];
texels[11] = row2[3];
texels[12] = row3[0];
texels[13] = row3[1];
texels[14] = row3[2];
texels[15] = row3[3];
}
PhysicalBlock physical_block_zero = {0};
} // namespace
void compress_texture(const uint8_t* src,
uint8_t* dst,
int width_int,
int height_int) {
const unorm8_t* data = reinterpret_cast<const unorm8_t*>(src);
size_t width = static_cast<size_t>(width_int);
size_t height = static_cast<size_t>(height_int);
PhysicalBlock* dst_re = reinterpret_cast<PhysicalBlock*>(dst);
for (size_t ypos = 0; ypos < height; ypos += BLOCK_WIDTH) {
for (size_t xpos = 0; xpos < width; xpos += BLOCK_HEIGHT) {
unorm8_t texels[BLOCK_TEXEL_COUNT];
fetch_image_block(data, width, xpos, ypos, texels);
*dst_re = physical_block_zero;
compress_block(texels, dst_re);
++dst_re;
}
}
}

View File

@ -0,0 +1,16 @@
#ifndef ASTC_COMPRESS_TEXTURE_H_
#define ASTC_COMPRESS_TEXTURE_H_
#include <cstdint>
/**
* Compress an texture with the ASTC format.
*
* @param src The source data, width*height*4 bytes with BGRA ordering.
* @param dst The output, width*height bytes.
* @param width The width of the input texture.
* @param height The height of the input texture.
*/
void compress_texture(const uint8_t* src, uint8_t* dst, int width, int height);
#endif // ASTC_COMPRESS_TEXTURE_H_

View File

@ -0,0 +1,18 @@
#ifndef ASTC_CONSTANTS_H_
#define ASTC_CONSTANTS_H_
#include <cstddef>
const size_t BLOCK_WIDTH = 4;
const size_t BLOCK_HEIGHT = 4;
const size_t BLOCK_TEXEL_COUNT = BLOCK_WIDTH * BLOCK_HEIGHT;
const size_t BLOCK_BYTES = 16;
const size_t MAXIMUM_ENCODED_WEIGHT_BITS = 96;
const size_t MAXIMUM_ENCODED_WEIGHT_BYTES = 12;
const size_t MAXIMUM_ENCODED_COLOR_ENDPOINT_BYTES = 12;
const size_t MAX_ENDPOINT_VALUE_COUNT = 18;
#endif // ASTC_CONSTANTS_H_

View File

@ -0,0 +1,21 @@
#ifndef ASTC_DATA_SIZE_H_
#define ASTC_DATA_SIZE_H_
#include <cstddef>
#include <cstdint>
#include "dcheck.h"
#include "endpoints.h"
#include "range.h"
#include "tables_data_size.h"
range_t endpoint_quantization(size_t partitions,
range_t weight_quant,
color_endpoint_mode_t endpoint_mode) {
int8_t ce_range =
color_endpoint_range_table[partitions - 1][weight_quant][endpoint_mode];
DCHECK(ce_range >= 0 && ce_range <= RANGE_MAX);
return static_cast<range_t>(ce_range);
}
#endif // ASTC_DATA_SIZE_H_

View File

@ -0,0 +1,7 @@
#ifndef ASTC_DCHECK_H_
#define ASTC_DCHECK_H_
#include <cassert>
#define DCHECK(x) assert(x)
#endif // ASTC_DCHECK_H_

View File

@ -0,0 +1,24 @@
#ifndef ASTC_ENDPOINTS_H_
#define ASTC_ENDPOINTS_H_
enum color_endpoint_mode_t {
CEM_LDR_LUMINANCE_DIRECT = 0,
CEM_LDR_LUMINANCE_BASE_OFFSET = 1,
CEM_HDR_LUMINANCE_LARGE_RANGE = 2,
CEM_HDR_LUMINANCE_SMALL_RANGE = 3,
CEM_LDR_LUMINANCE_ALPHA_DIRECT = 4,
CEM_LDR_LUMINANCE_ALPHA_BASE_OFFSET = 5,
CEM_LDR_RGB_BASE_SCALE = 6,
CEM_HDR_RGB_BASE_SCALE = 7,
CEM_LDR_RGB_DIRECT = 8,
CEM_LDR_RGB_BASE_OFFSET = 9,
CEM_LDR_RGB_BASE_SCALE_PLUS_TWO_ALPHA = 10,
CEM_HDR_RGB = 11,
CEM_LDR_RGBA_DIRECT = 12,
CEM_LDR_RGBA_BASE_OFFSET = 13,
CEM_HDR_RGB_LDR_ALPHA = 14,
CEM_HDR_RGB_HDR_ALPHA = 15,
CEM_MAX = 16
};
#endif // ASTC_ENDPOINTS_H_

View File

@ -0,0 +1,32 @@
#ifndef ASTC_ENDPOINTS_BOUNDING_BOX_H_
#define ASTC_ENDPOINTS_BOUNDING_BOX_H_
#include <cstddef>
#include "astc/colors.h"
#include "astc/constants.h"
#include "astc/misc.h"
#include "astc/vector.h"
void bounding_box(const unorm8_t* texels,
size_t count,
vec3i_t& e0,
vec3i_t& e1) {
vec3i_t a(255, 255, 255);
vec3i_t b(0, 0, 0);
for (size_t i = 0; i < count; ++i) {
vec3i_t t = to_vec3i(texels[i]);
a = vecmin(a, t);
b = vecmax(b, t);
}
e0 = a;
e1 = b;
}
void bounding_box_block(const unorm8_t texels[BLOCK_TEXEL_COUNT],
vec3i_t& e0,
vec3i_t& e1) {
bounding_box(texels, BLOCK_TEXEL_COUNT, e0, e1);
}
#endif // ASTC_ENDPOINTS_BOUNDING_BOX_H_

View File

@ -0,0 +1,63 @@
#ifndef ASTC_ENDPOINTS_ENCODE_H_
#define ASTC_ENDPOINTS_ENCODE_H_
#include <cstdint>
#include "endpoints_quantize.h"
#include "range.h"
#include "vector.h"
int color_channel_sum(vec3i_t color) {
return color.r + color.g + color.b;
}
void encode_luminance_direct(range_t endpoint_quant,
int v0,
int v1,
uint8_t endpoint_unquantized[2],
uint8_t endpoint_quantized[2]) {
endpoint_quantized[0] = quantize_color(endpoint_quant, v0);
endpoint_quantized[1] = quantize_color(endpoint_quant, v1);
endpoint_unquantized[0] =
unquantize_color(endpoint_quant, endpoint_quantized[0]);
endpoint_unquantized[1] =
unquantize_color(endpoint_quant, endpoint_quantized[1]);
}
void encode_rgb_direct(range_t endpoint_quant,
vec3i_t e0,
vec3i_t e1,
uint8_t endpoint_quantized[6],
vec3i_t endpoint_unquantized[2]) {
vec3i_t e0q = quantize_color(endpoint_quant, e0);
vec3i_t e1q = quantize_color(endpoint_quant, e1);
vec3i_t e0u = unquantize_color(endpoint_quant, e0q);
vec3i_t e1u = unquantize_color(endpoint_quant, e1q);
// ASTC uses a different blue contraction encoding when the sum of values for
// the first endpoint is larger than the sum of values in the second
// endpoint. Sort the endpoints to ensure that the normal encoding is used.
if (color_channel_sum(e0u) > color_channel_sum(e1u)) {
endpoint_quantized[0] = static_cast<uint8_t>(e1q.r);
endpoint_quantized[1] = static_cast<uint8_t>(e0q.r);
endpoint_quantized[2] = static_cast<uint8_t>(e1q.g);
endpoint_quantized[3] = static_cast<uint8_t>(e0q.g);
endpoint_quantized[4] = static_cast<uint8_t>(e1q.b);
endpoint_quantized[5] = static_cast<uint8_t>(e0q.b);
endpoint_unquantized[0] = e1u;
endpoint_unquantized[1] = e0u;
} else {
endpoint_quantized[0] = static_cast<uint8_t>(e0q.r);
endpoint_quantized[1] = static_cast<uint8_t>(e1q.r);
endpoint_quantized[2] = static_cast<uint8_t>(e0q.g);
endpoint_quantized[3] = static_cast<uint8_t>(e1q.g);
endpoint_quantized[4] = static_cast<uint8_t>(e0q.b);
endpoint_quantized[5] = static_cast<uint8_t>(e1q.b);
endpoint_unquantized[0] = e0u;
endpoint_unquantized[1] = e1u;
}
}
#endif // ASTC_ENDPOINTS_ENCODE_H_

View File

@ -0,0 +1,47 @@
#ifndef ASTC_ENDPOINTS_MIN_MAX_H_
#define ASTC_ENDPOINTS_MIN_MAX_H_
#include <algorithm>
#include <cstddef>
#include "colors.h"
#include "constants.h"
#include "dcheck.h"
#include "misc.h"
#include "vector.h"
void find_min_max(const unorm8_t texels[BLOCK_TEXEL_COUNT],
size_t count,
vec3f_t line_k,
vec3f_t line_m,
vec3f_t& e0,
vec3f_t& e1) {
DCHECK(count <= BLOCK_TEXEL_COUNT);
DCHECK(approx_equal(quadrance(line_k), 1.0, 0.0001f));
float a, b;
{
float t = dot(to_vec3f(texels[0]) - line_m, line_k);
a = t;
b = t;
}
for (size_t i = 1; i < count; ++i) {
float t = dot(to_vec3f(texels[i]) - line_m, line_k);
a = std::min(a, t);
b = std::max(b, t);
}
e0 = clamp_rgb(line_k * a + line_m);
e1 = clamp_rgb(line_k * b + line_m);
}
void find_min_max_block(const unorm8_t texels[BLOCK_TEXEL_COUNT],
vec3f_t line_k,
vec3f_t line_m,
vec3f_t& e0,
vec3f_t& e1) {
find_min_max(texels, BLOCK_TEXEL_COUNT, line_k, line_m, e0, e1);
}
#endif // ASTC_ENDPOINTS_MIN_MAX_H_

View File

@ -0,0 +1,59 @@
#include <cstddef>
#include "colors.h"
#include "constants.h"
#include "dcheck.h"
#include "endpoints_principal_components.h"
#include "matrix.h"
#include "vector.h"
vec3f_t mean(const unorm8_t texels[BLOCK_TEXEL_COUNT], size_t count) {
vec3i_t sum(0, 0, 0);
for (size_t i = 0; i < count; ++i) {
sum = sum + to_vec3i(texels[i]);
}
return to_vec3f(sum) / static_cast<float>(count);
}
void subtract(const unorm8_t texels[BLOCK_TEXEL_COUNT],
size_t count,
vec3f_t v,
vec3f_t output[BLOCK_TEXEL_COUNT]) {
for (size_t i = 0; i < count; ++i) {
output[i] = to_vec3f(texels[i]) - v;
}
}
mat3x3f_t covariance(const vec3f_t m[BLOCK_TEXEL_COUNT], size_t count) {
mat3x3f_t cov;
for (size_t i = 0; i < 3; ++i) {
for (size_t j = 0; j < 3; ++j) {
float s = 0;
for (size_t k = 0; k < count; ++k) {
s += m[k].components[i] * m[k].components[j];
}
cov.at(i, j) = s / static_cast<float>(count - 1);
}
}
return cov;
}
void principal_component_analysis(const unorm8_t texels[BLOCK_TEXEL_COUNT],
size_t count,
vec3f_t& line_k,
vec3f_t& line_m) {
// Since we are working with fixed sized blocks count we can cap count. This
// avoids dynamic allocation.
DCHECK(count <= BLOCK_TEXEL_COUNT);
line_m = mean(texels, count);
vec3f_t n[BLOCK_TEXEL_COUNT];
subtract(texels, count, line_m, n);
mat3x3f_t w = covariance(n, count);
eigen_vector(w, line_k);
}

View File

@ -0,0 +1,22 @@
#ifndef ASTC_ENDPOINTS_PRINCIPAL_COMPONENTS_H_
#define ASTC_ENDPOINTS_PRINCIPAL_COMPONENTS_H_
#include <cstddef>
#include "colors.h"
#include "constants.h"
#include "vector.h"
void principal_component_analysis(const unorm8_t texels[BLOCK_TEXEL_COUNT],
size_t count,
vec3f_t& line_k,
vec3f_t& line_m);
inline void principal_component_analysis_block(
const unorm8_t texels[BLOCK_TEXEL_COUNT],
vec3f_t& line_k,
vec3f_t& line_m) {
principal_component_analysis(texels, BLOCK_TEXEL_COUNT, line_k, line_m);
}
#endif // ASTC_ENDPOINTS_PRINCIPAL_COMPONENTS_H_

View File

@ -0,0 +1,37 @@
#ifndef ASTC_ENDPOINTS_QUANTIZE_H_
#define ASTC_ENDPOINTS_QUANTIZE_H_
#include <cstdint>
#include "dcheck.h"
#include "range.h"
#include "tables_color_quantization.h"
#include "vector.h"
uint8_t quantize_color(range_t quant, int c) {
DCHECK(c >= 0 && c <= 255);
return color_quantize_table[quant][c];
}
vec3i_t quantize_color(range_t quant, vec3i_t c) {
vec3i_t result;
result.r = color_quantize_table[quant][c.r];
result.g = color_quantize_table[quant][c.g];
result.b = color_quantize_table[quant][c.b];
return result;
}
uint8_t unquantize_color(range_t quant, int c) {
DCHECK(c >= 0 && c <= 255);
return color_unquantize_table[quant][c];
}
vec3i_t unquantize_color(range_t quant, vec3i_t c) {
vec3i_t result;
result.r = color_unquantize_table[quant][c.r];
result.g = color_unquantize_table[quant][c.g];
result.b = color_unquantize_table[quant][c.b];
return result;
}
#endif // ASTC_ENDPOINTS_QUANTIZE_H_

View File

@ -0,0 +1,212 @@
#ifndef ASTC_INTEGER_SEQUENCE_ENCODING_H_
#define ASTC_INTEGER_SEQUENCE_ENCODING_H_
#include <cstddef>
#include <cstdint>
#include "bitmanip.h"
#include "dcheck.h"
#include "tables_integer_sequence_encoding.h"
#include "range.h"
/**
* Table that describes the number of trits or quints along with bits required
* for storing each range.
*/
const uint8_t bits_trits_quints_table[RANGE_MAX][3] = {
{1, 0, 0}, // RANGE_2
{0, 1, 0}, // RANGE_3
{2, 0, 0}, // RANGE_4
{0, 0, 1}, // RANGE_5
{1, 1, 0}, // RANGE_6
{3, 0, 0}, // RANGE_8
{1, 0, 1}, // RANGE_10
{2, 1, 0}, // RANGE_12
{4, 0, 0}, // RANGE_16
{2, 0, 1}, // RANGE_20
{3, 1, 0}, // RANGE_24
{5, 0, 0}, // RANGE_32
{3, 0, 1}, // RANGE_40
{4, 1, 0}, // RANGE_48
{6, 0, 0}, // RANGE_64
{4, 0, 1}, // RANGE_80
{5, 1, 0}, // RANGE_96
{7, 0, 0}, // RANGE_128
{5, 0, 1}, // RANGE_160
{6, 1, 0}, // RANGE_192
{8, 0, 0} // RANGE_256
};
/**
* Encode a group of 5 numbers using trits and bits.
*/
inline void encode_trits(size_t bits,
uint8_t b0,
uint8_t b1,
uint8_t b2,
uint8_t b3,
uint8_t b4,
bitwriter& writer) {
uint8_t t0, t1, t2, t3, t4;
uint8_t m0, m1, m2, m3, m4;
split_high_low(b0, bits, t0, m0);
split_high_low(b1, bits, t1, m1);
split_high_low(b2, bits, t2, m2);
split_high_low(b3, bits, t3, m3);
split_high_low(b4, bits, t4, m4);
DCHECK(t0 < 3);
DCHECK(t1 < 3);
DCHECK(t2 < 3);
DCHECK(t3 < 3);
DCHECK(t4 < 3);
uint8_t packed = integer_from_trits[t4][t3][t2][t1][t0];
writer.write8(m0, bits);
writer.write8(getbits(packed, 1, 0), 2);
writer.write8(m1, bits);
writer.write8(getbits(packed, 3, 2), 2);
writer.write8(m2, bits);
writer.write8(getbits(packed, 4, 4), 1);
writer.write8(m3, bits);
writer.write8(getbits(packed, 6, 5), 2);
writer.write8(m4, bits);
writer.write8(getbits(packed, 7, 7), 1);
}
/**
* Encode a group of 3 numbers using quints and bits.
*/
inline void encode_quints(size_t bits,
uint8_t b0,
uint8_t b1,
uint8_t b2,
bitwriter& writer) {
uint8_t q0, q1, q2;
uint8_t m0, m1, m2;
split_high_low(b0, bits, q0, m0);
split_high_low(b1, bits, q1, m1);
split_high_low(b2, bits, q2, m2);
DCHECK(q0 < 5);
DCHECK(q1 < 5);
DCHECK(q2 < 5);
uint8_t packed = integer_from_quints[q2][q1][q0];
writer.write8(m0, bits);
writer.write8(getbits(packed, 2, 0), 3);
writer.write8(m1, bits);
writer.write8(getbits(packed, 4, 3), 2);
writer.write8(m2, bits);
writer.write8(getbits(packed, 6, 5), 2);
}
/**
* Encode a sequence of numbers using using one trit and a custom number of
* bits per number.
*/
inline void encode_trits(const uint8_t* numbers,
size_t count,
bitwriter& writer,
size_t bits) {
for (size_t i = 0; i < count; i += 5) {
uint8_t b0 = numbers[i + 0];
uint8_t b1 = i + 1 >= count ? 0 : numbers[i + 1];
uint8_t b2 = i + 2 >= count ? 0 : numbers[i + 2];
uint8_t b3 = i + 3 >= count ? 0 : numbers[i + 3];
uint8_t b4 = i + 4 >= count ? 0 : numbers[i + 4];
encode_trits(bits, b0, b1, b2, b3, b4, writer);
}
}
/**
* Encode a sequence of numbers using one quint and the custom number of bits
* per number.
*/
inline void encode_quints(const uint8_t* numbers,
size_t count,
bitwriter& writer,
size_t bits) {
for (size_t i = 0; i < count; i += 3) {
uint8_t b0 = numbers[i + 0];
uint8_t b1 = i + 1 >= count ? 0 : numbers[i + 1];
uint8_t b2 = i + 2 >= count ? 0 : numbers[i + 2];
encode_quints(bits, b0, b1, b2, writer);
}
}
/**
* Encode a sequence of numbers using binary representation with the selected
* bit count.
*/
inline void encode_binary(const uint8_t* numbers,
size_t count,
bitwriter& writer,
size_t bits) {
DCHECK(count > 0);
for (size_t i = 0; i < count; ++i) {
writer.write8(numbers[i], bits);
}
}
/**
* Encode a sequence of numbers in a specific range using the binary integer
* sequence encoding. The numbers are assumed to be in the correct range and
* the memory we are writing to is assumed to be zero-initialized.
*/
inline void integer_sequence_encode(const uint8_t* numbers,
size_t count,
range_t range,
bitwriter writer) {
#ifndef NDEBUG
for (size_t i = 0; i < count; ++i) {
DCHECK(numbers[i] <= range_max_table[range]);
}
#endif
size_t bits = bits_trits_quints_table[range][0];
size_t trits = bits_trits_quints_table[range][1];
size_t quints = bits_trits_quints_table[range][2];
if (trits == 1) {
encode_trits(numbers, count, writer, bits);
} else if (quints == 1) {
encode_quints(numbers, count, writer, bits);
} else {
encode_binary(numbers, count, writer, bits);
}
}
inline void integer_sequence_encode(const uint8_t* numbers,
size_t count,
range_t range,
uint8_t* output) {
integer_sequence_encode(numbers, count, range, bitwriter(output));
}
/**
* Compute the number of bits required to store a number of items in a specific
* range using the binary integer sequence encoding.
*/
inline size_t compute_ise_bitcount(size_t items, range_t range) {
size_t bits = bits_trits_quints_table[range][0];
size_t trits = bits_trits_quints_table[range][1];
size_t quints = bits_trits_quints_table[range][2];
if (trits) {
return ((8 + 5 * bits) * items + 4) / 5;
}
if (quints) {
return ((7 + 3 * bits) * items + 2) / 3;
}
return items * bits;
}
#endif // ASTC_INTEGER_SEQUENCE_ENCODING_H_

View File

@ -0,0 +1,10 @@
#include "matrix.h"
void eigen_vector(const mat3x3f_t& a, vec3f_t& eig) {
vec3f_t b = signorm(vec3f_t(1, 5, 2)); // FIXME: Magic number
for (size_t i = 0; i < 8; ++i) {
b = signorm(a * b);
}
eig = b;
}

View File

@ -0,0 +1,45 @@
#ifndef ASTC_MATRIX_H_
#define ASTC_MATRIX_H_
#include <cstddef>
#include "vector.h"
struct mat3x3f_t {
public:
mat3x3f_t() {}
mat3x3f_t(float m00,
float m01,
float m02,
float m10,
float m11,
float m12,
float m20,
float m21,
float m22) {
m[0] = vec3f_t(m00, m01, m02);
m[1] = vec3f_t(m10, m11, m12);
m[2] = vec3f_t(m20, m21, m22);
}
const vec3f_t& row(size_t i) const { return m[i]; }
float& at(size_t i, size_t j) { return m[i].components[j]; }
const float& at(size_t i, size_t j) const { return m[i].components[j]; }
private:
vec3f_t m[3];
};
inline vec3f_t operator*(const mat3x3f_t& a, vec3f_t b) {
vec3f_t tmp;
tmp.x = dot(a.row(0), b);
tmp.y = dot(a.row(1), b);
tmp.z = dot(a.row(2), b);
return tmp;
}
void eigen_vector(const mat3x3f_t& a, vec3f_t& eig);
#endif // ASTC_MATRIX_H_

View File

@ -0,0 +1,57 @@
tables_color_quantization = custom_target(
'gen-color-quantization',
input: [],
output: ['tables_color_quantization.h'],
command: [codegen, 'quantize', '@OUTPUT0@']
)
tables_data_size = custom_target(
'gen-data-size',
input: [],
output: ['tables_data_size.h'],
command: [codegen, 'datasize', '@OUTPUT0@']
)
tables_integer_sequence_encoding = custom_target(
'gen-integer_sequence_encoding-tables',
input: [],
output: ['tables_integer_sequence_encoding.h'],
command: [codegen, 'bise', '@OUTPUT0@']
)
astc_sources = [
'bitmanip.h',
'colors.h',
'compress_block.cc',
'compress_block.h',
'compress_texture.cc',
'compress_texture.h',
'constants.h',
'data_size.h',
'dcheck.h',
'endpoints.h',
'endpoints_bounding_box.h',
'endpoints_encode.h',
'endpoints_min_max.h',
'endpoints_principal_components.cc',
'endpoints_principal_components.h',
'endpoints_quantize.h',
'integer_sequence_encoding.h',
'matrix.cc',
'matrix.h',
'misc.h',
'range.h',
'store_block.h',
'vector.h',
'weights_quantize.h',
'weights_quantize_table.h',
tables_color_quantization,
tables_data_size,
tables_integer_sequence_encoding,
]
astc = static_library(
'astc',
sources: astc_sources,
include_directories: incdir
)

View File

@ -0,0 +1,23 @@
#ifndef ASTC_MISC_H_
#define ASTC_MISC_H_
#include <math.h>
template <typename T>
T clamp(T a, T b, T x) {
if (x < a) {
return a;
}
if (x > b) {
return b;
}
return x;
}
inline bool approx_equal(float x, float y, float epsilon) {
return fabs(x - y) < epsilon;
}
#endif // ASTC_MISC_H_

View File

@ -0,0 +1,42 @@
#ifndef ASTC_RANGE_H_
#define ASTC_RANGE_H_
#include <cstdint>
/**
* Define normalized (starting at zero) numeric ranges that can be represented
* with 8 bits or less.
*/
enum range_t {
RANGE_2,
RANGE_3,
RANGE_4,
RANGE_5,
RANGE_6,
RANGE_8,
RANGE_10,
RANGE_12,
RANGE_16,
RANGE_20,
RANGE_24,
RANGE_32,
RANGE_40,
RANGE_48,
RANGE_64,
RANGE_80,
RANGE_96,
RANGE_128,
RANGE_160,
RANGE_192,
RANGE_256,
RANGE_MAX
};
/**
* Table of maximum value for each range, minimum is always zero.
*/
const uint8_t range_max_table[RANGE_MAX] = {1, 2, 3, 4, 5, 7, 9,
11, 15, 19, 23, 31, 39, 47,
63, 79, 95, 127, 159, 191, 255};
#endif // ASTC_RANGE_H_

View File

@ -0,0 +1,113 @@
#ifndef ASTC_STORE_BLOCK_H_
#define ASTC_STORE_BLOCK_H_
#include <cstddef>
#include <cstdint>
#include "bitmanip.h"
#include "colors.h"
#include "constants.h"
#include "dcheck.h"
#include "endpoints.h"
#include "integer_sequence_encoding.h"
#include "range.h"
struct PhysicalBlock {
uint8_t data[BLOCK_BYTES];
};
inline void void_extent_to_physical(unorm16_t color, PhysicalBlock* pb) {
pb->data[0] = 0xFC;
pb->data[1] = 0xFD;
pb->data[2] = 0xFF;
pb->data[3] = 0xFF;
pb->data[4] = 0xFF;
pb->data[5] = 0xFF;
pb->data[6] = 0xFF;
pb->data[7] = 0xFF;
setbytes2(pb->data, 8, color.channels.r);
setbytes2(pb->data, 10, color.channels.g);
setbytes2(pb->data, 12, color.channels.b);
setbytes2(pb->data, 14, color.channels.a);
}
inline void symbolic_to_physical(
color_endpoint_mode_t color_endpoint_mode,
range_t endpoint_quant,
range_t weight_quant,
size_t partition_count,
size_t partition_index,
const uint8_t endpoint_ise[MAXIMUM_ENCODED_COLOR_ENDPOINT_BYTES],
// FIXME: +1 needed here because orbits_8ptr breaks when the offset reaches
// the last byte which always happens if the weight mode is RANGE_32.
const uint8_t weights_ise[MAXIMUM_ENCODED_WEIGHT_BYTES + 1],
PhysicalBlock* pb) {
DCHECK(weight_quant <= RANGE_32);
DCHECK(endpoint_quant < RANGE_MAX);
DCHECK(color_endpoint_mode < CEM_MAX);
DCHECK(partition_count == 1 || partition_index < 1024);
DCHECK(partition_count >= 1 && partition_count <= 4);
DCHECK(compute_ise_bitcount(BLOCK_TEXEL_COUNT, weight_quant) <
MAXIMUM_ENCODED_WEIGHT_BITS);
size_t n = BLOCK_WIDTH;
size_t m = BLOCK_HEIGHT;
static const bool h_table[RANGE_32 + 1] = {0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1};
static const uint8_t r_table[RANGE_32 + 1] = {0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
bool h = h_table[weight_quant];
size_t r = r_table[weight_quant];
// Use the first row of Table 11 in the ASTC specification. Beware that
// this has to be changed if another block-size is used.
size_t a = m - 2;
size_t b = n - 4;
bool d = 0; // TODO: dual plane
bool multi_part = partition_count > 1;
size_t part_value = partition_count - 1;
size_t part_index = multi_part ? partition_index : 0;
size_t cem_offset = multi_part ? 23 : 13;
size_t ced_offset = multi_part ? 29 : 17;
size_t cem_bits = multi_part ? 6 : 4;
size_t cem = color_endpoint_mode;
cem = multi_part ? cem << 2 : cem;
// Block mode
orbits8_ptr(pb->data, 0, getbit(r, 1), 1);
orbits8_ptr(pb->data, 1, getbit(r, 2), 1);
orbits8_ptr(pb->data, 2, 0, 1);
orbits8_ptr(pb->data, 3, 0, 1);
orbits8_ptr(pb->data, 4, getbit(r, 0), 1);
orbits8_ptr(pb->data, 5, a, 2);
orbits8_ptr(pb->data, 7, b, 2);
orbits8_ptr(pb->data, 9, h, 1);
orbits8_ptr(pb->data, 10, d, 1);
// Partitions
orbits8_ptr(pb->data, 11, part_value, 2);
orbits16_ptr(pb->data, 13, part_index, 10);
// CEM
orbits8_ptr(pb->data, cem_offset, cem, cem_bits);
copy_bytes(endpoint_ise, MAXIMUM_ENCODED_COLOR_ENDPOINT_BYTES, pb->data,
ced_offset);
reverse_bytes(weights_ise, MAXIMUM_ENCODED_WEIGHT_BYTES, pb->data + 15);
}
#endif // ASTC_STORE_BLOCK_H_

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
#ifndef ASTC_TABLES_DATA_SIZE_H_
#define ASTC_TABLES_DATA_SIZE_H_
const int8_t color_endpoint_range_table[2][12][16] = {{{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},{20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20},{20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20},{20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20},{20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20},{20,20,20,20,20,20,20,20,20,20,20,20,19,19,19,19},{20,20,20,20,20,20,20,20,20,20,20,20,17,17,17,17},{20,20,20,20,20,20,20,20,20,20,20,20,16,16,16,16},{20,20,20,20,20,20,20,20,19,19,19,19,13,13,13,13},{20,20,20,20,20,20,20,20,16,16,16,16,11,11,11,11},{20,20,20,20,20,20,20,20,14,14,14,14,10,10,10,10},{20,20,20,20,19,19,19,19,11,11,11,11,7,7,7,7}},{{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},{20,20,20,20,20,20,20,20,14,14,14,14,9,9,9,9},{20,20,20,20,20,20,20,20,12,12,12,12,8,8,8,8},{20,20,20,20,19,19,19,19,11,11,11,11,7,7,7,7},{20,20,20,20,17,17,17,17,10,10,10,10,6,6,6,6},{20,20,20,20,15,15,15,15,8,8,8,8,5,5,5,5},{20,20,20,20,13,13,13,13,7,7,7,7,4,4,4,4},{20,20,20,20,11,11,11,11,6,6,6,6,3,3,3,3},{20,20,20,20,9,9,9,9,4,4,4,4,2,2,2,2},{17,17,17,17,7,7,7,7,3,3,3,3,1,1,1,1},{14,14,14,14,5,5,5,5,2,2,2,2,0,0,0,0},{10,10,10,10,3,3,3,3,0,0,0,0,0,0,0,0}}};
#endif

View File

@ -0,0 +1,7 @@
#ifndef ASTC_TABLES_INTEGER_SEQUENCE_ENCODING_H_
#define ASTC_TABLES_INTEGER_SEQUENCE_ENCODING_H_
const uint8_t integer_from_trits[3][3][3][3][3] = {{{{{0,1,2},{4,5,6},{8,9,10}},{{16,17,18},{20,21,22},{24,25,26}},{{3,7,15},{19,23,27},{12,13,14}}},{{{32,33,34},{36,37,38},{40,41,42}},{{48,49,50},{52,53,54},{56,57,58}},{{35,39,47},{51,55,59},{44,45,46}}},{{{64,65,66},{68,69,70},{72,73,74}},{{80,81,82},{84,85,86},{88,89,90}},{{67,71,79},{83,87,91},{76,77,78}}}},{{{{128,129,130},{132,133,134},{136,137,138}},{{144,145,146},{148,149,150},{152,153,154}},{{131,135,143},{147,151,155},{140,141,142}}},{{{160,161,162},{164,165,166},{168,169,170}},{{176,177,178},{180,181,182},{184,185,186}},{{163,167,175},{179,183,187},{172,173,174}}},{{{192,193,194},{196,197,198},{200,201,202}},{{208,209,210},{212,213,214},{216,217,218}},{{195,199,207},{211,215,219},{204,205,206}}}},{{{{96,97,98},{100,101,102},{104,105,106}},{{112,113,114},{116,117,118},{120,121,122}},{{99,103,111},{115,119,123},{108,109,110}}},{{{224,225,226},{228,229,230},{232,233,234}},{{240,241,242},{244,245,246},{248,249,250}},{{227,231,239},{243,247,251},{236,237,238}}},{{{28,29,30},{60,61,62},{92,93,94}},{{156,157,158},{188,189,190},{220,221,222}},{{31,63,127},{159,191,255},{252,253,254}}}}};
const uint8_t integer_from_quints[5][5][5] = {{{0,1,2,3,4},{8,9,10,11,12},{16,17,18,19,20},{24,25,26,27,28},{5,13,21,29,6}},{{32,33,34,35,36},{40,41,42,43,44},{48,49,50,51,52},{56,57,58,59,60},{37,45,53,61,14}},{{64,65,66,67,68},{72,73,74,75,76},{80,81,82,83,84},{88,89,90,91,92},{69,77,85,93,22}},{{96,97,98,99,100},{104,105,106,107,108},{112,113,114,115,116},{120,121,122,123,124},{101,109,117,125,30}},{{102,103,70,71,38},{110,111,78,79,46},{118,119,86,87,54},{126,127,94,95,62},{39,47,55,63,31}}};
#endif

View File

@ -0,0 +1,148 @@
#ifndef ASTC_VECTOR_H_
#define ASTC_VECTOR_H_
#include <algorithm>
#include <cmath>
#include "dcheck.h"
template <typename T>
union vec3_t {
public:
vec3_t() {}
vec3_t(T x_, T y_, T z_) : x(x_), y(y_), z(z_) {}
struct {
T x, y, z;
};
struct {
T r, g, b;
};
T components[3];
};
typedef vec3_t<float> vec3f_t;
typedef vec3_t<int> vec3i_t;
template <typename T>
vec3_t<T> operator+(vec3_t<T> a, vec3_t<T> b) {
vec3_t<T> result;
result.x = a.x + b.x;
result.y = a.y + b.y;
result.z = a.z + b.z;
return result;
}
template <typename T>
vec3_t<T> operator-(vec3_t<T> a, vec3_t<T> b) {
vec3_t<T> result;
result.x = a.x - b.x;
result.y = a.y - b.y;
result.z = a.z - b.z;
return result;
}
template <typename T>
vec3_t<T> operator*(vec3_t<T> a, vec3_t<T> b) {
vec3_t<T> result;
result.x = a.x * b.x;
result.y = a.y * b.y;
result.z = a.z * b.z;
return result;
}
template <typename T>
vec3_t<T> operator*(vec3_t<T> a, T b) {
vec3_t<T> result;
result.x = a.x * b;
result.y = a.y * b;
result.z = a.z * b;
return result;
}
template <typename T>
vec3_t<T> operator/(vec3_t<T> a, T b) {
vec3_t<T> result;
result.x = a.x / b;
result.y = a.y / b;
result.z = a.z / b;
return result;
}
template <typename T>
vec3_t<T> operator/(vec3_t<T> a, vec3_t<T> b) {
vec3_t<T> result;
result.x = a.x / b.x;
result.y = a.y / b.y;
result.z = a.z / b.z;
return result;
}
template <typename T>
bool operator==(vec3_t<T> a, vec3_t<T> b) {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
template <typename T>
bool operator!=(vec3_t<T> a, vec3_t<T> b) {
return a.x != b.x || a.y != b.y || a.z != b.z;
}
template <typename T>
T dot(vec3_t<T> a, vec3_t<T> b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
template <typename T>
T quadrance(vec3_t<T> a) {
return dot(a, a);
}
template <typename T>
T norm(vec3_t<T> a) {
return static_cast<T>(sqrt(quadrance(a)));
}
template <typename T>
T distance(vec3_t<T> a, vec3_t<T> b) {
return norm(a - b);
}
template <typename T>
T qd(vec3_t<T> a, vec3_t<T> b) {
return quadrance(a - b);
}
template <typename T>
vec3_t<T> signorm(vec3_t<T> a) {
T x = norm(a);
DCHECK(x != 0.0);
return a / x;
}
template <typename T>
vec3_t<T> vecmin(vec3_t<T> a, vec3_t<T> b) {
vec3_t<T> result;
result.x = std::min(a.x, b.x);
result.y = std::min(a.y, b.y);
result.z = std::min(a.z, b.z);
return result;
}
template <typename T>
vec3_t<T> vecmax(vec3_t<T> a, vec3_t<T> b) {
vec3_t<T> result;
result.x = std::max(a.x, b.x);
result.y = std::max(a.y, b.y);
result.z = std::max(a.z, b.z);
return result;
}
template <typename T>
T qd_to_line(vec3_t<T> m, vec3_t<T> k, T kk, vec3_t<T> p) {
T t = dot(p - m, k) / kk;
vec3_t<T> q = k * t + m;
return qd(p, q);
}
#endif // ASTC_VECTOR_H_

View File

@ -0,0 +1,88 @@
#ifndef ASTC_WEIGHTS_QUANTIZE_H_
#define ASTC_WEIGHTS_QUANTIZE_H_
#include <cstddef>
#include <cstdint>
#include "colors.h"
#include "constants.h"
#include "dcheck.h"
#include "misc.h"
#include "range.h"
#include "vector.h"
#include "weights_quantize_table.h"
uint8_t quantize_weight(range_t weight_quant, size_t weight) {
DCHECK(weight_quant <= RANGE_32);
DCHECK(weight <= 1024);
return weight_quantize_table[weight_quant][weight];
}
/**
* Project a texel to a line and quantize the result in 1 dimension.
*
* The line is defined by t=k*x + m. This function calculates and quantizes x
* by projecting n=t-m onto k, x=|n|/|k|. Since k and m is derived from the
* minimum and maximum of all texel values the result will be in the range [0,
* 1].
*
* To quantize the result using the weight_quantize_table the value needs to
* be extended to the range [0, 1024].
*
* @param k the derivative of the line
* @param m the minimum endpoint
* @param t the texel value
*/
size_t project(size_t k, size_t m, size_t t) {
DCHECK(k > 0);
return size_t((t - m) * 1024) / k;
}
/**
* Project a texel to a line and quantize the result in 3 dimensions.
*/
size_t project(vec3i_t k, int kk, vec3i_t m, vec3i_t t) {
DCHECK(kk > 0);
return static_cast<size_t>(clamp(0, 1024, dot(t - m, k) * 1024 / kk));
}
void calculate_quantized_weights_luminance(
const uint8_t texels[BLOCK_TEXEL_COUNT],
range_t quant,
uint8_t l0,
uint8_t l1,
uint8_t weights[BLOCK_TEXEL_COUNT]) {
DCHECK(l0 < l1);
size_t k = l1 - l0;
size_t m = l0;
for (size_t i = 0; i < BLOCK_TEXEL_COUNT; ++i) {
size_t t = static_cast<size_t>(texels[i]);
weights[i] = quantize_weight(quant, project(k, m, t));
}
}
void calculate_quantized_weights_rgb(const unorm8_t texels[BLOCK_TEXEL_COUNT],
range_t quant,
vec3i_t e0,
vec3i_t e1,
uint8_t weights[BLOCK_TEXEL_COUNT]) {
if (e0 == e1) {
for (size_t i = 0; i < BLOCK_TEXEL_COUNT; ++i) {
weights[i] = 0; // quantize_weight(quant, 0) is always 0
}
} else {
vec3i_t k = e1 - e0;
vec3i_t m = e0;
int kk = dot(k, k);
for (size_t i = 0; i < BLOCK_TEXEL_COUNT; ++i) {
weights[i] =
quantize_weight(quant, project(k, kk, m, to_vec3i(texels[i])));
}
}
}
#endif // ASTC_WEIGHTS_QUANTIZE_H_

View File

@ -0,0 +1,566 @@
#ifndef ASTC_WEIGHTS_QUANTIZE_TABLE_H_
#define ASTC_WEIGHTS_QUANTIZE_TABLE_H_
#include <cstdint>
// FIXME: This is copied from ARM-code
const uint8_t weight_quantize_table[12][1025] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31}};
#endif // ASTC_WEIGHTS_QUANTIZE_TABLE_H_

View File

@ -0,0 +1,74 @@
#include <sys/time.h>
#include "astc.h"
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "compress_texture.h"
#include "constants.h"
#include "bgra.h"
#include "compressed.h"
int64_t usecs_passed(const timeval& t1, const timeval& t2) {
return (t2.tv_sec - t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec);
}
void compress_astc(const BgraImage& image, CompressedImage* compressed) {
compress_texture(reinterpret_cast<uint8_t*>(image.buffer), compressed->buffer, static_cast<int>(image.width), static_cast<int>(image.height));
}
/*int main(int argc, const char** argv) {
if (argc < 3 || argc > 4) {
fprintf(stderr, "Usage: %s [-q | --quiet] INPUT OUTPUT\n", argv[0]);
return 1;
}
bool quiet = false;
const char* input = nullptr;
const char* output = nullptr;
int i = 1;
if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) {
quiet = true;
++i;
}
input = argv[i];
output = argv[i + 1];
try {
BgraImage image = ReadTGAFile(input);
if (image.width % BLOCK_WIDTH != 0 || image.height % BLOCK_HEIGHT != 0) {
fprintf(stderr,
"Error: image size (%ldx%ld) not a multiple of block size "
"(%ldx%ld)\n",
image.width, image.height, BLOCK_WIDTH, BLOCK_HEIGHT);
return 1;
}
CompressedImage compressed(image.width, image.height, BLOCK_WIDTH,
BLOCK_HEIGHT, BLOCK_BYTES);
if (quiet) {
compress_astc(image, &compressed);
} else {
timeval t1;
gettimeofday(&t1, NULL);
compress_astc(image, &compressed);
timeval t2;
gettimeofday(&t2, NULL);
fprintf(stdout, "Time passed: %ldus\n", usecs_passed(t1, t2));
}
WriteASTCFile(compressed, output);
} catch (const char* err) {
fprintf(stderr, "Error: %s\n", err);
return 1;
}
return 0;
}*/

View File

@ -0,0 +1,9 @@
#ifndef astc_h
#define astc_h
#include "bgra.h"
#include "compressed.h"
void compress_astc(const BgraImage& image, CompressedImage* compressed);
#endif /* astc_h */

View File

@ -0,0 +1,18 @@
#include "bgra.h"
#include <fstream>
struct TGAHeader {
uint8_t id_length;
uint8_t color_map_type;
uint8_t image_type;
uint8_t first_entry_index[2];
uint8_t color_map_length[2];
uint8_t color_map_entry_size;
uint8_t origin_x[2], origin_y[2];
uint8_t width[2], height[2];
uint8_t pixel_depth;
uint8_t image_descriptor;
};

View File

@ -0,0 +1,38 @@
#ifndef IMAGE_BGRA_H_
#define IMAGE_BGRA_H_
#include <cstddef>
#include "color.h"
class BgraImage {
public:
BgraImage(size_t width_, size_t height_, uint8_t *bytes)
: width(width_),
height(height_),
pixel_count(width_ * height_),
buffer_size(pixel_count * sizeof(bgra8_t)),
buffer((bgra8_t *)bytes) {}
BgraImage(BgraImage&& other)
: width(other.width),
height(other.height),
buffer_size(other.buffer_size),
buffer(other.buffer) {
other.buffer = nullptr;
}
BgraImage(const BgraImage&) = delete;
BgraImage& operator=(const BgraImage&) = delete;
~BgraImage() {
}
size_t width, height;
size_t pixel_count;
size_t buffer_size;
bgra8_t* buffer;
};
#endif // IMAGE_BGRA_H_

View File

@ -0,0 +1,37 @@
#ifndef IMAGE_COLOR_H_
#define IMAGE_COLOR_H_
#include <cstdint>
union rgba8_t {
struct type {
uint8_t r, g, b, a;
} channels;
uint32_t bits;
};
union bgra8_t {
struct type {
uint8_t b, g, r, a;
} channels;
uint32_t bits;
};
inline bgra8_t swap_red_blue(rgba8_t color) {
bgra8_t output;
output.channels.r = color.channels.r;
output.channels.g = color.channels.g;
output.channels.b = color.channels.b;
output.channels.a = color.channels.a;
return output;
}
inline rgba8_t swap_red_blue(bgra8_t color) {
rgba8_t output;
output.channels.r = color.channels.r;
output.channels.g = color.channels.g;
output.channels.b = color.channels.b;
output.channels.a = color.channels.a;
return output;
}
#endif // IMAGE_COLOR_H_

View File

@ -0,0 +1,44 @@
#include "compressed.h"
#include <fstream>
static int MAGIC_FILE_CONSTANT = 0x5CA1AB13;
struct ASTCHeader {
uint8_t magic[4];
uint8_t blockdim_x;
uint8_t blockdim_y;
uint8_t blockdim_z;
uint8_t xsize[3];
uint8_t ysize[3];
uint8_t zsize[3];
};
void WriteASTCFile(const CompressedImage& compressed, const char* file_path) {
std::ofstream file(file_path, std::ios::binary);
if (file.fail()) {
throw "could not open file for writing";
}
ASTCHeader hdr;
hdr.magic[0] = static_cast<uint8_t>(MAGIC_FILE_CONSTANT & 0xFF);
hdr.magic[1] = static_cast<uint8_t>((MAGIC_FILE_CONSTANT >> 8) & 0xFF);
hdr.magic[2] = static_cast<uint8_t>((MAGIC_FILE_CONSTANT >> 16) & 0xFF);
hdr.magic[3] = static_cast<uint8_t>((MAGIC_FILE_CONSTANT >> 24) & 0xFF);
hdr.blockdim_x = static_cast<uint8_t>(compressed.xdim);
hdr.blockdim_y = static_cast<uint8_t>(compressed.ydim);
hdr.blockdim_z = 1;
hdr.xsize[0] = compressed.xsize & 0xFF;
hdr.xsize[1] = (compressed.xsize >> 8) & 0xFF;
hdr.xsize[2] = (compressed.xsize >> 16) & 0xFF;
hdr.ysize[0] = compressed.ysize & 0xFF;
hdr.ysize[1] = (compressed.ysize >> 8) & 0xFF;
hdr.ysize[2] = (compressed.ysize >> 16) & 0xFF;
hdr.zsize[0] = 1 & 0xFF;
hdr.zsize[1] = (1 >> 8) & 0xFF;
hdr.zsize[2] = (1 >> 16) & 0xFF;
file.write(reinterpret_cast<const char*>(&hdr), sizeof(ASTCHeader));
file.write(reinterpret_cast<const char*>(compressed.buffer),
static_cast<std::streamsize>(compressed.buffer_size));
}

View File

@ -0,0 +1,61 @@
#ifndef IMAGE_COMPRESSED_H_
#define IMAGE_COMPRESSED_H_
#include <cassert>
#include <cstddef>
#include <cstdint>
class CompressedImage {
public:
CompressedImage(size_t width,
size_t height,
size_t block_width,
size_t block_height,
size_t bytes_per_block_)
: xdim(block_width),
ydim(block_height),
xsize(width),
ysize(height),
xblocks(width / xdim),
yblocks(height / ydim),
block_count(yblocks * xblocks),
bytes_per_block(bytes_per_block_),
buffer_size(block_count * bytes_per_block),
buffer(new uint8_t[buffer_size]) {
assert(width % xdim == 0);
assert(height % ydim == 0);
}
CompressedImage(CompressedImage&& other)
: xdim(other.xdim),
ydim(other.ydim),
xsize(other.xsize),
ysize(other.ysize),
xblocks(other.xblocks),
yblocks(other.yblocks),
block_count(other.block_count),
bytes_per_block(other.bytes_per_block),
buffer_size(other.buffer_size),
buffer(other.buffer) {
other.buffer = nullptr;
}
CompressedImage(const CompressedImage&) = delete;
CompressedImage& operator=(const CompressedImage&) = delete;
~CompressedImage() { delete[] buffer; }
size_t xdim, ydim;
size_t xsize, ysize;
size_t xblocks, yblocks;
size_t block_count;
size_t bytes_per_block;
size_t buffer_size;
uint8_t* buffer;
};
void WriteASTCFile(const CompressedImage&, const char* file_path);
#endif // IMAGE_COMPRESSED_H_

View File

@ -0,0 +1,229 @@
from bitset import bitset
from range import *
import math
# Define the number of trits, quints and bits used for an encoded range, this
# table is indexed by N-1 where N is the number of elements in a range.
TRITS_QUINTS_BITS_TABLE = \
[
(0, 0, 1), # RANGE_2
(1, 0, 0), # RANGE_3
(0, 0, 2), # RANGE_4
(0, 1, 0), # RANGE_5
(1, 0, 1), # RANGE_6
(0, 0, 3), # RANGE_8
(0, 1, 1), # RANGE_10
(1, 0, 2), # RANGE_12
(0, 0, 4), # RANGE_16
(0, 1, 2), # RANGE_20
(1, 0, 3), # RANGE_24
(0, 0, 5), # RANGE_32
(0, 1, 3), # RANGE_40
(1, 0, 4), # RANGE_48
(0, 0, 6), # RANGE_64
(0, 1, 4), # RANGE_80
(1, 0, 5), # RANGE_96
(0, 0, 7), # RANGE_128
(0, 1, 5), # RANGE_160
(1, 0, 6), # RANGE_192
(0, 0, 8) # RANGE_256
]
def bits_bise_bitcount(items, bits):
"""
Compute the number of bits needed for regular binary encoding.
"""
assert items > 0 and bits > 0
return items * bits
def trits_bise_bitcount(items, bits):
"""
Compute the number of bits needed for trit-based encoding.
"""
assert items > 0 and bits >= 0
#return math.ceil((8.0 + 5.0*bits) * items / 5.0)
return math.ceil(8.0*items / 5.0 + bits*items)
def quints_bise_bitcount(items, bits):
"""
Compute the number of bits needed for quint-based encoding.
"""
assert items > 0 and bits >= 0
#return math.ceil((7.0 + 3.0*bits) * items / 3.0)
return math.ceil(7.0*items / 3.0 + bits*items)
def compute_bise_bitcount(items, quant):
"""
Compute the number of bits needed for the BISE stream.
"""
assert type(items) is int
assert type(quant) is int
assert items > 0
assert quant >= RANGE_2 and quant <= RANGE_256
trits, quints, bits = TRITS_QUINTS_BITS_TABLE[quant]
if trits == 0 and quints == 0:
return bits_bise_bitcount(items, bits)
elif trits != 0:
return trits_bise_bitcount(items, bits)
elif quints != 0:
return quints_bise_bitcount(items, bits)
else:
assert False
def last_index(lst, a):
last = -1
for i in range(len(lst)):
if a == lst[i]:
last = i
if last == -1:
raise ValueError("%s is not in the list" % repr(a))
return last
# From ASTC specification, decode the a encoded set of 5 trits.
def decode_trits(T):
assert isinstance(T, bitset)
assert T.size() == 8
t4 = -1
t3 = -1
t2 = -1
t1 = -1
C = bitset(5, 0)
if T.substr(4, 2) == bitset(3, 0b111):
C.set(4, T.get(7))
C.set(3, T.get(6))
C.set(2, T.get(5))
C.set(1, T.get(1))
C.set(0, T.get(0))
t4 = 2
t3 = 2
else:
C = T.substr(4, 0)
if T.substr(6, 5) == bitset(2, 0b11):
t4 = 2
t3 = T.get(7)
else:
t4 = T.get(7)
t3 = T.substr(6, 5).number()
if C.substr(1, 0) == bitset(2, 0b11):
t2 = 2
t1 = C.get(4)
t0 = bitset.from_args(C.get(3), C.get(2) & (not C.get(3))).number()
elif C.substr(3, 2) == bitset(2, 0b11):
t2 = 2
t1 = 2
t0 = C.substr(1, 0).number()
else:
t2 = C.get(4)
t1 = C.substr(3, 2).number()
t0 = bitset.from_args(C.get(1), C.get(0) & (not C.get(1))).number()
assert t4 >= 0 and t4 <= 2, t4
assert t3 >= 0 and t3 <= 2, t3
assert t2 >= 0 and t2 <= 2, t2
assert t1 >= 0 and t1 <= 2, t1
assert t0 >= 0 and t0 <= 2, t0
return (t0, t1, t2, t3, t4)
# From ASTC specification, decode a encoded set of 3 quints.
def decode_quints(Q):
assert Q.size() == 7
q2 = -1
q1 = -1
q0 = -1
if Q.substr(2, 1) == bitset(2, 0b11) and Q.substr(6, 5) == bitset(2, 0b00):
q2 = bitset.from_args(
Q.get(0), Q.get(4) & (not Q.get(0)), Q.get(3) & (not Q.get(0))).number()
q1 = 4
q0 = 4
else:
C = None
if Q.substr(2, 1) == bitset(2, 0b11):
q2 = 4
C = bitset.from_args(
Q.get(4),
Q.get(3),
not Q.get(6),
not Q.get(5),
Q.get(0))
else:
q2 = Q.substr(6, 5).number()
C = Q.substr(4, 0)
if C.substr(2, 0) == bitset(3, 0b101):
q1 = 4
q0 = C.substr(4, 3).number()
else:
q1 = C.substr(4, 3).number()
q0 = C.substr(2, 0).number()
assert q2 >= 0 and q2 <= 4, q2
assert q1 >= 0 and q1 <= 4, q1
assert q0 >= 0 and q0 <= 4, q0
return (q0, q1, q2)
# Generate table for trit decoding for all possible 8 bit numbers, [0, 255].
def trits_from_integer_table():
return [decode_trits(bitset(8, i)) for i in range(256)]
# Generate table for trit decoding by brute force searching the encoding table.
# Exhaustive search solution works because the search space is small.
def integer_from_trits_table(trits):
return \
[
[
[
[
[
last_index(trits, (t0, t1, t2, t3, t4))
for t0 in range(3)
]
for t1 in range(3)
]
for t2 in range(3)
]
for t3 in range(3)
]
for t4 in range(3)
]
# Generate table for quint encoding for all possible 7 bit numbers, [0, 127].
def quints_from_integer_table():
return [decode_quints(bitset(7, i)) for i in range(128)]
# Generate table for quint decoding by brute force searching the encoding
# table. Exhaustive search solution works because the search space is small.
def integer_from_quints_table(quints):
return \
[
[
[
last_index(quints, (q0, q1, q2))
for q0 in range(5)
]
for q1 in range(5)
]
for q2 in range(5)
]
if __name__ == "__main__":
trits_from_integer = trits_from_integer_table()
integer_from_trits = integer_from_trits_table(trits_from_integer)
quints_from_integer = quints_from_integer_table()
integer_from_quints = integer_from_quints_table(quints_from_integer)
print(trits_from_integer)
print(integer_from_trits)
print(quints_from_integer)
print(integer_from_quints)

View File

@ -0,0 +1,77 @@
# A bitset represents a fixed number of bits and have some helper methods for
# manipulating them.
class bitset:
def __init__(self, n, val):
assert n > 0
assert val < pow(2, n) # number should fit within the available bits
self.n = n
self.data = val
def size(self):
return self.n
def get(self, i):
assert i >= 0 and i < self.n
return (self.data >> i) & 1
def get_msb(self):
return self.get(self.n-1)
def get_lsb(self):
return self.get(0)
def set(self, i, x):
assert isinstance(x, bool) or isinstance(x, int)
assert i >= 0 and i < self.n
self.data ^= (-x ^ self.data) & (1 << i)
def substr(self, msb, lsb):
assert msb >= lsb
assert lsb >= 0
assert msb < self.n
count = msb - lsb + 1
newdata = self.data >> lsb & ((1 << count) - 1)
return bitset(count, newdata)
def number(self):
return self.data
def bits(self):
return [self.get(i) for i in range(self.n-1, -1, -1)]
def __eq__(self, other):
assert isinstance(other, bitset)
return self.n == other.n and self.data == other.data
def __str__(self):
return ''.join('1' if x else '0' for x in self.bits())
def __repr__(self):
return "bitset(%d, 0b%s)" % (self.n, self.__str__())
@staticmethod
def from_list(lst):
num = 0
n = len(lst) - 1
for x in lst:
assert x >= 0 and x <= 1
num = num | (x << n)
n = n - 1
return bitset(len(lst), num)
@staticmethod
def from_args(*args):
return bitset.from_list(list(args))
@staticmethod
def join(a, b):
assert isinstance(a, bitset)
assert isinstance(b, bitset)
count = a.size()+b.size()
number = b.number() | (a.number() << b.size())
return bitset(count, number)

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python
import bise
import datasize
import partitions
import quantize
import sys
def safe_head(lst, default):
try:
return lst[0]
except:
return default
def compute_dimensions(array):
if isinstance(array, list):
yield len(array)
yield from compute_dimensions(array[-1])
def pretty_array(element, fmt):
if isinstance(element, int):
return fmt % element
elif isinstance(element, tuple) or isinstance(element, list):
return pretty_array(iter(element), fmt)
else:
first = next(element)
out = "{"
out += pretty_array(first, fmt)
for x in element:
out += ","
out += pretty_array(x, fmt)
out += "}"
return out
def pretty_dimensions(dimensions):
out = ""
for dimension in dimensions:
out += "[" + str(dimension) + "]"
return out
header_template = """#ifndef {guard}
#define {guard}
{content}
#endif
"""
array_template = "const {type} {name}{dimensions} = {array};"
def build_header(guard, content):
return header_template.format(guard=guard, content=content)
def build_array(type, name, array):
return array_template.format(
name=name,
type=type,
dimensions=pretty_dimensions(compute_dimensions(array)),
array=pretty_array(array, "%d"),
)
def print_bise_tables(file):
trits_from_integer = bise.trits_from_integer_table()
integer_from_trits = bise.integer_from_trits_table(trits_from_integer)
quints_from_integer = bise.quints_from_integer_table()
integer_from_quints = bise.integer_from_quints_table(quints_from_integer)
file.write(build_header(
"ASTC_TABLES_INTEGER_SEQUENCE_ENCODING_H_",
build_array("uint8_t", "integer_from_trits", integer_from_trits) +
'\n' +
build_array("uint8_t", "integer_from_quints", integer_from_quints)
))
def print_partitions_tables(file):
table = list(partitions.compute_partitioning_table(
partition_count=2,
block_width=4,
block_height=4))
lookup_table = partitions.compute_partitioning_lookup_table(table)
file.write(build_header(
"ASTC_TABLES_PARTITIONS_H_",
build_array(
"uint16_t",
"partition_2_4x4_mask_table",
[part.partition_mask for part in table]
) + '\n' +
build_array(
"int16_t",
"partition_2_4x4_lookup_table",
[safe_head(parts, -1) for parts in lookup_table]
)
))
def print_data_size_table(file, block_width, block_height):
table = datasize.color_endpoint_range_table(block_width, block_height)
file.write(build_header(
"ASTC_TABLES_DATA_SIZE_H_",
build_array("int8_t", "color_endpoint_range_table", table)
))
def print_color_quantization_tables(file):
unquantize_table = quantize.color_unquantize_table()
quantize_table = quantize.color_quantize_table(unquantize_table)
file.write(build_header(
"ASTC_TABLES_COLOR_QUANTIZATION_H_",
build_array("uint8_t", "color_unquantize_table", unquantize_table) +
'\n' +
build_array("uint8_t", "color_quantize_table", quantize_table)
))
def print_usage(prog):
sys.stderr.write(
("Usage: %s COMMAND\n"
" Commands:\n"
" bise\n"
" partitions\n"
" datasize\n"
" quantize\n") % prog)
def main(kind, path):
file = open(path, 'w') if path != '-' else sys.stdout
if kind == "bise":
print_bise_tables(file)
elif kind == "partitions":
print_partitions_tables(file)
elif kind == "datasize":
print_data_size_table(file, 4, 4)
elif kind == "quantize":
print_color_quantization_tables(file)
else:
sys.stderr.write("Error: unknown mode {}\n".format(kind))
sys.exit(1)
if len(sys.argv) != 3:
print_usage(sys.argv[0])
else:
main(sys.argv[1], sys.argv[2])

View File

@ -0,0 +1,46 @@
from bise import compute_bise_bitcount
from datasize import data_size, cem_values_count, color_endpoint_range
from range import RANGE_CARDINALITY_TABLE
import sys
def print_data_size_info(block_width, block_height, cem, partitions,
weight_range):
config_bits, weight_bits, remaining_bits = data_size(
partitions=partitions,
single_cem=True,
block_width=block_width,
block_height=block_height,
block_depth=1,
dual_plane=False,
weight_range=weight_range
)
ce_values = cem_values_count(cem, partitions)
ce_range = color_endpoint_range(cem, remaining_bits, partitions)
cem_bits = compute_bise_bitcount(ce_values, ce_range)
print("block width:", block_width)
print("block height:", block_height)
print("config bits:", config_bits)
print("weight count:", block_width * block_height)
print("weight range:", RANGE_CARDINALITY_TABLE[weight_range])
print("weight bits:", weight_bits)
print("remaining bits:", remaining_bits)
print("color endpoint values:", ce_values)
print("color endpoint range:", RANGE_CARDINALITY_TABLE[ce_range])
print("color endpoint bits:", cem_bits)
print("unused bits:", remaining_bits - cem_bits)
if len(sys.argv) != 6:
sys.stderr.write(
"Usage: {} BLOCKWIDTH BLOCKHEIGHT CEM PARTITIONS WEIGHTRANGE\n".format(
sys.argv[0]))
else:
print_data_size_info(
int(sys.argv[1]),
int(sys.argv[2]),
int(sys.argv[3]),
int(sys.argv[4]),
int(sys.argv[5]))

View File

@ -0,0 +1,137 @@
from bise import compute_bise_bitcount
from endpointmodes import *
from range import *
# Count the number of set bits in a number.
def count_bits(x):
assert type(x) is int
assert x >= 0 # negative integers are undefined behaviour
count = 0
while x != 0:
if x & 1:
count = count + 1
x = x >> 1
return count
# Calculate the number of bits used for config data, texel weight data and
# color endpoint data for an ASTC block.
def data_size(
partitions,
single_cem,
block_width,
block_height,
block_depth,
dual_plane,
weight_range):
assert partitions >= 1 and partitions <= 4
assert isinstance(single_cem, bool), single_cem
assert block_width >= 1 and block_width <= 12
assert block_height >= 1 and block_height <= 12
assert block_depth >= 1 and block_depth <= 12
assert isinstance(dual_plane, bool)
assert weight_range < WEIGHT_RANGE_MAX
if partitions == 4 and dual_plane:
raise ValueError("illegal encoding with 4 partitions and dual planes")
config_bits = 17
if partitions > 1:
if single_cem:
config_bits = 29
else:
config_bits = 24 + 3 * partitions
weights = block_width * block_height * block_depth
if weights > 64:
raise ValueError("illegal encoding with {} (> 64) weights".format(weights))
if dual_plane:
config_bits += 2
weights *= 2
weight_bits = compute_bise_bitcount(weights, weight_range)
if weight_bits < 24:
raise ValueError("illegal encoding with {} (< 24) weight bits".format(weight_bits))
if weight_bits > 96:
raise ValueError("illegal encoding with {} (> 96) weight bits".format(weight_bits))
remaining_bits = 128 - config_bits - weight_bits
return config_bits, weight_bits, remaining_bits
# Define the class for every color endpoint mode. Used to derive the range for
# color endpoint encoding.
CEM_VALUE_COUNT_TABLE = \
[
2, 2, 2, 2,
4, 4, 4, 4,
6, 6, 6, 6,
8, 8, 8, 8
]
# Count the number of encoded color endpoint values we are storing.
def cem_values_count(cem, partitions):
assert cem < CEM_MAX
# The ASTC specification derives this count from the CEM class and a value
# they call extra_CEM_bits. I do not understand what extra_CEM_bits is
# referring to, I use the CEM_VALUE_COUNT_TABLE instead and assume that
# there is one set of endpoint values for each partition.
return CEM_VALUE_COUNT_TABLE[cem] * partitions
# Calculate the range for color endpoint encoding for a given number of
# remaining bits.
def color_endpoint_range(cem, remaining_bits, partitions):
assert cem < CEM_MAX
cem_values = cem_values_count(cem, partitions)
if cem_values > 18:
raise ValueError("illegal encoding with {} (> 18) integers for color endpoints".format(cem_values))
# Brute-force search for the biggest range which fits in the remaining
# bits.
for ce_range in reversed(range(RANGE_MAX)):
cem_bits = compute_bise_bitcount(cem_values, ce_range)
if cem_bits <= remaining_bits:
return ce_range
raise ValueError("illegal encoding with not enough bits for cem {}".format(remaining_bits))
def color_endpoint_range_table(block_width, block_height):
def handle_except(partitions, cem, weight_range):
assert weight_range < WEIGHT_RANGE_MAX
try:
_, _, remaining_bits = data_size(
partitions = partitions,
single_cem = True,
block_width = block_width,
block_height = block_height,
block_depth = 1,
dual_plane = False,
weight_range = weight_range)
return color_endpoint_range(cem, remaining_bits, partitions)
except ValueError:
return -1
return \
[
[
[
handle_except(partitions, cem, weight_range)
for cem in range(CEM_MAX)
]
for weight_range in range(WEIGHT_RANGE_MAX)
]
for partitions in [1, 2]
]
if __name__ == "__main__":
print(color_endpoint_range_table(4, 4))

View File

@ -0,0 +1,17 @@
CEM_LDR_LUMINANCE_DIRECT = 0
CEM_LDR_LUMINANCE_BASE_OFFSET = 1
CEM_HDR_LUMINANCE_LARGE_RANGE = 2
CEM_HDR_LUMINANCE_SMALL_RANGE = 3
CEM_LDR_LUMINANCE_ALPHA_DIRECT = 4
CEM_LDR_LUMINANCE_ALPHA_BASE_OFFSET = 5
CEM_LDR_RGB_BASE_SCALE = 6
CEM_HDR_RGB_BASE_SCALE = 7
CEM_LDR_RGB_DIRECT = 8
CEM_LDR_RGB_BASE_OFFSET = 9
CEM_LDR_RGB_BASE_SCALE_PLUS_TWO_ALPHA = 10
CEM_HDR_RGB = 11
CEM_LDR_RGBA_DIRECT = 12
CEM_LDR_RGBA_BASE_OFFSET = 13
CEM_HDR_RGB_LDR_ALPHA = 14
CEM_HDR_RGB_HDR_ALPHA = 15
CEM_MAX = 16

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
from partitions import compute_partitioning_table
import matplotlib.image as mpimg
import numpy as np
def masks_to_image(block_width, block_height, masks):
colors = [ (1, 0, 0), (0, 0, 1), (0, 1, 0), (1, 1, 1) ]
xblocks = 32
yblocks = 32
img_width = xblocks * (block_width + 1) + 1
img_height = yblocks * (block_height + 1) + 1
pixels = np.zeros((img_height, img_width, 3))
i = 0
for mask in masks:
xblock = i % xblocks
yblock = i // xblocks
xtopleft = xblock * (block_width + 1) + 1
ytopleft = yblock * (block_height + 1) + 1
j = 0
for partition in mask:
x = j % block_width
y = j // block_width
pixels[ytopleft+y, xtopleft+x] = colors[partition]
j = j + 1
i = i + 1
assert i == 1024
return pixels
def write_image(partition_count, block_width, block_height):
table = compute_partitioning_table(
partition_count = partition_count,
block_width = block_width,
block_height = block_height)
img = masks_to_image(
block_width = block_width,
block_height = block_height,
masks = table)
path = "/tmp/%dx%d-blocks-%d-partitions.png" % (block_width, block_height, partition_count)
mpimg.imsave(path, img)
if __name__ == "__main__":
write_image(2, 4, 4)
write_image(3, 4, 4)
write_image(4, 4, 4)
write_image(4, 6, 12)
write_image(4, 12, 6)
write_image(4, 12, 12)

View File

@ -0,0 +1,289 @@
def square(x):
return x*x
def shiftr32(x, y):
return (x >> y) & (2**32-1)
def shiftl32(x, y):
return (x << y) & (2**32-1)
def xor32(x, y):
return x ^ y
def add32(x, y):
return (x + y) % 2**32
def sub32(x, y):
return (x - y) % 2**32
def hash52(p):
p = xor32(p, shiftr32(p, 15))
p = sub32(p, shiftl32(p, 17))
p = add32(p, shiftl32(p, 7))
p = add32(p, shiftl32(p, 4))
p = xor32(p, shiftr32(p, 5))
p = add32(p, shiftl32(p, 16))
p = xor32(p, shiftr32(p, 7))
p = xor32(p, shiftr32(p, 3))
p = xor32(p, shiftl32(p, 6))
p = xor32(p, shiftr32(p, 17))
assert p >= 0 and p < 2**32
return p
# Select partion index as defined by ASTC specification.
def select_partition(seed, x, y, z, partition_count, small_block):
assert seed >= 0 and seed < 2**10
assert partition_count >= 1 and partition_count <= 4
if small_block:
x = x << 1
y = y << 1
z = z << 1
seed += (partition_count - 1) * 1024
rnum = hash52(seed)
seed1 = square(rnum & 0xF)
seed2 = square((rnum >> 4) & 0xF)
seed3 = square((rnum >> 8) & 0xF)
seed4 = square((rnum >> 12) & 0xF)
seed5 = square((rnum >> 16) & 0xF)
seed6 = square((rnum >> 20) & 0xF)
seed7 = square((rnum >> 24) & 0xF)
seed8 = square((rnum >> 28) & 0xF)
seed9 = square((rnum >> 18) & 0xF)
seed10 = square((rnum >> 22) & 0xF)
seed11 = square((rnum >> 26) & 0xF)
seed12 = square(((rnum >> 30) | (rnum << 2)) & 0xF)
sh1 = 4 if seed & 2 else 5
sh2 = 6 if partition_count == 3 else 5
if not (seed & 1):
sh1, sh2 = (sh2, sh1)
sh3 = sh1 if seed & 0x10 else sh2
seed1 = seed1 >> sh1
seed2 = seed2 >> sh2
seed3 = seed3 >> sh1
seed4 = seed4 >> sh2
seed5 = seed5 >> sh1
seed6 = seed6 >> sh2
seed7 = seed7 >> sh1
seed8 = seed8 >> sh2
seed9 = seed9 >> sh3
seed10 = seed10 >> sh3
seed11 = seed11 >> sh3
seed12 = seed12 >> sh3
a = seed1*x + seed2*y + seed11*z + (rnum >> 14)
b = seed3*x + seed4*y + seed12*z + (rnum >> 10)
c = seed5*x + seed6*y + seed9*z + (rnum >> 6)
d = seed7*x + seed8*y + seed10*z + (rnum >> 2)
a = a & 0x3F
b = b & 0x3F if partition_count > 1 else 0
c = c & 0x3F if partition_count > 2 else 0
d = d & 0x3F if partition_count > 3 else 0
if a >= b and a >= c and a >= d:
return 0
elif b >= c and b >= d:
return 1
elif c >= d:
return 2
else:
return 3
# Convert a list of digits to a number with a specific base.
def digits_to_num(base, lst):
sum = 0
power = 0
for x in lst:
sum = sum + x * (base**power)
power = power + 1
return sum
# Convert a number to a list of digits for a certain base.
def num_to_digits(base, digits, num):
for x in range(0, digits):
yield num % base
num = num // base
class partitioning:
bit_masks = [0x1, 0x1, 0x3, 0x3]
shift_counts = [1, 1, 2, 2]
def __init__(self, partition_count, block_width, block_height, partition_mask):
assert isinstance(partition_mask, int)
assert partition_count >= 1 and partition_count <= 4
self.block_width = block_width
self.block_height = block_height
self.texel_count = block_width * block_height
self.partition_count = partition_count
self.partition_mask = partition_mask
self.bit_mask = partitioning.bit_masks[partition_count-1]
self.shift_count = partitioning.shift_counts[partition_count-1]
def __eq__(self, other):
return \
self.partition_count == other.partition_count and \
self.block_width == other.block_width and \
self.block_height == other.block_height and \
self.partition_mask == other.partition_mask
def __iter__(self):
return num_to_digits(
self.partition_count,
self.texel_count,
self.partition_mask)
def __str__(self):
return "%#x" % self.partition_mask
def __repr__(self):
return "partitioning({}, {}, {}, [{}])".format(
self.partition_count,
self.block_width,
self.block_height,
",".join((str(x) for x in self)))
def invert(part):
assert isinstance(part, partitioning)
assert part.partition_count == 2
return partitioning(
part.partition_count,
part.block_width,
part.block_height,
part.partition_mask ^ (2**part.texel_count-1))
def distance(a, b):
assert isinstance(a, partitioning)
assert isinstance(b, partitioning)
assert a.partition_count == b.partition_count
assert a.block_width == b.block_width
assert a.block_height == b.block_height
def cost(m, n):
return 0 if m == n else 1
return sum((cost(m, n) for (m, n) in zip(a, b)))
# Create human readable format for a partition mask.
def show_ascii(part):
assert isinstance(part, partitioning)
s = ""
i = 0
j = 0
for p in part:
s = s + str(p)
i = i + 1
if i == part.block_width and j < part.block_height-1:
s = s + "\n"
i = 0
j = j + 1
return s
# Compute the partition bitmask for a given block size, partition count and
# seed. The bitmask is a list of numbers in range [0, partition count-1]
# starting in top left corner of the block in row major order.
def compute_partitioning(partition_count, block_width, block_height, seed):
width_range = range(0, block_width)
height_range = range(0, block_height)
def f(x, y):
return select_partition(seed, x, y, 0, partition_count, True)
return partitioning(
partition_count,
block_width,
block_height,
digits_to_num(
partition_count,
(f(x, y) for y in height_range for x in width_range)))
# Compute the table that maps partition seeds to partition block masks for a
# given block size and partition count.
def compute_partitioning_table(partition_count, block_width, block_height):
def f(seed):
return compute_partitioning(
partition_count = partition_count,
block_width = block_width,
block_height = block_height,
seed = seed)
return (f(seed) for seed in range(0, 2**10))
# Compute the lookup table from a partition mask to a matching partition index.
# Matching is done according to the edit distance between the partitioning and
# all availible partitions.
def compute_partitioning_lookup_table(table):
assert len(table) == 1024
partition_count = 2
block_width = 4
block_height = 4
for ideal in range(0, 2**16):
ideal_part = partitioning(
partition_count = partition_count,
block_width = block_width,
block_height = block_height,
partition_mask = ideal)
ideal_inverted_part = invert(ideal_part)
best_score = 100000
best_indices = []
for index, actual_part in enumerate(table):
score = min(
distance(ideal_part, actual_part),
distance(ideal_inverted_part, actual_part))
if score < 2:
if score == best_score:
best_indices.append(index)
elif score < best_score:
best_score = score
best_indices = [index]
yield best_indices
def compute_partitioning_lookup_table_equality(table):
assert len(table) == 1024
partition_count = 2
block_width = 4
block_height = 4
for ideal in range(0, 2**16):
ideal_part = partitioning(
partition_count = partition_count,
block_width = block_width,
block_height = block_height,
partition_mask = ideal)
ideal_inverted_part = invert(ideal_part)
for index, actual_part in enumerate(table):
if ideal_part == actual_part or ideal_inverted_part == actual_part:
yield index
yield -1
if __name__ == "__main__":
table = list(compute_partitioning_table(
partition_count=2,
block_width=4,
block_height=4))
print([list(part) for part in table])
lookup_table = compute_partitioning_lookup_table(table)
print(list(lookup_table))

View File

@ -0,0 +1,123 @@
from bitset import bitset
from range import *
def unquantize_color(i, quant):
assert i >= 0 and i < RANGE_CARDINALITY_TABLE[quant]
assert quant >= RANGE_2 and quant <= RANGE_256
def unquant(a, b, c, d):
"""
This is the magic bit twiddling hack ARM uses in the ASTC decoder
specification to avoid full-width multipliers.
T = D * C + B;
T = T ^ A;
T = (A & 0x80) | (T >> 2);
"""
return (a & 0x80) | (((d*c + b) ^ a) >> 2)
def bit_only(lst):
return bitset.from_list(lst).number()
def trit_quint(A, B, C, D):
return unquant(
bitset.from_list(A).number(),
bitset.from_list(B).number(),
C,
bitset.from_list(D).number())
bits = bitset(8, i)
a = bits.get(0)
b = bits.get(1)
c = bits.get(2)
d = bits.get(3)
e = bits.get(4)
f = bits.get(5)
g = bits.get(6)
h = bits.get(7)
if quant == RANGE_2:
return bit_only([a,a,a,a,a,a,a,a])
elif quant == RANGE_3:
return [0, 128, 255][i]
elif quant == RANGE_4:
return bit_only([b,a,b,a,b,a,b,a])
elif quant == RANGE_5:
return [0, 64, 128, 192, 255][i]
elif quant == RANGE_6:
return trit_quint([a,a,a,a,a,a,a,a,a], [0,0,0,0,0,0,0,0,0], 204, [c,b])
elif quant == RANGE_8:
return bit_only([c,b,a,c,b,a,c,b])
elif quant == RANGE_10:
return trit_quint([a,a,a,a,a,a,a,a,a], [0,0,0,0,0,0,0,0,0], 113, [d,c,b])
elif quant == RANGE_12:
return trit_quint([a,a,a,a,a,a,a,a,a], [b,0,0,0,b,0,b,b,0], 93, [d,c])
elif quant == RANGE_16:
return bit_only([d,c,b,a,d,c,b,a])
elif quant == RANGE_20:
return trit_quint([a,a,a,a,a,a,a,a,a], [b,0,0,0,0,b,b,0,0], 54, [e,d,c])
elif quant == RANGE_24:
return trit_quint([a,a,a,a,a,a,a,a,a], [c,b,0,0,0,c,b,c,b], 44, [e,d])
elif quant == RANGE_32:
return bit_only([e,d,c,b,a,e,d,c])
elif quant == RANGE_40:
return trit_quint([a,a,a,a,a,a,a,a,a], [c,b,0,0,0,0,c,b,c], 26, [f,e,d])
elif quant == RANGE_48:
return trit_quint([a,a,a,a,a,a,a,a,a], [d,c,b,0,0,0,d,c,b], 22, [f,e])
elif quant == RANGE_64:
return bit_only([f,e,d,c,b,a,f,e])
elif quant == RANGE_80:
return trit_quint([a,a,a,a,a,a,a,a,a], [d,c,b,0,0,0,0,d,c], 13, [g,f,e])
elif quant == RANGE_96:
return trit_quint([a,a,a,a,a,a,a,a,a], [e,d,c,b,0,0,0,e,d], 11, [g,f])
elif quant == RANGE_128:
return bit_only([g,f,e,d,c,b,a,g])
elif quant == RANGE_160:
return trit_quint([a,a,a,a,a,a,a,a,a], [e,d,c,b,0,0,0,0,e], 6, [h,g,f])
elif quant == RANGE_192:
return trit_quint([a,a,a,a,a,a,a,a,a], [f,e,d,c,b,0,0,0,f], 5, [h,g])
elif quant == RANGE_256:
return bit_only([h,g,f,e,d,c,b,a])
assert False
def find_closest(unquantized, value):
assert isinstance(unquantized, list)
assert len(unquantized) > 0
assert isinstance(value, int)
class Item:
def __init__(self, index):
self.index = index
self.cost = abs(value - unquantized[self.index])
def __lt__(self, other):
return self.cost < other.cost
return min(map(Item, range(len(unquantized)))).index
def color_quantize_table(color_unquantize_table):
return \
[
[
find_closest(color_unquantize_table[quant], i)
for i in range(256)
]
for quant in range(RANGE_MAX)
]
def color_unquantize_table():
return \
[
[
unquantize_color(i, quant)
for i in range(RANGE_CARDINALITY_TABLE[quant])
]
for quant in range(RANGE_MAX)
]
if __name__ == "__main__":
unquantize_table = color_unquantize_table()
quantize_table = color_quantize_table(unquantize_table)
print(unquantize_table)
print(quantize_table)

View File

@ -0,0 +1,67 @@
# There are 21 ranges (intervals in math lingo) for endpoint values.
RANGE_2 = 0
RANGE_3 = 1
RANGE_4 = 2
RANGE_5 = 3
RANGE_6 = 4
RANGE_8 = 5
RANGE_10 = 6
RANGE_12 = 7
RANGE_16 = 8
RANGE_20 = 9
RANGE_24 = 10
RANGE_32 = 11
RANGE_40 = 12
RANGE_48 = 13
RANGE_64 = 14
RANGE_80 = 15
RANGE_96 = 16
RANGE_128 = 17
RANGE_160 = 18
RANGE_192 = 19
RANGE_256 = 20
RANGE_MAX = 21
# Table of each range's cardinality, that is the number of representable
# integers in each range.
RANGE_CARDINALITY_TABLE = \
[
2,
3,
4,
5,
6,
8,
10,
12,
16,
20,
24,
32,
40,
48,
64,
80,
96,
128,
160,
192,
256
]
# There are 12 ranges for texel weights.
WEIGHT_RANGE_MAX = 12
def range_lookup(count):
"""
Find what quantization range an number of elements can be represented with.
"""
assert type(count) is int
assert count >= 2 and count <= 256
for i in range(RANGE_MAX):
if count <= RANGE_CARDINALITY_TABLE[i]:
return i
assert False

View File

@ -1,6 +1,11 @@
#import "TextureCompression.h" #import "TextureCompression.h"
#import "astc.h"
void compressRGBAToBC1(uint8_t const * _Nonnull argb, int width, int height, uint8_t * _Nonnull bc1) { void compressRGBAToBC1(uint8_t const * _Nonnull argb, int width, int height, uint8_t * _Nonnull bc1) {
BgraImage image(width, height, (uint8_t *)argb);
CompressedImage compressed(width, height, 4, 4, 16);
compress_astc(image, &compressed);
/*Javelin::RgbaBitmap bitmap(width, height); /*Javelin::RgbaBitmap bitmap(width, height);
uint8_t *data = (uint8_t *)bitmap.GetData(); uint8_t *data = (uint8_t *)bitmap.GetData();
for (int i = 0; i < width * height; i++) { for (int i = 0; i < width * height; i++) {