It is currently Tue Oct 17, 2017 10:55 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Mon Jun 26, 2017 3:41 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1398
As far as I see, the R, G and B components of colors in SNES emulators like ZSNES are converted like this:

PcValue = SnesValue * 256 / 32

This has the strange behavior that white is 248,248,248 instead of 255,255,255.

Then I've read some stuff about replicating the top three bits into the bottom three bits to get to the full range. Which sounds totally random and nonsensical to me. Why should you ever do this? In how far do the upper and the lower bits have any connection to each other to ever justify this kind of behavior?

Why don't they simply use the formula:

PcValue = SnesValue * 255 / 31

In this case, white is actually 255,255,255 and black is still 0,0,0.

And the colors (well, their exact values, not the rounded integers) are still evenly distributed.

So, why this crappy calculation with 32 and 256 instead of 31 and 255? And why some strange hack about replicating bits that have nothing to do with each other?

If calculating with 31 and 255 is a speed issue: Just declare a lookup array. It takes you exactly 32 bytes of space. Then you can do:
PcValue = AllPcValues[SnesValue]

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 5:19 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7224
Location: Chexbres, VD, Switzerland
Quote:
PcValue = SnesValue * 255 / 31

Indeed, that's the correct way to do it - mapping linear values from 0 to 31 to another linear space from 0 to 255.

Quote:
Then I've read some stuff about replicating the top three bits into the bottom three bits to get to the full range. Which sounds totally random and nonsensical to me. Why should you ever do this?

It's not random, it's roughly equivalent to the formula you proposed. The forumula you call bullshit nonsensical would be that :
Code:
pc_colour = (SNES_colour << 3) | (SNES_colour >> 2)

Which is equivalent to
Code:
pc_colour = (SNES_colour * 8) + (SNES_colour / 4)

Which is equivalent to
Code:
pc_colour = SNES_colour * 33 / 4


In both cases, we're linearly mapping colours by multiplying by an integer slightly bigger than 8, because multiplying by 8 leads to the problem that whites are not pure white. Whether this integer is 255/31 (8.2258) or 33/4 (8.25) is almost insignificant, since the new value will be rounded to an integer anyway.

I've tested this on excel. Basically it either makes no difference or there's a difference of '1' which is basically a rounding error. The first column is using the fraction 255/31, the second using 33/4, in both cases rounded towards 0 (floor).
Code:
0     0     0
1     8     8
2    16    16
3    24    24
4    32    33
5    41    41
6    49    49
7    57    57
8    65    66
9    74    74
10   82    82
11   90    90
12   98    99
13   106   107
14   115   115
15   123   123
16   131   132
17   139   140
18   148   148
19   156   156
20   164   165
21   172   173
22   180   181
23   189   189
24   197   198
25   205   206
26   213   214
27   222   222
28   230   231
29   238   239
30   246   247
31   255   255


As to why ZSNES did not map colours the proper way, I have no idea but the most likely explanation is that they were just lazy :)


Last edited by Bregalad on Mon Jun 26, 2017 7:44 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 5:59 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19093
Location: NE Indiana, USA (NTSC)
That and / is a fairly expensive operation that's hard to pipeline. A multiplication by 8 or by 33/4 might allow more throughput on an old Pentium than a formula involving a division by 31.


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 6:08 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1398
Bregalad wrote:
The forumula you call bullshit

I didn't call it that.

But thanks for the elaboration. I didn't really understand what they meant.
I would still prefer the 31 and 255 calculation though. It just looks cleaner to me.

tepples wrote:
That and / is a fairly expensive operation that's hard to pipeline. A multiplication by 8 or by 33/4 might allow more throughput on an old Pentium than a formula involving a division by 31.

But shouldn't an emulator strive to be as accurate as possible and not use some cheapshots just because of a simple division?
As I said: If the processor is too slow, it's a mere 32 bytes for a lookup table here.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 7:53 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7224
Location: Chexbres, VD, Switzerland
DRW wrote:
I didn't call it that.

Sorry, I fixed my post.

Quote:
I would still prefer the 31 and 255 calculation though. It just looks cleaner to me.

Both calculations sets a linear slope so that 0->0 and 31 -> 255. But it all comes down to rounding, the version based on bit shifts ignores the bits shifted out, so it actually sets the second point to 31 -> 255.75 because 2 set bits are shifted out on the right. So both can be seen as technically correct, it depends if you consider full white to be "exactly" 255 or if you consider it "all bits set" (including bits which are eventually dropped).

Quote:
But shouldn't an emulator strive to be as accurate as possible and not use some cheapshots just because of a simple division?

ZSNES is definitely inaccurate - their goal were to run as many SNES games as possible on late-1990s PCs. It's pretty much the Nesticle of SNES emulation. As I said lazyness is the only reason I see why they didn't scale colours properly.
Since the screen is entirely a bit more dim, I guess the eyes just get used to it and see (240, 240, 240) as white, even though it's technically not the brightest possible colour.


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 10:10 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10049
Location: Rio de Janeiro - Brazil
Bregalad wrote:
Both calculations sets a linear slope so that 0->0 and 31 -> 255. But it all comes down to rounding

