mikunyan 3.9.4 → 3.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +35 -41
  4. data/Rakefile +9 -0
  5. data/exe/mikunyan-image +12 -8
  6. data/ext/decoders/native/astc.c +760 -0
  7. data/ext/decoders/native/astc.h +8 -0
  8. data/ext/decoders/native/dxtc.c +104 -0
  9. data/ext/decoders/native/dxtc.h +9 -0
  10. data/ext/decoders/native/etc.c +271 -0
  11. data/ext/decoders/native/etc.h +11 -0
  12. data/ext/decoders/native/extconf.rb +8 -0
  13. data/ext/decoders/native/main.c +167 -0
  14. data/ext/decoders/native/rgb.c +26 -0
  15. data/ext/decoders/native/rgb.h +8 -0
  16. data/lib/mikunyan/asset.rb +13 -7
  17. data/lib/mikunyan/decoders/image_decoder.rb +40 -201
  18. data/lib/mikunyan/typetrees/00ad972a9b8de1baeacb62e297cbb968.dat +0 -0
  19. data/lib/mikunyan/typetrees/01ccfe05c6fbc7ff03dcf8afa8213ff5.dat +0 -0
  20. data/lib/mikunyan/typetrees/086efb68ee41abe4e98e1ae93ae96290.dat +0 -0
  21. data/lib/mikunyan/typetrees/10355709bc95355f57466913ac850d0b.dat +0 -0
  22. data/lib/mikunyan/typetrees/1e87d82d4fd058509a3c7866db0e7356.dat +0 -0
  23. data/lib/mikunyan/typetrees/26165a24a953362edb6a7078f6536c4b.dat +0 -0
  24. data/lib/mikunyan/typetrees/266d53113fa30d2b858f2768f92eaa14.dat +0 -0
  25. data/lib/mikunyan/typetrees/2d2b1d63eb2a68ed94bbf7f50fc21d7b.dat +0 -0
  26. data/lib/mikunyan/typetrees/434b934f757d042e20f52d8c2ae20843.dat +0 -0
  27. data/lib/mikunyan/typetrees/486ba4e15dbd6aea8ac1a064305889c8.dat +0 -0
  28. data/lib/mikunyan/typetrees/49ff511929094ac12ffaa4ab38ed7bd1.dat +0 -0
  29. data/lib/mikunyan/typetrees/4dbfaa1def6adb569b550804b19b4305.dat +0 -0
  30. data/lib/mikunyan/typetrees/5bc42b93159267aabba724a6a7923603.dat +0 -0
  31. data/lib/mikunyan/typetrees/66405447c6973a81e978410c391172fe.dat +0 -0
  32. data/lib/mikunyan/typetrees/6932d6d1d46264c8680a181056f98be2.dat +0 -0
  33. data/lib/mikunyan/typetrees/6974f6c74321933ec4ba7437a55be2c3.dat +0 -0
  34. data/lib/mikunyan/typetrees/69b01db128625aa95f1f92fb890ff045.dat +0 -0
  35. data/lib/mikunyan/typetrees/6f10d8f832d5adde6982d4515b3f0bb3.dat +0 -0
  36. data/lib/mikunyan/typetrees/761ca81f78491542badc37f810ab3455.dat +0 -0
  37. data/lib/mikunyan/typetrees/76ce55d4dbaf38f5c674ea9f0a344951.dat +0 -0
  38. data/lib/mikunyan/typetrees/7e050781d08ca9d10bc74beb7e91c3b5.dat +0 -0
  39. data/lib/mikunyan/typetrees/8198e72b2e2a96b9cfa38636b5565e13.dat +0 -0
  40. data/lib/mikunyan/typetrees/84c6ac46ef89030991cbbb3fd21d2889.dat +0 -0
  41. data/lib/mikunyan/typetrees/852794becbcf95f66992da2b96a69704.dat +0 -0
  42. data/lib/mikunyan/typetrees/961be27d12d60b1b3421191d5256a876.dat +0 -0
  43. data/lib/mikunyan/typetrees/96a47566b4e135078f690a4a69935d58.dat +0 -0
  44. data/lib/mikunyan/typetrees/97da5f4688e45a57c8b42d4f42497297.dat +0 -0
  45. data/lib/mikunyan/typetrees/97ec0712102a3ea3f1cf8c0a4e47c070.dat +0 -0
  46. data/lib/mikunyan/typetrees/9eabac6ec66ffe818e008883728fcc1b.dat +0 -0
  47. data/lib/mikunyan/typetrees/a372646834bcaf26eab1d21b29e39553.dat +0 -0
  48. data/lib/mikunyan/typetrees/a4f194097b08bc4c5019c3a4ea6f5cbd.dat +0 -0
  49. data/lib/mikunyan/typetrees/af863b6969b9b82be9450f0574339f65.dat +0 -0
  50. data/lib/mikunyan/typetrees/b0adafbe24f8148ebf01794ee6679925.dat +0 -0
  51. data/lib/mikunyan/typetrees/b14bcb0865632d1b2d6e215a000e4c0f.dat +0 -0
  52. data/lib/mikunyan/typetrees/b35bf02952f2946208ff6b4deca3a6a9.dat +0 -0
  53. data/lib/mikunyan/typetrees/b6bbd0e88d1feb636d89bd766ea5934f.dat +0 -0
  54. data/lib/mikunyan/typetrees/b78821b6aeb5b79c8961728a9f068024.dat +0 -0
  55. data/lib/mikunyan/typetrees/bea915a8ab3d9b55e80c969a22e692d3.dat +0 -0
  56. data/lib/mikunyan/typetrees/c184743520186f546000de20f4d19736.dat +0 -0
  57. data/lib/mikunyan/typetrees/d50ed13362e98df8096b2f735131fce5.dat +0 -0
  58. data/lib/mikunyan/typetrees/d871346d990bbc294d02f4c366bf1b6d.dat +0 -0
  59. data/lib/mikunyan/typetrees/d8e8eeb43589ccd7019398e56f6c16b0.dat +0 -0
  60. data/lib/mikunyan/typetrees/daea1bb1bba6613afb2cb001ca8fa0d4.dat +0 -0
  61. data/lib/mikunyan/typetrees/db088f9c2f2224da9f488879467856e5.dat +0 -0
  62. data/lib/mikunyan/typetrees/e7c5c01b0369574e9346ce846e1e8e63.dat +0 -0
  63. data/lib/mikunyan/typetrees/f123b055a61dfa7dc679d78cdaecd383.dat +0 -0
  64. data/lib/mikunyan/typetrees/f92d618c5266ea3a8ca770b6eca728c8.dat +0 -0
  65. data/lib/mikunyan/typetrees/fad2d0a58e9174708176102b418facf1.dat +0 -0
  66. data/lib/mikunyan/typetrees/ff001a2e51937aa5add9eaf9cd3d8ae4.dat +0 -0
  67. data/lib/mikunyan/version.rb +1 -1
  68. data/mikunyan.gemspec +1 -0
  69. metadata +63 -4
  70. 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: 3fa0e08afb0e0451f374cf94e9980f6f3b2a7ad279440b8d7d4e8a26426384f6
