mirror of https://github.com/bsnes-emu/bsnes.git
Color temperature control
This commit is contained in:
parent
b5a611c5db
commit
159d9d0348
|
@ -689,6 +689,11 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
|||
name:@"GBColorCorrectionChanged"
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(updateLightTemperature)
|
||||
name:@"GBLightTemperatureChanged"
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(updateFrameBlendingMode)
|
||||
name:@"GBFrameBlendingModeChanged"
|
||||
|
@ -1835,6 +1840,14 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
|||
}
|
||||
}
|
||||
|
||||
- (void) updateLightTemperature
|
||||
{
|
||||
if (GB_is_inited(&gb)) {
|
||||
GB_set_light_temperature(&gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBLightTemperature"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) updateFrameBlendingMode
|
||||
{
|
||||
self.view.frameBlendingMode = (GB_frame_blending_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBFrameBlendingMode"];
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
@property (strong) IBOutlet NSMenuItem *bootROMsFolderItem;
|
||||
@property (strong) IBOutlet NSPopUpButtonCell *bootROMsButton;
|
||||
@property (strong) IBOutlet NSPopUpButton *rumbleModePopupButton;
|
||||
|
||||
@property (weak) IBOutlet NSSlider *temperatureSlider;
|
||||
@property (weak) IBOutlet NSPopUpButton *dmgPopupButton;
|
||||
@property (weak) IBOutlet NSPopUpButton *sgbPopupButton;
|
||||
@property (weak) IBOutlet NSPopUpButton *cgbPopupButton;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
NSPopUpButton *_dmgPopupButton, *_sgbPopupButton, *_cgbPopupButton;
|
||||
NSPopUpButton *_preferredJoypadButton;
|
||||
NSPopUpButton *_rumbleModePopupButton;
|
||||
NSSlider *_temperatureSlider;
|
||||
}
|
||||
|
||||
+ (NSArray *)filterList
|
||||
|
@ -91,11 +92,23 @@
|
|||
[_colorCorrectionPopupButton selectItemAtIndex:mode];
|
||||
}
|
||||
|
||||
|
||||
- (NSPopUpButton *)colorCorrectionPopupButton
|
||||
{
|
||||
return _colorCorrectionPopupButton;
|
||||
}
|
||||
|
||||
- (void)setTemperatureSlider:(NSSlider *)temperatureSlider
|
||||
{
|
||||
_temperatureSlider = temperatureSlider;
|
||||
[temperatureSlider setDoubleValue:[[NSUserDefaults standardUserDefaults] doubleForKey:@"GBLightTemperature"] * 256];
|
||||
temperatureSlider.continuous = YES;
|
||||
}
|
||||
|
||||
- (NSSlider *)temperatureSlider
|
||||
{
|
||||
return _temperatureSlider;
|
||||
}
|
||||
- (void)setFrameBlendingModePopupButton:(NSPopUpButton *)frameBlendingModePopupButton
|
||||
{
|
||||
_frameBlendingModePopupButton = frameBlendingModePopupButton;
|
||||
|
@ -284,6 +297,13 @@
|
|||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorCorrectionChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)lightTemperatureChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0)
|
||||
forKey:@"GBLightTemperature"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBLightTemperatureChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)franeBlendingModeChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
|
||||
|
|
|
@ -79,15 +79,16 @@
|
|||
<outlet property="rumbleModePopupButton" destination="Ogs-xG-b4b" id="vuw-VN-MTp"/>
|
||||
<outlet property="sgbPopupButton" destination="dza-T7-RkX" id="B0o-Nb-pIH"/>
|
||||
<outlet property="skipButton" destination="d2I-jU-sLb" id="udX-8K-0sK"/>
|
||||
<outlet property="temperatureSlider" destination="G3D-2f-Zcr" id="Etd-U2-wv0"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="183" y="354"/>
|
||||
</window>
|
||||
<customView id="sRK-wO-K6R">
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="323"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="378"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T91-rh-rRp">
|
||||
<rect key="frame" x="18" y="286" width="256" height="17"/>
|
||||
<rect key="frame" x="18" y="341" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Graphics filter:" id="pXg-WY-8Q5">
|
||||
<font key="font" metaFont="system"/>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "gb.h"
|
||||
|
||||
/* FIFO functions */
|
||||
|
@ -208,6 +209,26 @@ static void display_vblank(GB_gameboy_t *gb)
|
|||
GB_timing_sync(gb);
|
||||
}
|
||||
|
||||
static inline void temperature_tint(double temperature, double *r, double *g, double *b)
|
||||
{
|
||||
if (temperature >= 0) {
|
||||
*r = 1;
|
||||
*g = pow(1 - temperature, 0.375);
|
||||
if (temperature >= 0.75) {
|
||||
*b = 0;
|
||||
}
|
||||
else {
|
||||
*b = sqrt(0.75 - temperature);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*b = 1;
|
||||
double squared = pow(temperature, 2);
|
||||
*g = 0.125 * squared + 0.3 * temperature + 1.0;
|
||||
*r = 0.21875 * squared + 0.5 * temperature + 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t scale_channel(uint8_t x)
|
||||
{
|
||||
return (x << 3) | (x >> 2);
|
||||
|
@ -240,13 +261,12 @@ uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border)
|
|||
g = scale_channel(g);
|
||||
b = scale_channel(b);
|
||||
}
|
||||
else if (GB_is_sgb(gb) || for_border) {
|
||||
r = scale_channel_with_curve_sgb(r);
|
||||
g = scale_channel_with_curve_sgb(g);
|
||||
b = scale_channel_with_curve_sgb(b);
|
||||
}
|
||||
else {
|
||||
if (GB_is_sgb(gb) || for_border) {
|
||||
return gb->rgb_encode_callback(gb,
|
||||
scale_channel_with_curve_sgb(r),
|
||||
scale_channel_with_curve_sgb(g),
|
||||
scale_channel_with_curve_sgb(b));
|
||||
}
|
||||
bool agb = gb->model == GB_MODEL_AGB;
|
||||
r = agb? scale_channel_with_curve_agb(r) : scale_channel_with_curve(r);
|
||||
g = agb? scale_channel_with_curve_agb(g) : scale_channel_with_curve(g);
|
||||
|
@ -301,6 +321,14 @@ uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border)
|
|||
}
|
||||
}
|
||||
|
||||
if (gb->light_temperature) {
|
||||
double light_r, light_g, light_b;
|
||||
temperature_tint(gb->light_temperature, &light_r, &light_g, &light_b);
|
||||
r = round(light_r * r);
|
||||
g = round(light_g * g);
|
||||
b = round(light_b * b);
|
||||
}
|
||||
|
||||
return gb->rgb_encode_callback(gb, r, g, b);
|
||||
}
|
||||
|
||||
|
@ -324,6 +352,17 @@ void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t m
|
|||
}
|
||||
}
|
||||
|
||||
void GB_set_light_temperature(GB_gameboy_t *gb, double temperature)
|
||||
{
|
||||
gb->light_temperature = temperature;
|
||||
if (GB_is_cgb(gb)) {
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
GB_palette_changed(gb, false, i * 2);
|
||||
GB_palette_changed(gb, true, i * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
STAT interrupt is implemented based on this finding:
|
||||
http://board.byuu.org/phpbb3/viewtopic.php?p=25527#p25531
|
||||
|
|
|
@ -58,5 +58,6 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette
|
|||
uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height);
|
||||
uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border);
|
||||
void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode);
|
||||
void GB_set_light_temperature(GB_gameboy_t *gb, double temperature);
|
||||
bool GB_is_odd_frame(GB_gameboy_t *gb);
|
||||
#endif /* display_h */
|
||||
|
|
|
@ -573,6 +573,7 @@ struct GB_gameboy_internal_s {
|
|||
uint32_t sprite_palettes_rgb[0x20];
|
||||
const GB_palette_t *dmg_palette;
|
||||
GB_color_correction_mode_t color_correction_mode;
|
||||
double light_temperature;
|
||||
bool keys[4][GB_KEY_MAX];
|
||||
GB_border_mode_t border_mode;
|
||||
GB_sgb_border_t borrowed_border;
|
||||
|
|
43
SDL/gui.c
43
SDL/gui.c
|
@ -110,6 +110,7 @@ configuration_t configuration =
|
|||
.volume = 100,
|
||||
.rumble_mode = GB_RUMBLE_ALL_GAMES,
|
||||
.default_scale = 2,
|
||||
.color_temperature = 10,
|
||||
};
|
||||
|
||||
|
||||
|
@ -453,6 +454,33 @@ const char *current_color_correction_mode(unsigned index)
|
|||
[configuration.color_correction_mode];
|
||||
}
|
||||
|
||||
const char *current_color_temperature(unsigned index)
|
||||
{
|
||||
return (const char *[]){"12000K",
|
||||
"11450K",
|
||||
"10900K",
|
||||
"10350K",
|
||||
"9800K",
|
||||
"9250K",
|
||||
"8700K",
|
||||
"8150K",
|
||||
"7600K",
|
||||
"7050K",
|
||||
"6500K (White)",
|
||||
"5950K",
|
||||
"5400K",
|
||||
"4850K",
|
||||
"4300K",
|
||||
"3750K",
|
||||
"3200K",
|
||||
"2650K",
|
||||
"2100K",
|
||||
"1550K",
|
||||
"1000K"}
|
||||
[configuration.color_temperature];
|
||||
}
|
||||
|
||||
|
||||
const char *current_palette(unsigned index)
|
||||
{
|
||||
return (const char *[]){"Greyscale", "Lime (Game Boy)", "Olive (Pocket)", "Teal (Light)"}
|
||||
|
@ -533,6 +561,20 @@ static void cycle_color_correction_backwards(unsigned index)
|
|||
}
|
||||
}
|
||||
|
||||
static void decrease_color_temperature(unsigned index)
|
||||
{
|
||||
if (configuration.color_temperature < 20) {
|
||||
configuration.color_temperature++;
|
||||
}
|
||||
}
|
||||
|
||||
static void increase_color_temperature(unsigned index)
|
||||
{
|
||||
if (configuration.color_temperature > 0) {
|
||||
configuration.color_temperature--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cycle_palette(unsigned index)
|
||||
{
|
||||
if (configuration.dmg_palette == 3) {
|
||||
|
@ -684,6 +726,7 @@ static const struct menu_item graphics_menu[] = {
|
|||
{"Default Window Scale:", cycle_default_scale, current_default_scale, cycle_default_scale_backwards},
|
||||
{"Scaling Filter:", cycle_filter, current_filter_name, cycle_filter_backwards},
|
||||
{"Color Correction:", cycle_color_correction, current_color_correction_mode, cycle_color_correction_backwards},
|
||||
{"Ambient Light:", decrease_color_temperature, current_color_temperature, increase_color_temperature},
|
||||
{"Frame Blending:", cycle_blending_mode, blending_mode_string, cycle_blending_mode_backwards},
|
||||
{"Mono Palette:", cycle_palette, current_palette, cycle_palette_backwards},
|
||||
{"Display Border:", cycle_border_mode, current_border_mode, cycle_border_mode_backwards},
|
||||
|
|
|
@ -110,6 +110,10 @@ typedef struct {
|
|||
GB_rumble_mode_t rumble_mode;
|
||||
|
||||
uint8_t default_scale;
|
||||
|
||||
/* v0.14 */
|
||||
unsigned padding;
|
||||
uint8_t color_temperature;
|
||||
} configuration_t;
|
||||
|
||||
extern configuration_t configuration;
|
||||
|
|
|
@ -120,6 +120,7 @@ static void open_menu(void)
|
|||
GB_audio_set_paused(false);
|
||||
}
|
||||
GB_set_color_correction_mode(&gb, configuration.color_correction_mode);
|
||||
GB_set_light_temperature(&gb, (configuration.color_temperature - 10.0) / 10.0);
|
||||
GB_set_border_mode(&gb, configuration.border_mode);
|
||||
update_palette();
|
||||
GB_set_highpass_filter_mode(&gb, configuration.highpass_mode);
|
||||
|
@ -496,6 +497,7 @@ restart:
|
|||
GB_set_rumble_mode(&gb, configuration.rumble_mode);
|
||||
GB_set_sample_rate(&gb, GB_audio_get_frequency());
|
||||
GB_set_color_correction_mode(&gb, configuration.color_correction_mode);
|
||||
GB_set_light_temperature(&gb, (configuration.color_temperature - 10.0) / 10.0);
|
||||
update_palette();
|
||||
if ((unsigned)configuration.border_mode <= GB_BORDER_ALWAYS) {
|
||||
GB_set_border_mode(&gb, configuration.border_mode);
|
||||
|
@ -646,6 +648,7 @@ int main(int argc, char **argv)
|
|||
configuration.dmg_palette %= 3;
|
||||
configuration.border_mode %= GB_BORDER_ALWAYS + 1;
|
||||
configuration.rumble_mode %= GB_RUMBLE_ALL_GAMES + 1;
|
||||
configuration.color_temperature %= 21;
|
||||
}
|
||||
|
||||
if (configuration.model >= MODEL_MAX) {
|
||||
|
|
Loading…
Reference in New Issue