mikunyan 3.9.4 → 3.9.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +35 -41
- data/Rakefile +9 -0
- data/exe/mikunyan-image +12 -8
- data/ext/decoders/native/astc.c +760 -0
- data/ext/decoders/native/astc.h +8 -0
- data/ext/decoders/native/dxtc.c +104 -0
- data/ext/decoders/native/dxtc.h +9 -0
- data/ext/decoders/native/etc.c +271 -0
- data/ext/decoders/native/etc.h +11 -0
- data/ext/decoders/native/extconf.rb +8 -0
- data/ext/decoders/native/main.c +167 -0
- data/ext/decoders/native/rgb.c +26 -0
- data/ext/decoders/native/rgb.h +8 -0
- data/lib/mikunyan/asset.rb +13 -7
- data/lib/mikunyan/decoders/image_decoder.rb +40 -201
- data/lib/mikunyan/typetrees/00ad972a9b8de1baeacb62e297cbb968.dat +0 -0
- data/lib/mikunyan/typetrees/01ccfe05c6fbc7ff03dcf8afa8213ff5.dat +0 -0
- data/lib/mikunyan/typetrees/086efb68ee41abe4e98e1ae93ae96290.dat +0 -0
- data/lib/mikunyan/typetrees/10355709bc95355f57466913ac850d0b.dat +0 -0
- data/lib/mikunyan/typetrees/1e87d82d4fd058509a3c7866db0e7356.dat +0 -0
- data/lib/mikunyan/typetrees/26165a24a953362edb6a7078f6536c4b.dat +0 -0
- data/lib/mikunyan/typetrees/266d53113fa30d2b858f2768f92eaa14.dat +0 -0
- data/lib/mikunyan/typetrees/2d2b1d63eb2a68ed94bbf7f50fc21d7b.dat +0 -0
- data/lib/mikunyan/typetrees/434b934f757d042e20f52d8c2ae20843.dat +0 -0
- data/lib/mikunyan/typetrees/486ba4e15dbd6aea8ac1a064305889c8.dat +0 -0
- data/lib/mikunyan/typetrees/49ff511929094ac12ffaa4ab38ed7bd1.dat +0 -0
- data/lib/mikunyan/typetrees/4dbfaa1def6adb569b550804b19b4305.dat +0 -0
- data/lib/mikunyan/typetrees/5bc42b93159267aabba724a6a7923603.dat +0 -0
- data/lib/mikunyan/typetrees/66405447c6973a81e978410c391172fe.dat +0 -0
- data/lib/mikunyan/typetrees/6932d6d1d46264c8680a181056f98be2.dat +0 -0
- data/lib/mikunyan/typetrees/6974f6c74321933ec4ba7437a55be2c3.dat +0 -0
- data/lib/mikunyan/typetrees/69b01db128625aa95f1f92fb890ff045.dat +0 -0
- data/lib/mikunyan/typetrees/6f10d8f832d5adde6982d4515b3f0bb3.dat +0 -0
- data/lib/mikunyan/typetrees/761ca81f78491542badc37f810ab3455.dat +0 -0
- data/lib/mikunyan/typetrees/76ce55d4dbaf38f5c674ea9f0a344951.dat +0 -0
- data/lib/mikunyan/typetrees/7e050781d08ca9d10bc74beb7e91c3b5.dat +0 -0
- data/lib/mikunyan/typetrees/8198e72b2e2a96b9cfa38636b5565e13.dat +0 -0
- data/lib/mikunyan/typetrees/84c6ac46ef89030991cbbb3fd21d2889.dat +0 -0
- data/lib/mikunyan/typetrees/852794becbcf95f66992da2b96a69704.dat +0 -0
- data/lib/mikunyan/typetrees/961be27d12d60b1b3421191d5256a876.dat +0 -0
- data/lib/mikunyan/typetrees/96a47566b4e135078f690a4a69935d58.dat +0 -0
- data/lib/mikunyan/typetrees/97da5f4688e45a57c8b42d4f42497297.dat +0 -0
- data/lib/mikunyan/typetrees/97ec0712102a3ea3f1cf8c0a4e47c070.dat +0 -0
- data/lib/mikunyan/typetrees/9eabac6ec66ffe818e008883728fcc1b.dat +0 -0
- data/lib/mikunyan/typetrees/a372646834bcaf26eab1d21b29e39553.dat +0 -0
- data/lib/mikunyan/typetrees/a4f194097b08bc4c5019c3a4ea6f5cbd.dat +0 -0
- data/lib/mikunyan/typetrees/af863b6969b9b82be9450f0574339f65.dat +0 -0
- data/lib/mikunyan/typetrees/b0adafbe24f8148ebf01794ee6679925.dat +0 -0
- data/lib/mikunyan/typetrees/b14bcb0865632d1b2d6e215a000e4c0f.dat +0 -0
- data/lib/mikunyan/typetrees/b35bf02952f2946208ff6b4deca3a6a9.dat +0 -0
- data/lib/mikunyan/typetrees/b6bbd0e88d1feb636d89bd766ea5934f.dat +0 -0
- data/lib/mikunyan/typetrees/b78821b6aeb5b79c8961728a9f068024.dat +0 -0
- data/lib/mikunyan/typetrees/bea915a8ab3d9b55e80c969a22e692d3.dat +0 -0
- data/lib/mikunyan/typetrees/c184743520186f546000de20f4d19736.dat +0 -0
- data/lib/mikunyan/typetrees/d50ed13362e98df8096b2f735131fce5.dat +0 -0
- data/lib/mikunyan/typetrees/d871346d990bbc294d02f4c366bf1b6d.dat +0 -0
- data/lib/mikunyan/typetrees/d8e8eeb43589ccd7019398e56f6c16b0.dat +0 -0
- data/lib/mikunyan/typetrees/daea1bb1bba6613afb2cb001ca8fa0d4.dat +0 -0
- data/lib/mikunyan/typetrees/db088f9c2f2224da9f488879467856e5.dat +0 -0
- data/lib/mikunyan/typetrees/e7c5c01b0369574e9346ce846e1e8e63.dat +0 -0
- data/lib/mikunyan/typetrees/f123b055a61dfa7dc679d78cdaecd383.dat +0 -0
- data/lib/mikunyan/typetrees/f92d618c5266ea3a8ca770b6eca728c8.dat +0 -0
- data/lib/mikunyan/typetrees/fad2d0a58e9174708176102b418facf1.dat +0 -0
- data/lib/mikunyan/typetrees/ff001a2e51937aa5add9eaf9cd3d8ae4.dat +0 -0
- data/lib/mikunyan/version.rb +1 -1
- data/mikunyan.gemspec +1 -0
- metadata +63 -4
- data/lib/mikunyan/decoders/astc_block_decoder.rb +0 -526
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d98bb997b5988424bf6ac0a0f116965bbd4cb5959bde3cad40541143872ab93
|
4
|
+
data.tar.gz: d77ddb35f213bd0d0729dfe9b53b2f6fa125687b2e89a79fbe876a72a8a7d7a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 839775366553bae8d90525e47088cbe9d42c59638ffcd1964411f7b006af89b6eb9893392be81b456ce599678155c87213c1a59a4c79759990b2a5724c89b3a0
|
7
|
+
data.tar.gz: 8138498cac6cd2a845321be929e936520e2f535a5195dad604561bd98f021a5ce2463219fb8996a7a2cd8f05dfbf90370487b12620bbf91e1e4b4c85dfe25cd7
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# mikunyan
|
2
2
|
|
3
|
-
|
3
|
+
A library to deserialize AssetBundle files (\*.unity3d) and asset files of Unity.
|
4
|
+
|
5
|
+
The name "Mikunyan" is derived from [Miku Maekawa](http://www.project-imas.com/wiki/Miku_Maekawa).
|
6
|
+
|
7
|
+
Ruby-Doc: http://www.rubydoc.info/gems/mikunyan/
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
@@ -33,67 +37,67 @@ If you want to install development build:
|
|
33
37
|
```ruby
|
34
38
|
require 'mikunyan'
|
35
39
|
|
36
|
-
# load AssetBundle
|
40
|
+
# load an AssetBundle file
|
37
41
|
bundle = Mikunyan::AssetBundle.file(filename)
|
38
42
|
|
39
|
-
# you can load
|
43
|
+
# you can also load a bundle from blob
|
40
44
|
# bundle = Mikunyan::AssetBundle.load(blob)
|
41
45
|
|
42
|
-
# select asset (
|
46
|
+
# select asset (a bundle normally contains only one asset)
|
43
47
|
asset = bundle.assets[0]
|
44
48
|
|
45
|
-
# or you can directly load asset
|
49
|
+
# or you can directly load an asset from an asset file
|
46
50
|
# asset = Mikunyan::Asset.file(filename)
|
47
51
|
|
48
|
-
#
|
52
|
+
# get a list of objects
|
49
53
|
list = asset.objects
|
50
54
|
|
51
|
-
#
|
55
|
+
# get PathIds of objects
|
52
56
|
path_ids = asset.path_ids
|
53
57
|
|
54
|
-
#
|
58
|
+
# get an container table of objects (if available)
|
55
59
|
containers = asset.containers
|
56
60
|
|
57
|
-
# load object (Mikunyan::ObjectValue)
|
61
|
+
# load an object (Mikunyan::ObjectValue)
|
58
62
|
obj = asset.parse_object(path_ids[0])
|
59
63
|
|
60
|
-
#
|
64
|
+
# load an object to Ruby data structures
|
61
65
|
obj_hash = asset.parse_object_simple(path_ids[0])
|
62
66
|
|
63
|
-
#
|
67
|
+
# a Hash can be serialized to JSON
|
64
68
|
require 'json'
|
65
69
|
obj_hash.to_json
|
66
70
|
```
|
67
71
|
|
68
72
|
### Mikunyan::ObjectValue
|
69
73
|
|
70
|
-
`Mikunyan::ObjectValue` can be 3 types
|
74
|
+
`Mikunyan::ObjectValue` can be 3 types: value, array and key-value table.
|
71
75
|
|
72
76
|
```ruby
|
73
|
-
#
|
77
|
+
# get whether obj is value or not
|
74
78
|
obj.value?
|
75
79
|
|
76
|
-
# get value
|
80
|
+
# get a value
|
77
81
|
obj.value
|
78
82
|
|
79
83
|
# same as obj.value
|
80
84
|
obj[]
|
81
85
|
|
82
86
|
|
83
|
-
#
|
87
|
+
# get whether obj is array or not
|
84
88
|
obj.array?
|
85
89
|
|
86
|
-
# get array
|
90
|
+
# get an array
|
87
91
|
obj.value
|
88
92
|
|
89
93
|
# you can directly access by index
|
90
94
|
obj[0]
|
91
95
|
|
92
96
|
|
93
|
-
#
|
97
|
+
# get keys (if obj is key-value table)
|
94
98
|
obj.keys
|
95
99
|
|
96
|
-
# get child
|
100
|
+
# get child objects
|
97
101
|
obj[key]
|
98
102
|
|
99
103
|
# same as obj[key]
|
@@ -102,9 +106,9 @@ obj.key
|
|
102
106
|
|
103
107
|
### Unpack Texture2D
|
104
108
|
|
105
|
-
You can get
|
109
|
+
You can get image data directly from Texture2D object. Output object's class is `ChunkyPNG::Image`.
|
106
110
|
|
107
|
-
Some basic texture formats (1–5, 7, 9, 13–20, 22, 62, and 63), ETC_RGB4 (34), ETC2 (45
|
111
|
+
Some basic texture formats (1–5, 7, 9, 13–20, 22, 62, and 63), DXT1 (10), DXT5 (12), ETC_RGB4 (34), ETC2 (45–47), and ASTC (48–59) are available.
|
108
112
|
|
109
113
|
```ruby
|
110
114
|
require 'mikunyan/decoders'
|
@@ -112,7 +116,7 @@ require 'mikunyan/decoders'
|
|
112
116
|
# get some Texture2D asset
|
113
117
|
obj = asset.parse_object(path_ids[1])
|
114
118
|
|
115
|
-
# you can get
|
119
|
+
# you can get image data
|
116
120
|
img = Mikunyan::ImageDecoder.decode_object(obj)
|
117
121
|
|
118
122
|
# save it!
|
@@ -123,14 +127,14 @@ Mikunyan cannot decode ASTC with HDR data. Use `Mikunyan::ImageDecoder.create_as
|
|
123
127
|
|
124
128
|
### Json / YAML Outputter
|
125
129
|
|
126
|
-
`mikunyan-json` is an executable command for converting unity3d to
|
130
|
+
`mikunyan-json` is an executable command for converting unity3d to JSON.
|
127
131
|
|
128
132
|
$ mikunyan-json bundle.unity3d > bundle.json
|
129
133
|
|
130
134
|
Available options:
|
131
135
|
|
132
|
-
- `--as-asset` (`-a`): interpret input file as not
|
133
|
-
- `--pretty` (`-p`): prettify output
|
136
|
+
- `--as-asset` (`-a`): interpret input file as not AssetBundle but Asset
|
137
|
+
- `--pretty` (`-p`): prettify output JSON
|
134
138
|
- `--yaml` (`-y`): YAML mode
|
135
139
|
|
136
140
|
### Image Outputter
|
@@ -139,7 +143,7 @@ Available options:
|
|
139
143
|
|
140
144
|
$ mikunyan-image bundle.unity3d
|
141
145
|
|
142
|
-
The console log is
|
146
|
+
The console log is JSON data of output textures as follows.
|
143
147
|
|
144
148
|
```json
|
145
149
|
[
|
@@ -158,7 +162,7 @@ The console log is json data of output textures as below.
|
|
158
162
|
]
|
159
163
|
```
|
160
164
|
|
161
|
-
If the option `--sprite` specified, `mikunyan-image` will output sprites. The
|
165
|
+
If the option `--sprite` specified, `mikunyan-image` will output sprites. The logged JSON also contains sprite information.
|
162
166
|
|
163
167
|
```json
|
164
168
|
[
|
@@ -215,10 +219,10 @@ If the option `--sprite` specified, `mikunyan-image` will output sprites. The lo
|
|
215
219
|
|
216
220
|
Available options:
|
217
221
|
|
218
|
-
- `--as-asset` (`-a`): interpret input file as not
|
219
|
-
- `--outputdir` (`-o`): output directory (default is a basename of input file without an
|
222
|
+
- `--as-asset` (`-a`): interpret input file as not AssetBundle but Asset
|
223
|
+
- `--outputdir` (`-o`): specify an output directory (default is a basename of input file without an extension)
|
220
224
|
- `--sprite` (`-s`): output sprites instead of textures
|
221
|
-
- `--pretty` (`-p`): prettify output
|
225
|
+
- `--pretty` (`-p`): prettify output JSON
|
222
226
|
|
223
227
|
## Dependencies
|
224
228
|
|
@@ -229,19 +233,9 @@ Available options:
|
|
229
233
|
|
230
234
|
Mikunyan uses [oily_png](https://rubygems.org/gems/oily_png) instead of chunky_png if available.
|
231
235
|
|
232
|
-
##
|
233
|
-
|
234
|
-
### Sometimes unpacking fails
|
235
|
-
|
236
|
-
I'm sorry...
|
237
|
-
|
238
|
-
### Can I unpack Mesh files?
|
239
|
-
|
240
|
-
It's hard work for me...
|
241
|
-
|
242
|
-
### What mikunyan comes from?
|
236
|
+
## Implementation in other languages
|
243
237
|
|
244
|
-
[
|
238
|
+
- TypeScript: [shibunyan](https://github.com/AnemoneStar/shibunyan)
|
245
239
|
|
246
240
|
## Contributing
|
247
241
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
require "rake/extensiontask"
|
2
3
|
|
3
4
|
task :scream do
|
4
5
|
puts "みくは自分を曲げないよ!"
|
5
6
|
end
|
7
|
+
|
8
|
+
task :build => :compile
|
9
|
+
|
10
|
+
Rake::ExtensionTask.new('decoders/native') do |ext|
|
11
|
+
ext.lib_dir = 'lib/mikunyan'
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => [:clobber, :compile, :spec]
|
data/exe/mikunyan-image
CHANGED
@@ -54,15 +54,18 @@ assets.each do |asset|
|
|
54
54
|
json = {}
|
55
55
|
textures = {}
|
56
56
|
|
57
|
-
asset.
|
58
|
-
obj = asset.parse_object(
|
57
|
+
asset.objects.select{|o| asset.object_type(o) == 'Sprite'}.each do |o|
|
58
|
+
obj = asset.parse_object(o)
|
59
|
+
next unless obj
|
59
60
|
name = obj.m_Name.value
|
60
61
|
tex_id = obj.m_RD.texture.m_PathID.value
|
61
62
|
|
62
63
|
unless textures[tex_id]
|
63
64
|
tex_obj = asset.parse_object(tex_id)
|
64
|
-
|
65
|
-
|
65
|
+
if tex_obj
|
66
|
+
textures[tex_id] = Mikunyan::ImageDecoder.decode_object(tex_obj) if tex_obj
|
67
|
+
json[tex_id] = {:name => tex_obj.m_Name.value, :width => textures[tex_id].width, :height => textures[tex_id].height, :path_id => tex_id, :sprites => []}
|
68
|
+
end
|
66
69
|
end
|
67
70
|
|
68
71
|
if textures[tex_id]
|
@@ -71,19 +74,20 @@ assets.each do |asset|
|
|
71
74
|
width = obj.m_Rect.width.value
|
72
75
|
height = obj.m_Rect.height.value
|
73
76
|
|
74
|
-
json[tex_id][:sprites] << {:name => name, :x => x, :y => y, :width => width, :height => height, :path_id => path_id}
|
77
|
+
json[tex_id][:sprites] << {:name => name, :x => x, :y => y, :width => width, :height => height, :path_id => o.path_id}
|
75
78
|
textures[tex_id].crop(x.round, (textures[tex_id].height - height - y).round, width.round, height.round).save("#{outdir}/#{name}.png")
|
76
79
|
end
|
77
80
|
end
|
78
81
|
puts opts[:pretty] ? JSON.pretty_generate(json.values) : JSON.generate(json.values)
|
79
82
|
else
|
80
83
|
json = []
|
81
|
-
asset.
|
82
|
-
obj = asset.parse_object(
|
84
|
+
asset.objects.select{|o| asset.object_type(o) == 'Texture2D'}.each do |o|
|
85
|
+
obj = asset.parse_object(o)
|
86
|
+
next unless obj
|
83
87
|
name = obj.m_Name.value
|
84
88
|
image = Mikunyan::ImageDecoder.decode_object(obj)
|
85
89
|
if image
|
86
|
-
json << {:name => name, :width => image.width, :height => image.height, :path_id => path_id}
|
90
|
+
json << {:name => name, :width => image.width, :height => image.height, :path_id => o.path_id}
|
87
91
|
image.save("#{outdir}/#{name}.png")
|
88
92
|
end
|
89
93
|
end
|
@@ -0,0 +1,760 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include <stdint.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <ruby.h>
|
5
|
+
#include "astc.h"
|
6
|
+
|
7
|
+
static const int BitReverseTable[] = {
|
8
|
+
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
9
|
+
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
10
|
+
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
11
|
+
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
12
|
+
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
13
|
+
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
14
|
+
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
15
|
+
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
16
|
+
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
17
|
+
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
18
|
+
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
19
|
+
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
20
|
+
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
21
|
+
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
22
|
+
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
23
|
+
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
24
|
+
};
|
25
|
+
|
26
|
+
static int WeightPrecTableA[] = {0, 0, 0, 3, 0, 5, 3, 0, 0, 0, 5, 3, 0, 5, 3, 0};
|
27
|
+
static int WeightPrecTableB[] = {0, 0, 1, 0, 2, 0, 1, 3, 0, 0, 1, 2, 4, 2, 3, 5};
|
28
|
+
|
29
|
+
static int CemTableA[] = {0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 0, 0};
|
30
|
+
static int CemTableB[] = {8, 6, 5, 7, 5, 4, 6, 4, 3, 5, 3, 2, 4, 2, 1, 3, 1, 2, 1};
|
31
|
+
|
32
|
+
static inline uint_fast32_t color(uint_fast32_t r, uint_fast32_t g, uint_fast32_t b, uint_fast32_t a) {
|
33
|
+
return r | g << 8 | b << 16 | a << 24;
|
34
|
+
}
|
35
|
+
|
36
|
+
static inline uint_fast8_t bit_reverse_u8(const uint_fast8_t c, const int bits) {
|
37
|
+
return BitReverseTable[c] >> (8 - bits);
|
38
|
+
}
|
39
|
+
|
40
|
+
static inline uint_fast64_t bit_reverse_u64(const uint_fast64_t d, const int bits) {
|
41
|
+
uint_fast64_t ret =
|
42
|
+
(uint_fast64_t)BitReverseTable[d & 0xff] << 56 |
|
43
|
+
(uint_fast64_t)BitReverseTable[d >> 8 & 0xff] << 48 |
|
44
|
+
(uint_fast64_t)BitReverseTable[d >> 16 & 0xff] << 40 |
|
45
|
+
(uint_fast64_t)BitReverseTable[d >> 24 & 0xff] << 32 |
|
46
|
+
(uint_fast32_t)BitReverseTable[d >> 32 & 0xff] << 24 |
|
47
|
+
(uint_fast32_t)BitReverseTable[d >> 40 & 0xff] << 16 |
|
48
|
+
(uint_fast16_t)BitReverseTable[d >> 48 & 0xff] << 8 | BitReverseTable[d >> 56 & 0xff];
|
49
|
+
return ret >> (64 - bits);
|
50
|
+
}
|
51
|
+
|
52
|
+
static inline int getbits(const uint8_t *buf, const int bit, const int len) {
|
53
|
+
return (*(int*)(buf + bit / 8) >> (bit % 8)) & ((1 << len) - 1);
|
54
|
+
}
|
55
|
+
|
56
|
+
static inline uint_fast64_t getbits64(const uint8_t *buf, const int bit, const int len) {
|
57
|
+
uint_fast64_t mask = len == 64 ? 0xffffffffffffffff : (1ull << len) - 1;
|
58
|
+
if (len < 1)
|
59
|
+
return 0;
|
60
|
+
else if (bit >= 64)
|
61
|
+
return (*(uint_fast64_t*)(buf + 8)) >> (bit - 64) & mask;
|
62
|
+
else if (bit <= 0)
|
63
|
+
return (*(uint_fast64_t*)buf) << -bit & mask;
|
64
|
+
else if (bit + len <= 64)
|
65
|
+
return (*(uint_fast64_t*)buf) >> bit & mask;
|
66
|
+
else
|
67
|
+
return ((*(uint_fast64_t*)buf) >> bit | *(uint_fast64_t*)(buf + 8) << (64 - bit)) & mask;
|
68
|
+
}
|
69
|
+
|
70
|
+
static inline uint_fast8_t clamp(const int n) {
|
71
|
+
return n < 0 ? 0 : n > 255 ? 255 : n;
|
72
|
+
}
|
73
|
+
|
74
|
+
static inline void bit_transfer_signed(int *a, int *b) {
|
75
|
+
*b = (*b >> 1) | (*a & 0x80);
|
76
|
+
*a = (*a >> 1) & 0x3f;
|
77
|
+
if (*a & 0x20)
|
78
|
+
*a -= 0x40;
|
79
|
+
}
|
80
|
+
|
81
|
+
static inline void set_endpoint(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
82
|
+
endpoint[0] = r1;
|
83
|
+
endpoint[1] = g1;
|
84
|
+
endpoint[2] = b1;
|
85
|
+
endpoint[3] = a1;
|
86
|
+
endpoint[4] = r2;
|
87
|
+
endpoint[5] = g2;
|
88
|
+
endpoint[6] = b2;
|
89
|
+
endpoint[7] = a2;
|
90
|
+
}
|
91
|
+
|
92
|
+
static inline void set_endpoint_clamp(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
93
|
+
endpoint[0] = clamp(r1);
|
94
|
+
endpoint[1] = clamp(g1);
|
95
|
+
endpoint[2] = clamp(b1);
|
96
|
+
endpoint[3] = clamp(a1);
|
97
|
+
endpoint[4] = clamp(r2);
|
98
|
+
endpoint[5] = clamp(g2);
|
99
|
+
endpoint[6] = clamp(b2);
|
100
|
+
endpoint[7] = clamp(a2);
|
101
|
+
}
|
102
|
+
|
103
|
+
static inline void set_endpoint_blue(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
104
|
+
endpoint[0] = (r1 + b1) >> 1;
|
105
|
+
endpoint[1] = (g1 + b1) >> 1;
|
106
|
+
endpoint[2] = b1;
|
107
|
+
endpoint[3] = a1;
|
108
|
+
endpoint[4] = (r2 + b2) >> 1;
|
109
|
+
endpoint[5] = (g2 + b2) >> 1;
|
110
|
+
endpoint[6] = b2;
|
111
|
+
endpoint[7] = a2;
|
112
|
+
}
|
113
|
+
|
114
|
+
static inline void set_endpoint_blue_clamp(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
115
|
+
endpoint[0] = clamp((r1 + b1) >> 1);
|
116
|
+
endpoint[1] = clamp((g1 + b1) >> 1);
|
117
|
+
endpoint[2] = clamp(b1);
|
118
|
+
endpoint[3] = clamp(a1);
|
119
|
+
endpoint[4] = clamp((r2 + b2) >> 1);
|
120
|
+
endpoint[5] = clamp((g2 + b2) >> 1);
|
121
|
+
endpoint[6] = clamp(b2);
|
122
|
+
endpoint[7] = clamp(a2);
|
123
|
+
}
|
124
|
+
|
125
|
+
static inline uint_fast8_t select_color(int v0, int v1, int weight) {
|
126
|
+
return ((((v0 << 8 | v0) * (64 - weight) + (v1 << 8 | v1) * weight + 32) >> 6) * 255 + 32768) / 65536;
|
127
|
+
}
|
128
|
+
|
129
|
+
typedef struct {
|
130
|
+
int bw;
|
131
|
+
int bh;
|
132
|
+
int width;
|
133
|
+
int height;
|
134
|
+
int part_num;
|
135
|
+
int dual_plane;
|
136
|
+
int plane_selector;
|
137
|
+
int weight_range;
|
138
|
+
int weight_num; // max: 120
|
139
|
+
int cem[4];
|
140
|
+
int cem_range;
|
141
|
+
int endpoint_value_num; // max: 32
|
142
|
+
int endpoints[4][8];
|
143
|
+
int weights[144][2];
|
144
|
+
int partition[144];
|
145
|
+
} BlockData;
|
146
|
+
|
147
|
+
typedef struct {
|
148
|
+
int bits;
|
149
|
+
int nonbits;
|
150
|
+
} IntSeqData;
|
151
|
+
|
152
|
+
void decode_intseq(const uint8_t *buf, int offset, const int a, const int b, const int count, const int reverse, IntSeqData *out) {
|
153
|
+
static int mt[] = { 0, 2, 4, 5, 7 };
|
154
|
+
static int mq[] = { 0, 3, 5 };
|
155
|
+
static int TritsTable[5][256] = {
|
156
|
+
{0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 1, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 1, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2},
|
157
|
+
{0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1},
|
158
|
+
{0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2},
|
159
|
+
{0, 0, 0, 0, 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, 1, 1, 1, 1, 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, 0, 0, 0, 0, 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, 0, 0, 0, 0, 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, 1, 1, 1, 1, 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, 1, 1, 1, 1, 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},
|
160
|
+
{0, 0, 0, 0, 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, 0, 0, 0, 0, 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, 0, 0, 0, 0, 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, 1, 1, 1, 1, 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, 1, 1, 1, 1, 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, 1, 1, 1, 1, 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}
|
161
|
+
};
|
162
|
+
static int QuintsTable[3][128] = {
|
163
|
+
{0, 1, 2, 3, 4, 0, 4, 4, 0, 1, 2, 3, 4, 1, 4, 4, 0, 1, 2, 3, 4, 2, 4, 4, 0, 1, 2, 3, 4, 3, 4, 4, 0, 1, 2, 3, 4, 0, 4, 0, 0, 1, 2, 3, 4, 1, 4, 1, 0, 1, 2, 3, 4, 2, 4, 2, 0, 1, 2, 3, 4, 3, 4, 3, 0, 1, 2, 3, 4, 0, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 0, 1, 2, 3, 4, 2, 2, 3, 0, 1, 2, 3, 4, 3, 2, 3, 0, 1, 2, 3, 4, 0, 0, 1, 0, 1, 2, 3, 4, 1, 0, 1, 0, 1, 2, 3, 4, 2, 0, 1, 0, 1, 2, 3, 4, 3, 0, 1},
|
164
|
+
{0, 0, 0, 0, 0, 4, 4, 4, 1, 1, 1, 1, 1, 4, 4, 4, 2, 2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 4, 0, 4, 1, 1, 1, 1, 1, 4, 1, 4, 2, 2, 2, 2, 2, 4, 2, 4, 3, 3, 3, 3, 3, 4, 3, 4, 0, 0, 0, 0, 0, 4, 0, 0, 1, 1, 1, 1, 1, 4, 1, 1, 2, 2, 2, 2, 2, 4, 2, 2, 3, 3, 3, 3, 3, 4, 3, 3, 0, 0, 0, 0, 0, 4, 0, 0, 1, 1, 1, 1, 1, 4, 1, 1, 2, 2, 2, 2, 2, 4, 2, 2, 3, 3, 3, 3, 3, 4, 3, 3},
|
165
|
+
{0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 3, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4}
|
166
|
+
};
|
167
|
+
|
168
|
+
if (count <= 0)
|
169
|
+
return;
|
170
|
+
|
171
|
+
int n = 0;
|
172
|
+
|
173
|
+
if (a == 3) {
|
174
|
+
int mask = (1 << b) - 1;
|
175
|
+
int block_count = (count + 4) / 5;
|
176
|
+
int last_block_count = (count + 4) % 5 + 1;
|
177
|
+
int block_size = 8 + 5 * b;
|
178
|
+
int last_block_size = (block_size * last_block_count + 4) / 5;
|
179
|
+
|
180
|
+
if (reverse) {
|
181
|
+
for (int i = 0, p = offset; i < block_count; i++, p -= block_size) {
|
182
|
+
int now_size = (i < block_count - 1) ? block_size : last_block_size;
|
183
|
+
uint_fast64_t d = bit_reverse_u64(getbits64(buf, p - now_size, now_size), now_size);
|
184
|
+
int x = (d >> b & 3) | (d >> b * 2 & 0xc) | (d >> b * 3 & 0x10) | (d >> b * 4 & 0x60) | (d >> b * 5 & 0x80);
|
185
|
+
for (int j = 0; j < 5 && n < count; j++, n++)
|
186
|
+
out[n] = (IntSeqData){ d >> (mt[j] + b * j) & mask, TritsTable[j][x] };
|
187
|
+
}
|
188
|
+
} else {
|
189
|
+
for (int i = 0, p = offset; i < block_count; i++, p += block_size) {
|
190
|
+
uint_fast64_t d = getbits64(buf, p, (i < block_count - 1) ? block_size : last_block_size);
|
191
|
+
int x = (d >> b & 3) | (d >> b * 2 & 0xc) | (d >> b * 3 & 0x10) | (d >> b * 4 & 0x60) | (d >> b * 5 & 0x80);
|
192
|
+
for (int j = 0; j < 5 && n < count; j++, n++)
|
193
|
+
out[n] = (IntSeqData){ d >> (mt[j] + b * j) & mask, TritsTable[j][x] };
|
194
|
+
}
|
195
|
+
}
|
196
|
+
} else if (a == 5) {
|
197
|
+
int mask = (1 << b) - 1;
|
198
|
+
int block_count = (count + 2) / 3;
|
199
|
+
int last_block_count = (count + 2) % 3 + 1;
|
200
|
+
int block_size = 7 + 3 * b;
|
201
|
+
int last_block_size = (block_size * last_block_count + 2) / 3;
|
202
|
+
|
203
|
+
if (reverse) {
|
204
|
+
for (int i = 0, p = offset; i < block_count; i++, p -= block_size) {
|
205
|
+
int now_size = (i < block_count - 1) ? block_size : last_block_size;
|
206
|
+
uint_fast64_t d = bit_reverse_u64(getbits64(buf, p - now_size, now_size), now_size);
|
207
|
+
int x = (d >> b & 7) | (d >> b * 2 & 0x18) | (d >> b * 3 & 0x60);
|
208
|
+
for (int j = 0; j < 3 && n < count; j++, n++)
|
209
|
+
out[n] = (IntSeqData){ d >> (mq[j] + b * j) & mask, QuintsTable[j][x] };
|
210
|
+
}
|
211
|
+
} else {
|
212
|
+
for (int i = 0, p = offset; i < block_count; i++, p += block_size) {
|
213
|
+
uint_fast64_t d = getbits64(buf, p, (i < block_count - 1) ? block_size : last_block_size);
|
214
|
+
int x = (d >> b & 7) | (d >> b * 2 & 0x18) | (d >> b * 3 & 0x60);
|
215
|
+
for (int j = 0; j < 3 && n < count; j++, n++)
|
216
|
+
out[n] = (IntSeqData){ d >> (mq[j] + b * j) & mask, QuintsTable[j][x] };
|
217
|
+
}
|
218
|
+
}
|
219
|
+
} else {
|
220
|
+
if (reverse)
|
221
|
+
for (int p = offset - b; n < count; n++, p -= b)
|
222
|
+
out[n] = (IntSeqData){ bit_reverse_u8(getbits(buf, p, b), b), 0 };
|
223
|
+
else
|
224
|
+
for (int p = offset; n < count; n++, p += b)
|
225
|
+
out[n] = (IntSeqData){ getbits(buf, p, b), 0 };
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
void decode_block_params(const uint8_t *buf, BlockData *block_data) {
|
230
|
+
block_data->dual_plane = (buf[1] & 4) >> 2;
|
231
|
+
block_data->weight_range = (buf[0] >> 4 & 1) | (buf[1] << 2 & 8);
|
232
|
+
|
233
|
+
if (buf[0] & 3) {
|
234
|
+
block_data->weight_range |= buf[0] << 1 & 6;
|
235
|
+
switch (buf[0] & 0xc) {
|
236
|
+
case 0:
|
237
|
+
block_data->width = (*(int*)buf >> 7 & 3) + 4;
|
238
|
+
block_data->height = (buf[0] >> 5 & 3) + 2;
|
239
|
+
break;
|
240
|
+
case 4:
|
241
|
+
block_data->width = (*(int*)buf >> 7 & 3) + 8;
|
242
|
+
block_data->height = (buf[0] >> 5 & 3) + 2;
|
243
|
+
break;
|
244
|
+
case 8:
|
245
|
+
block_data->width = (buf[0] >> 5 & 3) + 2;
|
246
|
+
block_data->height = (*(int*)buf >> 7 & 3) + 8;
|
247
|
+
break;
|
248
|
+
case 12:
|
249
|
+
if (buf[1] & 1) {
|
250
|
+
block_data->width = (buf[0] >> 7 & 1) + 2;
|
251
|
+
block_data->height = (buf[0] >> 5 & 3) + 2;
|
252
|
+
} else {
|
253
|
+
block_data->width = (buf[0] >> 5 & 3) + 2;
|
254
|
+
block_data->height = (buf[0] >> 7 & 1) + 6;
|
255
|
+
}
|
256
|
+
break;
|
257
|
+
}
|
258
|
+
} else {
|
259
|
+
block_data->weight_range |= buf[0] >> 1 & 6;
|
260
|
+
switch ((*(int*)buf) & 0x180) {
|
261
|
+
case 0:
|
262
|
+
block_data->width = 12;
|
263
|
+
block_data->height = (buf[0] >> 5 & 3) + 2;
|
264
|
+
break;
|
265
|
+
case 0x80:
|
266
|
+
block_data->width = (buf[0] >> 5 & 3) + 2;
|
267
|
+
block_data->height = 12;
|
268
|
+
break;
|
269
|
+
case 0x100:
|
270
|
+
block_data->width = (buf[0] >> 5 & 3) + 6;
|
271
|
+
block_data->height = (buf[1] >> 1 & 3) + 6;
|
272
|
+
block_data->dual_plane = 0;
|
273
|
+
block_data->weight_range &= 7;
|
274
|
+
break;
|
275
|
+
case 0x180:
|
276
|
+
block_data->width = (buf[0] & 0x20) ? 10 : 6;
|
277
|
+
block_data->height = (buf[0] & 0x20) ? 6 : 10;
|
278
|
+
break;
|
279
|
+
}
|
280
|
+
}
|
281
|
+
|
282
|
+
block_data->part_num = (buf[1] >> 3 & 3) + 1;
|
283
|
+
|
284
|
+
block_data->weight_num = block_data->width * block_data->height;
|
285
|
+
if (block_data->dual_plane)
|
286
|
+
block_data->weight_num *= 2;
|
287
|
+
|
288
|
+
int weight_bits, config_bits, cem_base = 0;
|
289
|
+
|
290
|
+
switch (WeightPrecTableA[block_data->weight_range]) {
|
291
|
+
case 3:
|
292
|
+
weight_bits = block_data->weight_num * WeightPrecTableB[block_data->weight_range] + (block_data->weight_num * 8 + 4) / 5;
|
293
|
+
break;
|
294
|
+
case 5:
|
295
|
+
weight_bits = block_data->weight_num * WeightPrecTableB[block_data->weight_range] + (block_data->weight_num * 7 + 2) / 3;
|
296
|
+
break;
|
297
|
+
default:
|
298
|
+
weight_bits = block_data->weight_num * WeightPrecTableB[block_data->weight_range];
|
299
|
+
}
|
300
|
+
|
301
|
+
if (block_data->part_num == 1) {
|
302
|
+
block_data->cem[0] = *(int*)(buf + 1) >> 5 & 0xf;
|
303
|
+
config_bits = 17;
|
304
|
+
} else {
|
305
|
+
cem_base = *(int*)(buf + 2) >> 7 & 3;
|
306
|
+
if (cem_base == 0) {
|
307
|
+
int cem = buf[3] >> 1 & 0xf;
|
308
|
+
for (int i = 0; i < block_data->part_num; i++)
|
309
|
+
block_data->cem[i] = cem;
|
310
|
+
config_bits = 29;
|
311
|
+
} else {
|
312
|
+
for (int i = 0; i < block_data->part_num; i++)
|
313
|
+
block_data->cem[i] = ((buf[3] >> (i + 1) & 1) + cem_base - 1) << 2;
|
314
|
+
switch (block_data->part_num) {
|
315
|
+
case 2:
|
316
|
+
block_data->cem[0] |= buf[3] >> 3 & 3;
|
317
|
+
block_data->cem[1] |= getbits(buf, 126 - weight_bits, 2);
|
318
|
+
break;
|
319
|
+
case 3:
|
320
|
+
block_data->cem[0] |= buf[3] >> 4 & 1;
|
321
|
+
block_data->cem[0] |= getbits(buf, 122 - weight_bits, 2) & 2;
|
322
|
+
block_data->cem[1] |= getbits(buf, 124 - weight_bits, 2);
|
323
|
+
block_data->cem[2] |= getbits(buf, 126 - weight_bits, 2);
|
324
|
+
break;
|
325
|
+
case 4:
|
326
|
+
for (int i = 0; i < 4; i++)
|
327
|
+
block_data->cem[i] |= getbits(buf, 120 + i * 2 - weight_bits, 2);
|
328
|
+
break;
|
329
|
+
}
|
330
|
+
config_bits = 25 + block_data->part_num * 3;
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
if (block_data->dual_plane) {
|
335
|
+
config_bits += 2;
|
336
|
+
block_data->plane_selector = getbits(buf, cem_base ? 130 - weight_bits - block_data->part_num * 3 : 126 - weight_bits, 2);
|
337
|
+
}
|
338
|
+
|
339
|
+
int remain_bits = 128 - config_bits - weight_bits;
|
340
|
+
|
341
|
+
block_data->endpoint_value_num = 0;
|
342
|
+
for (int i = 0; i < block_data->part_num; i++)
|
343
|
+
block_data->endpoint_value_num += (block_data->cem[i] >> 1 & 6) + 2;
|
344
|
+
|
345
|
+
for (int i = 0, endpoint_bits; i < (int)(sizeof(CemTableA) / sizeof(int)); i++) {
|
346
|
+
switch (CemTableA[i]) {
|
347
|
+
case 3:
|
348
|
+
endpoint_bits = block_data->endpoint_value_num * CemTableB[i] + (block_data->endpoint_value_num * 8 + 4) / 5;
|
349
|
+
break;
|
350
|
+
case 5:
|
351
|
+
endpoint_bits = block_data->endpoint_value_num * CemTableB[i] + (block_data->endpoint_value_num * 7 + 2) / 3;
|
352
|
+
break;
|
353
|
+
default:
|
354
|
+
endpoint_bits = block_data->endpoint_value_num * CemTableB[i];
|
355
|
+
}
|
356
|
+
|
357
|
+
if (endpoint_bits <= remain_bits) {
|
358
|
+
block_data->cem_range = i;
|
359
|
+
break;
|
360
|
+
}
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
void decode_endpoints(const uint8_t *buf, BlockData *data) {
|
365
|
+
static int TritsTable[] = { 0, 204, 93, 44, 22, 11, 5 };
|
366
|
+
static int QuintsTable[] = { 0, 113, 54, 26, 13, 6 };
|
367
|
+
IntSeqData seq[32];
|
368
|
+
int ev[32];
|
369
|
+
decode_intseq(buf, data->part_num == 1 ? 17 : 29, CemTableA[data->cem_range], CemTableB[data->cem_range], data->endpoint_value_num, 0, seq);
|
370
|
+
|
371
|
+
switch (CemTableA[data->cem_range]) {
|
372
|
+
case 3:
|
373
|
+
for (int i = 0, b, c = TritsTable[CemTableB[data->cem_range]]; i < data->endpoint_value_num; i++) {
|
374
|
+
int a = (seq[i].bits & 1) * 0x1ff;
|
375
|
+
int x = seq[i].bits >> 1;
|
376
|
+
switch (CemTableB[data->cem_range]) {
|
377
|
+
case 1:
|
378
|
+
b = 0;
|
379
|
+
break;
|
380
|
+
case 2:
|
381
|
+
b = 0b100010110 * x;
|
382
|
+
break;
|
383
|
+
case 3:
|
384
|
+
b = x << 7 | x << 2 | x;
|
385
|
+
break;
|
386
|
+
case 4:
|
387
|
+
b = x << 6 | x;
|
388
|
+
break;
|
389
|
+
case 5:
|
390
|
+
b = x << 5 | x >> 2;
|
391
|
+
break;
|
392
|
+
case 6:
|
393
|
+
b = x << 4 | x >> 4;
|
394
|
+
break;
|
395
|
+
}
|
396
|
+
ev[i] = (a & 0x80) | ((seq[i].nonbits * c + b) ^ a) >> 2;
|
397
|
+
}
|
398
|
+
break;
|
399
|
+
case 5:
|
400
|
+
for (int i = 0, b, c = QuintsTable[CemTableB[data->cem_range]]; i < data->endpoint_value_num; i++) {
|
401
|
+
int a = (seq[i].bits & 1) * 0x1ff;
|
402
|
+
int x = seq[i].bits >> 1;
|
403
|
+
switch (CemTableB[data->cem_range]) {
|
404
|
+
case 1:
|
405
|
+
b = 0;
|
406
|
+
break;
|
407
|
+
case 2:
|
408
|
+
b = 0b100001100 * x;
|
409
|
+
break;
|
410
|
+
case 3:
|
411
|
+
b = x << 7 | x << 1 | x >> 1;
|
412
|
+
break;
|
413
|
+
case 4:
|
414
|
+
b = x << 6 | x >> 1;
|
415
|
+
break;
|
416
|
+
case 5:
|
417
|
+
b = x << 5 | x >> 3;
|
418
|
+
break;
|
419
|
+
}
|
420
|
+
ev[i] = (a & 0x80) | ((seq[i].nonbits * c + b) ^ a) >> 2;
|
421
|
+
}
|
422
|
+
break;
|
423
|
+
default:
|
424
|
+
switch (CemTableB[data->cem_range]) {
|
425
|
+
case 1:
|
426
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
427
|
+
ev[i] = seq[i].bits * 0xff;
|
428
|
+
break;
|
429
|
+
case 2:
|
430
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
431
|
+
ev[i] = seq[i].bits * 0x55;
|
432
|
+
break;
|
433
|
+
case 3:
|
434
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
435
|
+
ev[i] = seq[i].bits << 5 | seq[i].bits << 2 | seq[i].bits >> 1;
|
436
|
+
break;
|
437
|
+
case 4:
|
438
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
439
|
+
ev[i] = seq[i].bits << 4 | seq[i].bits;
|
440
|
+
break;
|
441
|
+
case 5:
|
442
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
443
|
+
ev[i] = seq[i].bits << 3 | seq[i].bits >> 2;
|
444
|
+
break;
|
445
|
+
case 6:
|
446
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
447
|
+
ev[i] = seq[i].bits << 2 | seq[i].bits >> 4;
|
448
|
+
break;
|
449
|
+
case 7:
|
450
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
451
|
+
ev[i] = seq[i].bits << 1 | seq[i].bits >> 6;
|
452
|
+
break;
|
453
|
+
case 8:
|
454
|
+
for (int i = 0; i < data->endpoint_value_num; i++)
|
455
|
+
ev[i] = seq[i].bits;
|
456
|
+
break;
|
457
|
+
}
|
458
|
+
}
|
459
|
+
|
460
|
+
int *v = ev;
|
461
|
+
for (int cem = 0; cem < data->part_num; v += (data->cem[cem] / 4 + 1) * 2, cem++) {
|
462
|
+
switch (data->cem[cem]) {
|
463
|
+
case 0:
|
464
|
+
set_endpoint(data->endpoints[cem], v[0], v[0], v[0], 255, v[1], v[1], v[1], 255);
|
465
|
+
break;
|
466
|
+
case 1:
|
467
|
+
{
|
468
|
+
int l0 = (v[0] >> 2) | (v[1] & 0xc0);
|
469
|
+
int l1 = clamp(l0 + (v[1] & 0x3f));
|
470
|
+
set_endpoint(data->endpoints[cem], l0, l0, l0, 255, l1, l1, l1, 255);
|
471
|
+
}
|
472
|
+
break;
|
473
|
+
case 4:
|
474
|
+
set_endpoint(data->endpoints[cem], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[3]);
|
475
|
+
break;
|
476
|
+
case 5:
|
477
|
+
bit_transfer_signed(&v[1], &v[0]);
|
478
|
+
bit_transfer_signed(&v[3], &v[2]);
|
479
|
+
v[1] += v[0];
|
480
|
+
set_endpoint_clamp(data->endpoints[cem], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[2] + v[3]);
|
481
|
+
break;
|
482
|
+
case 6:
|
483
|
+
set_endpoint(data->endpoints[cem], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, 255, v[0], v[1], v[2], 255);
|
484
|
+
break;
|
485
|
+
case 8:
|
486
|
+
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
|
487
|
+
set_endpoint(data->endpoints[cem], v[0], v[2], v[4], 255, v[1], v[3], v[5], 255);
|
488
|
+
else
|
489
|
+
set_endpoint_blue(data->endpoints[cem], v[1], v[3], v[5], 255, v[0], v[2], v[4], 255);
|
490
|
+
break;
|
491
|
+
case 9:
|
492
|
+
bit_transfer_signed(&v[1], &v[0]);
|
493
|
+
bit_transfer_signed(&v[3], &v[2]);
|
494
|
+
bit_transfer_signed(&v[5], &v[4]);
|
495
|
+
if (v[1] + v[3] + v[5] >= 0)
|
496
|
+
set_endpoint_clamp(data->endpoints[cem], v[0], v[2], v[4], 255, v[0] + v[1], v[2] + v[3], v[4] + v[5], 255);
|
497
|
+
else
|
498
|
+
set_endpoint_blue_clamp(data->endpoints[cem], v[0] + v[1], v[2] + v[3], v[4] + v[5], 255, v[0], v[2], v[4], 255);
|
499
|
+
break;
|
500
|
+
case 10:
|
501
|
+
set_endpoint(data->endpoints[cem], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, v[4], v[0], v[1], v[2], v[5]);
|
502
|
+
break;
|
503
|
+
case 12:
|
504
|
+
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
|
505
|
+
set_endpoint(data->endpoints[cem], v[0], v[2], v[4], v[6], v[1], v[3], v[5], v[7]);
|
506
|
+
else
|
507
|
+
set_endpoint_blue(data->endpoints[cem], v[1], v[3], v[5], v[7], v[0], v[2], v[4], v[6]);
|
508
|
+
break;
|
509
|
+
case 13:
|
510
|
+
bit_transfer_signed(&v[1], &v[0]);
|
511
|
+
bit_transfer_signed(&v[3], &v[2]);
|
512
|
+
bit_transfer_signed(&v[5], &v[4]);
|
513
|
+
bit_transfer_signed(&v[7], &v[6]);
|
514
|
+
if (v[1] + v[3] + v[5] >= 0)
|
515
|
+
set_endpoint_clamp(data->endpoints[cem], v[0], v[2], v[4], v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7]);
|
516
|
+
else
|
517
|
+
set_endpoint_blue_clamp(data->endpoints[cem], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7], v[0], v[2], v[4], v[6]);
|
518
|
+
break;
|
519
|
+
default:
|
520
|
+
rb_raise(rb_eStandardError, "Unsupported ASTC format");
|
521
|
+
}
|
522
|
+
}
|
523
|
+
}
|
524
|
+
|
525
|
+
void decode_weights(const uint8_t *buf, BlockData *data) {
|
526
|
+
IntSeqData seq[128];
|
527
|
+
int wv[128] = {};
|
528
|
+
decode_intseq(buf, 128, WeightPrecTableA[data->weight_range], WeightPrecTableB[data->weight_range], data->weight_num, 1, seq);
|
529
|
+
|
530
|
+
if (WeightPrecTableA[data->weight_range] == 0) {
|
531
|
+
switch (WeightPrecTableB[data->weight_range]) {
|
532
|
+
case 1:
|
533
|
+
for (int i = 0; i < data->weight_num; i++)
|
534
|
+
wv[i] = seq[i].bits ? 63 : 0;
|
535
|
+
break;
|
536
|
+
case 2:
|
537
|
+
for (int i = 0; i < data->weight_num; i++)
|
538
|
+
wv[i] = seq[i].bits << 4 | seq[i].bits << 2 | seq[i].bits;
|
539
|
+
break;
|
540
|
+
case 3:
|
541
|
+
for (int i = 0; i < data->weight_num; i++)
|
542
|
+
wv[i] = seq[i].bits << 3 | seq[i].bits;
|
543
|
+
break;
|
544
|
+
case 4:
|
545
|
+
for (int i = 0; i < data->weight_num; i++)
|
546
|
+
wv[i] = seq[i].bits << 2 | seq[i].bits >> 2;
|
547
|
+
break;
|
548
|
+
case 5:
|
549
|
+
for (int i = 0; i < data->weight_num; i++)
|
550
|
+
wv[i] = seq[i].bits << 1 | seq[i].bits >> 4;
|
551
|
+
break;
|
552
|
+
}
|
553
|
+
for (int i = 0; i < data->weight_num; i++)
|
554
|
+
if (wv[i] > 32)
|
555
|
+
++wv[i];
|
556
|
+
} else if (WeightPrecTableB[data->weight_range] == 0) {
|
557
|
+
int s = WeightPrecTableA[data->weight_range] == 3 ? 32 : 16;
|
558
|
+
for (int i = 0; i < data->weight_num; i++)
|
559
|
+
wv[i] = seq[i].nonbits * s;
|
560
|
+
} else {
|
561
|
+
if (WeightPrecTableA[data->weight_range] == 3) {
|
562
|
+
switch (WeightPrecTableB[data->weight_range]) {
|
563
|
+
case 1:
|
564
|
+
for (int i = 0; i < data->weight_num; i++)
|
565
|
+
wv[i] = seq[i].nonbits * 50;
|
566
|
+
break;
|
567
|
+
case 2:
|
568
|
+
for (int i = 0; i < data->weight_num; i++) {
|
569
|
+
wv[i] = seq[i].nonbits * 23;
|
570
|
+
if (seq[i].bits & 2)
|
571
|
+
wv[i] += 0b1000101;
|
572
|
+
}
|
573
|
+
break;
|
574
|
+
case 3:
|
575
|
+
for (int i = 0; i < data->weight_num; i++)
|
576
|
+
wv[i] = seq[i].nonbits * 11 + ((seq[i].bits << 4 | seq[i].bits >> 1) & 0b1100011);
|
577
|
+
break;
|
578
|
+
}
|
579
|
+
} else if (WeightPrecTableA[data->weight_range] == 5) {
|
580
|
+
switch (WeightPrecTableB[data->weight_range]) {
|
581
|
+
case 1:
|
582
|
+
for (int i = 0; i < data->weight_num; i++)
|
583
|
+
wv[i] = seq[i].nonbits * 28;
|
584
|
+
break;
|
585
|
+
case 2:
|
586
|
+
for (int i = 0; i < data->weight_num; i++) {
|
587
|
+
wv[i] = seq[i].nonbits * 13;
|
588
|
+
if (seq[i].bits & 2)
|
589
|
+
wv[i] += 0b1000010;
|
590
|
+
}
|
591
|
+
break;
|
592
|
+
}
|
593
|
+
}
|
594
|
+
for (int i = 0; i < data->weight_num; i++) {
|
595
|
+
int a = (seq[i].bits & 1) * 0x7f;
|
596
|
+
wv[i] = (a & 0x20) | ((wv[i] ^ a) >> 2);
|
597
|
+
if (wv[i] > 32)
|
598
|
+
++wv[i];
|
599
|
+
}
|
600
|
+
}
|
601
|
+
|
602
|
+
int ds = (1024 + data->bw / 2) / (data->bw - 1);
|
603
|
+
int dt = (1024 + data->bh / 2) / (data->bh - 1);
|
604
|
+
int pn = data->dual_plane ? 2 : 1;
|
605
|
+
|
606
|
+
for (int t = 0, i = 0; t < data->bh; t++) {
|
607
|
+
for (int s = 0; s < data->bw; s++, i++) {
|
608
|
+
int gs = (ds * s * (data->width - 1) + 32) >> 6;
|
609
|
+
int gt = (dt * t * (data->height - 1) + 32) >> 6;
|
610
|
+
int fs = gs & 0xf;
|
611
|
+
int ft = gt & 0xf;
|
612
|
+
int v = (gs >> 4) + (gt >> 4) * data->width;
|
613
|
+
int w11 = (fs * ft + 8) >> 4;
|
614
|
+
int w10 = ft - w11;
|
615
|
+
int w01 = fs - w11;
|
616
|
+
int w00 = 16 - fs - ft + w11;
|
617
|
+
|
618
|
+
for (int p = 0; p < pn; p++) {
|
619
|
+
int p00 = wv[v * pn + p];
|
620
|
+
int p01 = wv[(v + 1) * pn + p];
|
621
|
+
int p10 = wv[(v + data->width) * pn + p];
|
622
|
+
int p11 = wv[(v + data->width + 1) * pn + p];
|
623
|
+
data->weights[i][p] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4;
|
624
|
+
}
|
625
|
+
}
|
626
|
+
}
|
627
|
+
}
|
628
|
+
|
629
|
+
void select_partition(const uint8_t *buf, BlockData *data) {
|
630
|
+
int small_block = data->bw * data->bh < 31;
|
631
|
+
int seed = (*(int*)buf >> 13 & 0x3ff) | (data->part_num - 1) << 10;
|
632
|
+
|
633
|
+
uint32_t rnum = seed;
|
634
|
+
rnum ^= rnum >> 15;
|
635
|
+
rnum -= rnum << 17;
|
636
|
+
rnum += rnum << 7;
|
637
|
+
rnum += rnum << 4;
|
638
|
+
rnum ^= rnum >> 5;
|
639
|
+
rnum += rnum << 16;
|
640
|
+
rnum ^= rnum >> 7;
|
641
|
+
rnum ^= rnum >> 3;
|
642
|
+
rnum ^= rnum << 6;
|
643
|
+
rnum ^= rnum >> 17;
|
644
|
+
|
645
|
+
int seeds[8];
|
646
|
+
for (int i = 0; i < 8; i++) {
|
647
|
+
seeds[i] = (rnum >> (i * 4)) & 0xF;
|
648
|
+
seeds[i] *= seeds[i];
|
649
|
+
}
|
650
|
+
|
651
|
+
int sh[2] = { seed & 2 ? 4 : 5, data->part_num == 3 ? 6 : 5 };
|
652
|
+
|
653
|
+
if (seed & 1)
|
654
|
+
for (int i = 0; i < 8; i++)
|
655
|
+
seeds[i] >>= sh[i % 2];
|
656
|
+
else
|
657
|
+
for (int i = 0; i < 8; i++)
|
658
|
+
seeds[i] >>= sh[1 - i % 2];
|
659
|
+
|
660
|
+
if (small_block) {
|
661
|
+
for (int t = 0, i = 0; t < data->bh; t++) {
|
662
|
+
for (int s = 0; s < data->bw; s++, i++) {
|
663
|
+
int x = s << 1;
|
664
|
+
int y = t << 1;
|
665
|
+
int a = (seeds[0] * x + seeds[1] * y + (rnum >> 14)) & 0x3f;
|
666
|
+
int b = (seeds[2] * x + seeds[3] * y + (rnum >> 10)) & 0x3f;
|
667
|
+
int c = data->part_num < 3 ? 0 : (seeds[4] * x + seeds[5] * y + (rnum >> 6)) & 0x3f;
|
668
|
+
int d = data->part_num < 4 ? 0 : (seeds[6] * x + seeds[7] * y + (rnum >> 2)) & 0x3f;
|
669
|
+
data->partition[i] = (a >= b && a >= c && a >= d) ? 0 : (b >= c && b >= d) ? 1 : (c >= d) ? 2 : 3;
|
670
|
+
}
|
671
|
+
}
|
672
|
+
} else {
|
673
|
+
for (int y = 0, i = 0; y < data->bh; y++) {
|
674
|
+
for (int x = 0; x < data->bw; x++, i++) {
|
675
|
+
int a = (seeds[0] * x + seeds[1] * y + (rnum >> 14)) & 0x3f;
|
676
|
+
int b = (seeds[2] * x + seeds[3] * y + (rnum >> 10)) & 0x3f;
|
677
|
+
int c = data->part_num < 3 ? 0 : (seeds[4] * x + seeds[5] * y + (rnum >> 6)) & 0x3f;
|
678
|
+
int d = data->part_num < 4 ? 0 : (seeds[6] * x + seeds[7] * y + (rnum >> 2)) & 0x3f;
|
679
|
+
data->partition[i] = (a >= b && a >= c && a >= d) ? 0 : (b >= c && b >= d) ? 1 : (c >= d) ? 2 : 3;
|
680
|
+
}
|
681
|
+
}
|
682
|
+
}
|
683
|
+
}
|
684
|
+
|
685
|
+
void applicate_color(const BlockData *data, uint32_t *outbuf) {
|
686
|
+
if (data->dual_plane) {
|
687
|
+
int ps[] = { 0, 0, 0, 0 };
|
688
|
+
ps[data->plane_selector] = 1;
|
689
|
+
if (data->part_num > 1) {
|
690
|
+
for (int i = 0; i < data->bw * data->bh; i++) {
|
691
|
+
int p = data->partition[i];
|
692
|
+
uint_fast8_t r = select_color(data->endpoints[p][0], data->endpoints[p][4], data->weights[i][ps[0]]);
|
693
|
+
uint_fast8_t g = select_color(data->endpoints[p][1], data->endpoints[p][5], data->weights[i][ps[1]]);
|
694
|
+
uint_fast8_t b = select_color(data->endpoints[p][2], data->endpoints[p][6], data->weights[i][ps[2]]);
|
695
|
+
uint_fast8_t a = select_color(data->endpoints[p][3], data->endpoints[p][7], data->weights[i][ps[3]]);
|
696
|
+
outbuf[i] = color(r, g, b, a);
|
697
|
+
}
|
698
|
+
} else {
|
699
|
+
for (int i = 0; i < data->bw * data->bh; i++) {
|
700
|
+
uint_fast8_t r = select_color(data->endpoints[0][0], data->endpoints[0][4], data->weights[i][ps[0]]);
|
701
|
+
uint_fast8_t g = select_color(data->endpoints[0][1], data->endpoints[0][5], data->weights[i][ps[1]]);
|
702
|
+
uint_fast8_t b = select_color(data->endpoints[0][2], data->endpoints[0][6], data->weights[i][ps[2]]);
|
703
|
+
uint_fast8_t a = select_color(data->endpoints[0][3], data->endpoints[0][7], data->weights[i][ps[3]]);
|
704
|
+
outbuf[i] = color(r, g, b, a);
|
705
|
+
}
|
706
|
+
}
|
707
|
+
} else if (data->part_num > 1) {
|
708
|
+
for (int i = 0; i < data->bw * data->bh; i++) {
|
709
|
+
int p = data->partition[i];
|
710
|
+
uint_fast8_t r = select_color(data->endpoints[p][0], data->endpoints[p][4], data->weights[i][0]);
|
711
|
+
uint_fast8_t g = select_color(data->endpoints[p][1], data->endpoints[p][5], data->weights[i][0]);
|
712
|
+
uint_fast8_t b = select_color(data->endpoints[p][2], data->endpoints[p][6], data->weights[i][0]);
|
713
|
+
uint_fast8_t a = select_color(data->endpoints[p][3], data->endpoints[p][7], data->weights[i][0]);
|
714
|
+
outbuf[i] = color(r, g, b, a);
|
715
|
+
}
|
716
|
+
} else {
|
717
|
+
for (int i = 0; i < data->bw * data->bh; i++) {
|
718
|
+
uint_fast8_t r = select_color(data->endpoints[0][0], data->endpoints[0][4], data->weights[i][0]);
|
719
|
+
uint_fast8_t g = select_color(data->endpoints[0][1], data->endpoints[0][5], data->weights[i][0]);
|
720
|
+
uint_fast8_t b = select_color(data->endpoints[0][2], data->endpoints[0][6], data->weights[i][0]);
|
721
|
+
uint_fast8_t a = select_color(data->endpoints[0][3], data->endpoints[0][7], data->weights[i][0]);
|
722
|
+
outbuf[i] = color(r, g, b, a);
|
723
|
+
}
|
724
|
+
}
|
725
|
+
}
|
726
|
+
|
727
|
+
void decode_block(const uint8_t *buf, const int bw, const int bh, uint32_t *outbuf) {
|
728
|
+
if (buf[0] == 0xfc && (buf[1] & 1) == 1) {
|
729
|
+
uint_fast32_t c = color(buf[9], buf[11], buf[13], buf[15]);
|
730
|
+
for (int i = 0; i < bw * bh; i++)
|
731
|
+
outbuf[i] = c;
|
732
|
+
} else {
|
733
|
+
BlockData block_data;
|
734
|
+
block_data.bw = bw;
|
735
|
+
block_data.bh = bh;
|
736
|
+
decode_block_params(buf, &block_data);
|
737
|
+
decode_endpoints(buf, &block_data);
|
738
|
+
decode_weights(buf, &block_data);
|
739
|
+
if (block_data.part_num > 1)
|
740
|
+
select_partition(buf, &block_data);
|
741
|
+
applicate_color(&block_data, outbuf);
|
742
|
+
}
|
743
|
+
}
|
744
|
+
|
745
|
+
void decode_astc(const uint8_t *data, const int w, const int h, const int bw, const int bh, uint32_t *image) {
|
746
|
+
int bcw = (w + bw - 1) / bw;
|
747
|
+
int bch = (h + bh - 1) / bh;
|
748
|
+
int clen_last = (w + bw - 1) % bw + 1;
|
749
|
+
uint32_t *buf = (uint32_t*)calloc(bw * bh, sizeof(uint32_t));
|
750
|
+
const uint8_t *ptr = data;
|
751
|
+
for (int t = 0; t < bch; t++) {
|
752
|
+
for (int s = 0; s < bcw; s++, ptr += 16) {
|
753
|
+
decode_block(ptr, bw, bh, buf);
|
754
|
+
int clen = (s < bcw - 1 ? bw : clen_last) * 4;
|
755
|
+
for (int i = 0, y = h - t * bh - 1; i < bh && y >= 0; i++, y--)
|
756
|
+
memcpy(image + y * w + s * bw, buf + i * bw, clen);
|
757
|
+
}
|
758
|
+
}
|
759
|
+
free(buf);
|
760
|
+
}
|