OXYGENHUB
◆ main openmsx / src / video / scalers / hq_gen.py
10.2 KiB · Python · last changed chore(): initial commit 1 month ago source blame history raw
1
from functools import reduce
2
3
# Edges in the same order as the edge bits in "case".
4
#   0 | 1 | 2
5
#  ---+---+---
6
#   3 | 4 | 5
7
#  ---+---+---
8
#   6 | 7 | 8
9
edges = (
10
	(1, 5), (5, 7), (3, 7), (1, 3),   # first 4 are cross-edges
11
	(0, 4), (1, 4), (2, 4), (3, 4),   # followed by 8 star-edges
12
	(4, 5), (4, 6), (4, 7), (4, 8),
13
	)
14
15
def computeCasePermutation(neighbourPermutation):
16
	return tuple(
17
		edges.index(tuple(sorted(
18
			(neighbourPermutation[n1], neighbourPermutation[n2])
19
			)))
20
		for n1, n2 in edges
21
		)
22
23
def permute(seq, permutation):
24
	seq = tuple(seq)
25
	assert len(seq) == len(permutation)
26
	return tuple(seq[index] for index in permutation)
27
28
def permuteCase(case, permutation):
29
	return sum(
30
		((case >> newBit) & 1) << oldBit
31
		for newBit, oldBit in enumerate(permutation)
32
		)
33
34
def gcd(a, b):
35
	'''Returns the greatest common divisor of a and b.
36
	'''
37
	while a != 0:
38
		a, b = b % a, a
39
	return b
40
41
def simplifyWeights(weights):
42
	'''Returns the lowest weight values of which the ratios are equal to the
43
	given weights.
44
	'''
45
	weights = tuple(weights)
46
	divider = reduce(gcd, weights, 0)