It's not like an off-by-one error in some values makes any difference in this case, though. Also, there are so few input values that you can easily build a look-up table for this and have the output be as precise as you want.


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 11:08 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1398
So, which emulator is the Nestopia of the Super Nintendo?

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 11:56 am 
Offline
User avatar

Joined: Wed Feb 13, 2008 9:10 am
Posts: 575
Location: Estonia, Rapla city (50 and 60Hz compatible :P)
bsnes/higan

_________________
http://www.tmeeco.eu


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 12:11 pm 
Offline

Joined: Tue Oct 06, 2015 10:16 am
Posts: 554
DRW wrote:
As I said: If the processor is too slow, it's a mere 32 bytes for a lookup table here.

Your perception is colored by the NES. Memory access on PC platforms is not 1-2 cycles slower like on the NES, it's often 100 cycles slower. For something executed for every pixel, it really matters on slow processors.


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 12:18 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1398
calima wrote:
Your perception is colored by the NES.

Actually, my perception is colored by writing programs for regular PCs where a simple division or an array lookup was never really the bottleneck when any of my programs were slow, even on a computer from 1999.
But yeah, I don't really know in how far this would be an issue for an emulator.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 3:50 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 798
Location: Sweden
Bsnes/higan is not only Nestopia but also the Nintendulator of SNES emulators I guess. It's designed to be as hardware accurate as possible. Zsnes is a very old emulator and not very good anymore. It used to be very popular because of its decent compatibility, nice built-in gui and the fact that no highly accurate emulators existed for SNES back then.


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 5:10 pm 
Offline

Joined: Sun Mar 19, 2006 9:44 pm
Posts: 913
Location: Japan
DRW wrote:
Then I've read some stuff about replicating the top three bits into the bottom three bits to get to the full range. Which sounds totally random and nonsensical to me. Why should you ever do this? In how far do the upper and the lower bits have any connection to each other to ever justify this kind of behavior?

They have a connection with each other because you are doing a division in which the denominator will always generate a repeating fraction in decimal. The same also applies to any number base system (binary, in this case). The repeating values to the right of the decimal point will use values from the left of the decimal. (I explained it a bit more in this post: viewtopic.php?f=5&t=12739&p=146789#p146789 )

_________________
http://www.chrismcovell.com


Top
 Profile  
 
PostPosted: Mon Jun 26, 2017 5:34 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5711
Location: Canada
DRW wrote:
Then I've read some stuff about replicating the top three bits into the bottom three bits to get to the full range. Which sounds totally random and nonsensical to me. Why should you ever do this? In how far do the upper and the lower bits have any connection to each other to ever justify this kind of behavior?

It's a pretty reasonable approximation to the ideal 255 / 31 conversion:

Code:
; three equivalent operations;
31 * 256 / 32 = 248
31 * 8 = 248
31 << 3 = 248 ; note how the low 3 bits are unused

; attempting to fill the empty 3 bits with a scaled down version of the result:
248 + (248 >> 5) = 255
248 + (248 / 32) = 255.75
31 * (8 + (8/32)) = 255.75
31 * 8.25 = 255.75

; note how close this is to the ideal:
31 * (255 / 31) = 255
31 * ~8.226 = ~255

; another way of looking at the same approximation is
; the original shifted left to fill the top 5 bits,
; and shifted right to fill the bottom 3 bits:
(31 << 3) + (31 >> 2) = 255
(31 * 8) + (31 / 4) = 255.75

In this approximation, the low 3 bits go from 0-7 across the input range 0-31, and the high 5 bits go from 0-31. It results in all bits set at 31, and all bits clear at 0, and has an regular monotonic increase in between.

It's similar to the way that you can represent a multiplication with a shift and sum, just working the other way for division:
Code:
x * 248
= x * (128 + 64 + 32 + 16 + 8)
= (x << 7) + (x << 6) + (x << 5) + (x << 4) + (x << 3)


Top
 Profile  
 
PostPosted: Tue Jun 27, 2017 3:42 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1398
Thanks for all the information.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Thu Jun 29, 2017 9:57 pm 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 190
calima wrote:
DRW wrote:
As I said: If the processor is too slow, it's a mere 32 bytes for a lookup table here.

Your perception is colored by the NES. Memory access on PC platforms is not 1-2 cycles slower like on the NES, it's often 100 cycles slower. For something executed for every pixel, it really matters on slow processors.

The only time it's going to be 100 times slower is if the table causes a cache miss on high FSB ratio menory. Realistically, that's only going to happen for the first access in a tight loop doing tens of thousands of iterations. Slow processors (if by slow you mean one where the CPU might be a bottleneck for SNES emulation) typically won't have those extreme FSB ratios that would create that problem in the first place. In that case, a TLB miss is more likely to cause that problem. But even so, only on the first access.

_________________
Gameboy Genius (Blog) - Gameboy development forum (+wiki and file area)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group