4
- data.tar.gz: 31032deca5a1c100086c78c67a3c3b3bc899b66d08c97ab12fcb19980a2e70f3
3
+ metadata.gz: 1d98bb997b5988424bf6ac0a0f116965bbd4cb5959bde3cad40541143872ab93
4
+ data.tar.gz: d77ddb35f213bd0d0729dfe9b53b2f6fa125687b2e89a79fbe876a72a8a7d7a7
5
5
  SHA512:
6
- metadata.gz: 7bb6fdd93d68c6816d37f8cc6ab988672b2b2b6eab969faa71d79e98261e79c4a0376ab5d2989895537d54985426c1269eda763d13e9b73a452b72d7d626e3bc
7
- data.tar.gz: 8f9816d0bdf13fb919257c853f45591a2e668d89c0800387d00ff778b567071187982d861cbffeb3b11930dc19be9ebb5c08de5e0e0d091b530f80692966a9e4
6
+ metadata.gz: 839775366553bae8d90525e47088cbe9d42c59638ffcd1964411f7b006af89b6eb9893392be81b456ce599678155c87213c1a59a4c79759990b2a5724c89b3a0
7
+ data.tar.gz: 8138498cac6cd2a845321be929e936520e2f535a5195dad604561bd98f021a5ce2463219fb8996a7a2cd8f05dfbf90370487b12620bbf91e1e4b4c85dfe25cd7
data/.gitignore CHANGED
@@ -12,4 +12,6 @@
12
12
  # rspec failure tracking
13
13
  .rspec_status
14
14
 
15
+ *.bundle
16
+
15
17
  .DS_Store
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # mikunyan
2
2
 
3
- Library to deserialize Unity AssetBundle files (\*.unity3d) and asset files.
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 AssetBundle from blob
43
+ # you can also load a bundle from blob
40
44
  # bundle = Mikunyan::AssetBundle.load(blob)
41
45
 
42
- # select asset (normaly only one 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
- # object list
52
+ # get a list of objects
49
53
  list = asset.objects
50
54
 
51
- # object PathIds
55
+ # get PathIds of objects
52
56
  path_ids = asset.path_ids
53
57
 
54
- # object container table (if available)
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
- # simplified structure (based on Hash)
64
+ # load an object to Ruby data structures
61
65
  obj_hash = asset.parse_object_simple(path_ids[0])
62
66
 
63
- # hash can be easily serialized to json
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. Value, array and map.
74
+ `Mikunyan::ObjectValue` can be 3 types: value, array and key-value table.
71
75
 
72
76
  ```ruby
73
- # You can get whether obj is value or not
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
- # You can get whether obj is array or not
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
- # If obj is map, you can get keys
97
+ # get keys (if obj is key-value table)
94
98
  obj.keys
95
99
 
96
- # get child object
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 png file directly from Texture2D asset. Output object's class is `ChunkyPNG::Image`.
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, 47), and ASTC (48–59) are available.
111
+ Some basic texture formats (1–5, 7, 9, 13–20, 22, 62, and 63), DXT1 (10), DXT5 (12), ETC_RGB4 (34), ETC2 (4547), 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 Image object
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 json.
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 AssetBudnle but Asset
133
- - `--pretty` (`-p`): prettify output json
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 json data of output textures as below.
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 log json also contains sprite information.
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 AssetBudnle but Asset
219
- - `--outputdir` (`-o`): output directory (default is a basename of input file without an extention)
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 json
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
- ## FAQ
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
- [Miku Maekawa](http://www.project-imas.com/wiki/Miku_Maekawa).
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]
@@ -54,15 +54,18 @@ assets.each do |asset|
54
54
  json = {}
55
55
  textures = {}
56
56
 
57
- asset.path_ids.select{|path_id| asset.object_type(path_id) == 'Sprite'}.each do |path_id|
58
- obj = asset.parse_object(path_id)
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
- textures[tex_id] = Mikunyan::ImageDecoder.decode_object(tex_obj) if tex_obj
65
- json[tex_id] = {:name => tex_obj.m_Name.value, :width => textures[tex_id].width, :height => textures[tex_id].height, :path_id => tex_id, :sprites => []}
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.path_ids.select{|path_id| asset.object_type(path_id) == 'Texture2D'}.each do |path_id|
82
- obj = asset.parse_object(path_id)
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
+ }