47
	return tuple(w // divider for w in weights)
48
49
def expandTopLeftWeights(weights):
50
	return weights[0 : 2] + (0, ) + weights[2 : 4] + (0, 0, 0, 0)
51
52
def expandQuadrant(topLeftQuadrant, zoom):
53
	quadrantWidth = (zoom + 1) // 2
54
	assert quadrantWidth ** 2 == len(topLeftQuadrant[0])
55
	mirrorMap = [None] * (zoom ** 2)
56
	permId = (0, 1, 2, 3, 4, 5, 6, 7, 8)
57
	permLR = (2, 1, 0, 5, 4, 3, 8, 7, 6)
58
	permTB = (6, 7, 8, 3, 4, 5, 0, 1, 2)
59
	for quadrantIndex in range(quadrantWidth ** 2):
60
		qy, qx = divmod(quadrantIndex, quadrantWidth)
61
		for ty, py in ((zoom - qy - 1, permTB), (qy, permId)):
62
			for tx, px in ((zoom - qx - 1, permLR), (qx, permId)):
63
				nPerm = permute(px, py)
64
				cPerm = computeCasePermutation(nPerm)
65
				mirrorMap[ty * zoom + tx] = (quadrantIndex, cPerm, nPerm)
66
	return [
67
		[	permute(
68
				expandTopLeftWeights(
69
					topLeftQuadrant[permuteCase(case, cPerm)][quadrantIndex]
70
					),
71
				nPerm
72
				)
73
			for quadrantIndex, cPerm, nPerm in mirrorMap
74
			]
75
		for case in range(len(topLeftQuadrant))
76
		]
77
78
def computeZ2S0W0(case):
79
	if (case & 0xFF8) in (
80
		0x0A0, 0x1A0, 0x2A0, 0x3A0, 0x4A0, 0x5A0, 0x7A0,
81
		0x8A0, 0x9A0, 0xAA0, 0xBA0, 0xCA0, 0xDA0, 0xEA0,
82
		0x1A8, 0x4A8,
83
		0x0E0, 0x2E0, 0x4E0, 0x5E0,0x8E0, 0x9E0, 0xAE0, 0xCE0
84
		):
85
		return 0
86
	elif (case & 0x0B0) == 0:
87
		return 0
88
	elif (case & 0x010) == 0x010:
89
		return 0
90
	else:
91
		return 4
92
93
def computeZ2S0W1(case):
94
	if (case & 0xFF8) in (
95
		0x2A0, 0xAA0, 0x2B0, 0xAB0, 0xBB0, 0xCF0, 0x0E0, 0x8E0, 0x0F0, 0x8F0
96
		):
97
		return 6
98
	elif (case & 0x3FC) in (0x1D0, 0x1D8, 0x1F0, 0x1F4):
99
		return 4
100
	elif (case & 0x0B4) in (0x000, 0x010, 0x080, 0x004, 0x014, 0x084, 0x094):
101
		return 4
102
	elif (case & 0xFF1) in (0x130, 0x170, 0x330, 0x370, 0x770):
103
		return 4
104
	elif (case & 0xFF4) in (
105
		0x0D0, 0x2D0, 0x3D0, 0x8D0, 0xAD0, 0xBD0, 0xCD0, 0xED0, 0xFD0,
106
		0x090, 0x190, 0x290, 0x390, 0x590, 0x790,
107
		0x890, 0x990, 0xA90, 0xB90, 0xC90, 0xD90, 0xE90, 0xF90
108
		):
109
		return 4
110
	elif (case & 0xFF8) in (
111
		0x0A0, 0x1A0, 0x4A0, 0x8A0,
112
		0x0B0, 0x1B0, 0x3B0, 0x4B0, 0x5B0, 0x6B0, 0x7B0,
113
		0x8B0, 0x9B0, 0xCB0, 0xDB0, 0xEB0, 0xFB0,
114
		0x4F0
115
		):
116
		return 4
117
	elif (case & 0xFF8) in (
118
		0x3A0, 0x5A0, 0x7A0, 0x9A0, 0xBA0, 0xCA0, 0xDA0, 0xEA0,
119
		0x2E0, 0x4E0, 0x5E0, 0x9E0, 0xAE0, 0xCE0
120
		):
121
		return 2
122
	elif (case & 0xFF4) in (0x490, 0x4D0, 0x690, 0x6D0, 0x7D0):
123
		return 2
124
	elif (case & 0x2F8) == 0x2F0:
125
		return 1
126
	else:
127
		return 0
128
129
def genExpr2():
130
	quadrant = [
131
		[ None ]
132
		for case in range(1 << 12)
133
		]
134
	casePerm = computeCasePermutation((0, 3, 6, 1, 4, 7, 2, 5, 8))
135
136
	for case in range(1 << 12):
137
		w0 = computeZ2S0W0(case)
138
		w1 = computeZ2S0W1(case)
139
		w2 = computeZ2S0W1(permuteCase(case, casePerm))
140
		quadrant[case][0] = simplifyWeights((w0, w1, w2, 16 - w0 - w1 - w2))
141
142
	return quadrant
143
144
def computeZ3S0W0(case):
145
	if (case & 0xFF8) in (0x1A8, 0x4A8, 0x5E0, 0x7A0, 0x9E0, 0xEA0):
146
		return 0
147
	elif (case & 0x7F8) in (
148
		0x0A0, 0x0E0, 0x1A0, 0x2A0, 0x2E0, 0x3A0, 0x4A0, 0x4E0, 0x5A0
149
		):
150
		return 0
151
	elif (case & 0x0B0) == 0x000:
152
		return 0
153
	elif (case & 0x010) == 0x010:
154
		return 0
155
	else:
156
		return 4
157
158
def computeZ3S0W1(case):
159
	if (case & 0xFF8) in (
160
		0x0E0, 0x0F0, 0x2A0, 0x2B0, 0x8E0, 0x8F0, 0xAA0, 0xAB0, 0xBB0, 0xCF0
161
		):
162
		return 8
163
	elif (case & 0xFF8) in (
164
		0x0A0, 0x1A0, 0x4A0, 0x8A0,
165
		0x1F0, 0x4F0, 0x5F0, 0x9F0, 0xDF0,
166
		0x0B0, 0x1B0, 0x3B0, 0x4B0, 0x5B0, 0x6B0, 0x7B0,
167
		0x8B0, 0x9B0, 0xCB0, 0xDB0, 0xEB0, 0xFB0
168
		):
169
		return 7
170
	elif (case & 0xFF1) in (0x130, 0x170, 0x330, 0x370, 0x770):
171
		return 4
172
	elif (case & 0xFF8) in (
173
		0x3A0, 0x5A0, 0x7A0, 0x9A0, 0xBA0, 0xCA0, 0xDA0, 0xEA0,
174
		0x2E0, 0x4E0, 0x5E0, 0x9E0, 0xAE0, 0xCE0,
175
		0x2F0, 0x3F0, 0x6F0, 0x7F0, 0xAF0, 0xBF0, 0xEF0, 0xFF0
176
		):
177
		return 4
178
	elif (case & 0x0F0) in (0x000, 0x010, 0x040, 0x050, 0x090, 0x0D0):
179
		return 4
180
	else:
181
		return 0
182
183
def computeZ3S1W1(case):
184
	if (case & 0xFF1) in (0x170, 0x130, 0x330, 0x370, 0x770):
185
		return 12
186
	elif (case & 0xFF8) in (0x0E0, 0x0F0, 0x8E0, 0x8F0, 0xCF0):
187
		return 12
188
	elif (case & 0xFF1) in (0x920, 0x960, 0xB20, 0xB60, 0xBE0):
189
		return 4
190
	elif (case & 0xFF8) in (0x2A0, 0x2B0, 0xAA0, 0xAB0, 0xBB0):
191
		return 4
192
	elif (case & 0x020) == 0:
193
		return 4
194
	elif (case & 0xFF1) in (
195
		0x120, 0x160, 0x1E0, 0x320, 0x360, 0x3E0,
196
		0x520, 0x560, 0x570, 0x5E0, 0x760, 0x7E0,
197
		0x9E0, 0xD60, 0xDE0, 0xDF0, 0xF60, 0xFE0
198
		):
199
		return 2
200
	elif (case & 0xFF8) in (
201
		0x0A0, 0x0B0, 0x1B0, 0x3B0, 0x4A0, 0x4B0,
202
		0x4F0, 0x5B0, 0x6B0, 0x7B0, 0x7F0, 0x8A0,
203
		0x8B0, 0x9B0, 0xCB0, 0xDB0, 0xEB0, 0xFB0
204
		):
205
		return 2
206
	else:
207
		return 0
208
209
def genExpr3():
210
	quadrant = [
211
		[ None ] * 4
212
		for case in range(1 << 12)
213
		]
214
	quadrantPerm = (0, 2, 1, 3)
215
	casePerm = computeCasePermutation((0, 3, 6, 1, 4, 7, 2, 5, 8))
216
217
	for case in range(1 << 12):
218
		w0 = computeZ3S0W0(case)
219
		w1 = computeZ3S0W1(case)
220
		w2 = computeZ3S0W1(permuteCase(case, casePerm))
221
		weights = (w0, w1, w2, 16 - w0 - w1 - w2)
222
		quadrant[case][0] = simplifyWeights(weights)
223
224
	for case in range(1 << 12):
225
		w1 = computeZ3S1W1(case)
226
		weights = (0, w1, 0, 16 - w1)
227
		quadrant[case][1] = simplifyWeights(weights)
228
229
	for case in range(1 << 12):
230
		mirrorCase = permuteCase(case, casePerm)
231
		quadrant[case][2] = permute(quadrant[mirrorCase][1], quadrantPerm)
232
233
	for case in range(1 << 12):
234
		quadrant[case][3] = (0, 0, 0, 1)
235
236
	return quadrant
237
238
def computeZ4S0W0(case):
239
	if (case & 0xFF8) in (
240
		0x1A8, 0x4A8,
241
		0x0A0, 0x1A0, 0x2A0, 0x3A0, 0x4A0, 0x5A0, 0x7A0,
242
		0x8A0, 0x9A0, 0xAA0, 0xBA0, 0xCA0, 0xDA0, 0xEA0,
243
		0x0E0, 0x2E0, 0x4E0, 0x5E0, 0x8E0, 0x9E0, 0xAE0, 0xCE0
244
		):
245
		return 0
246
	elif (case & 0x0B0) == 0:
247
		return 0
248
	elif (case & 0x010) == 0x010:
249
		return 0
250
	else:
251
		return 6
252
253
def computeZ4S0W1(case):
254
	if (case & 0xFF8) in (
255
		0x0A0, 0x1A0, 0x2A0, 0x4A0, 0x8A0, 0xAA0,
256
		0x0E0, 0x8E0,
257
		0x0F0, 0x1F0, 0x4F0, 0x5F0, 0x8F0, 0x9F0, 0xCF0, 0xDF0
258
		):
259
		return 8
260
	elif (case & 0x0F8) == 0x0B0:
261
		return 8
262
	elif (case & 0xFF4) in (
263
		0x090, 0x190, 0x290, 0x390, 0x590, 0x790,
264
		0x890, 0x990, 0xB90, 0xC90, 0xE90, 0xA90, 0xD90, 0xF90,
265
		0x0D0, 0x1D0, 0x2D0, 0x3D0, 0x5D0,
266
		0x8D0, 0x9D0, 0xAD0, 0xBD0, 0xCD0, 0xDD0, 0xED0, 0xFD0
267
		):
268
		return 6
269
	elif (case & 0x0B4) == 0x094:
270
		return 6
271
	elif (case & 0xFF1) in (
272
		0x130, 0x170, 0x330, 0x370, 0x770
273
		):
274
		return 4
275
	elif (case & 0xFF8) in (
276
		0x3A0, 0x5A0, 0x7A0, 0x9A0, 0xBA0, 0xCA0, 0xDA0, 0xEA0,
277
		0x2E0, 0x4E0, 0x5E0, 0x9E0, 0xAE0, 0xCE0,
278
		0x2F0, 0x3F0, 0x6F0, 0x7F0, 0xAF0, 0xBF0, 0xEF0, 0xFF0
279
		):
280
		return 4
281
	elif (case & 0x0A0) == 0:
282
		return 4
283
	else:
284
		return 0
285
286
def computeZ4S1W0(case):
287
	if (case & 0xFF8) in (
288
		0x6A0, 0xFA0,
289
		0x1E0, 0xDE0, 0x6E0, 0xEE0, 0x3E0, 0x7E0, 0xBE0, 0xFE0,
290
		0x9A8, 0xCA8, 0x0A8, 0x8A8, 0x5A8, 0xDA8,
291
		0x2A8, 0x3A8, 0x6A8, 0x7A8, 0xAA8, 0xBA8, 0xEA8, 0xFA8
292
		):
293
		return 4
294
	elif (case & 0x0F8) in (0x020, 0x060, 0x028, 0x068, 0x0E8):
295
		return 4
296
	elif (case & 0x0B0) == 0x080:
297
		return 2
298
	else:
299
		return 0
300
301
def computeZ4S1W1(case):
302
	if (case & 0xFF1) in (0x130, 0x170, 0x330, 0x370, 0x770):
303
		return 12
304
	elif (case & 0xFF8) in (0x0E0, 0x0F0, 0x8E0, 0x8F0, 0xCF0):
305
		return 10
306
	elif (case & 0xFF8) in (
307
		0x0A0, 0x1A0, 0x2A0, 0x4A0, 0x8A0, 0xAA0,
308
		0x1F0, 0x4F0, 0x5F0, 0x9F0, 0xDF0
309
		):
310
		return 8
311
	elif (case & 0x0F8) == 0x0B0:
312
		return 8
313
	elif (case & 0x0B0) == 0x090:
314
		return 6
315
	elif (case & 0xFF8) in (
316
		0x3A0, 0x5A0, 0x7A0, 0x9A0, 0xBA0, 0xCA0, 0xDA0, 0xEA0,
317
		0x2E0, 0x4E0, 0x5E0, 0xAE0, 0x9E0, 0xCE0,
318
		):
319
		return 4
320
	elif (case & 0x0B0) in (0x000, 0x010, 0x080):
321
		return 4
322
	else:
323
		return 0
324
325
def computeZ4S1W2(case):
326
	if (case & 0xFF8) in (0x0E0, 0x0F0, 0x8E0, 0x8F0, 0xCF0):
327
		return 6
328
	elif (case & 0xFF8) in (0x2A0, 0x2B0, 0xAA0, 0xAB0, 0xBB0):
329
		return 4
330
	elif (case & 0xFF1) in (
331
		0x030, 0x230, 0x430, 0x530, 0x630, 0x730,
332
		0x830, 0x930, 0xA30, 0xB30, 0xC30, 0xD30, 0xE30, 0xF30,
333
		0x070, 0x270, 0x470, 0x570, 0x670,
334
		0x870, 0x970, 0xA70, 0xB70, 0xC70, 0xD70, 0xE70, 0xF70,
335
		):
336
		return 2
337
	elif (case & 0x0B1) in (0x000, 0x001, 0x010, 0x011, 0x031):
338
		return 2
339
	else:
340
		return 0
341
342
def computeZ4S3W0(case):
343
	if (case & 0xFF8) in (
344
		0x1A8, 0x4A8,
345
		0x0A0, 0x1A0, 0x2A0, 0x3A0, 0x4A0, 0x5A0, 0x7A0,
346
		0x8A0, 0x9A0, 0xAA0, 0xBA0, 0xCA0, 0xDA0, 0xEA0,
347
		0x0E0, 0x2E0, 0x4E0, 0x5E0, 0x8E0, 0x9E0, 0xAE0, 0xCE0,
348
		):
349
		return 0
350
	elif (case & 0x0B0) == 0:
351
		return 0
352
	elif (case & 0x010) == 0x010:
353
		return 0
354
	else:
355
		return 2
356
357
def computeZ4S3W1(case):
358
	if (case & 0xFF8) in (
359
		0x2A0, 0x2B0, 0xAA0,
360
		0xAB0, 0xBB0,
361
		0x0E0, 0x8E0,
362
		0x0F0, 0x8F0, 0xCF0
363
		):
364
		return 2
365
	elif (case & 0x0B0) in (0x000, 0x010, 0x090):
366
		return 2
367
	else:
368
		return 0
369
370
def genExpr4():
371
	quadrant = [
372
		[ None ] * 4
373
		for case in range(1 << 12)
374
		]
375
	quadrantPerm = (0, 2, 1, 3)
376
	casePerm = computeCasePermutation((0, 3, 6, 1, 4, 7, 2, 5, 8))
377
378
	for case in range(1 << 12):
379
		w0 = computeZ4S0W0(case)
380
		w1 = computeZ4S0W1(case)
381
		w2 = computeZ4S0W1(permuteCase(case, casePerm))
382
		quadrant[case][0] = simplifyWeights((w0, w1, w2, 16 - w0 - w1 - w2))
383
384
	for case in range(1 << 12):
385
		w0 = computeZ4S1W0(case)
386
		w1 = computeZ4S1W1(case)
387
		w2 = computeZ4S1W2(case)
388
		quadrant[case][1] = simplifyWeights((w0, w1, w2, 16 - w0 - w1 - w2))
389
390
	for case in range(1 << 12):
391
		mirrorCase = permuteCase(case, casePerm)
392
		quadrant[case][2] = permute(quadrant[mirrorCase][1], quadrantPerm)
393
394
	for case in range(1 << 12):
395
		w0 = computeZ4S3W0(case)
396
		w1 = computeZ4S3W1(case)
397
		w2 = computeZ4S3W1(permuteCase(case, casePerm))
398
		quadrant[case][3] = simplifyWeights((w0, w1, w2, 16 - w0 - w1 - w2))
399
400
	return quadrant