diff --git a/Cocoa/Document.m b/Cocoa/Document.m
index ea7ef49..a354e03 100644
--- a/Cocoa/Document.m
+++ b/Cocoa/Document.m
@@ -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"];
diff --git a/Cocoa/GBPreferencesWindow.h b/Cocoa/GBPreferencesWindow.h
index ee697a8..f0b7506 100644
--- a/Cocoa/GBPreferencesWindow.h
+++ b/Cocoa/GBPreferencesWindow.h
@@ -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;
diff --git a/Cocoa/GBPreferencesWindow.m b/Cocoa/GBPreferencesWindow.m
index 491f0c0..dd13ca1 100644
--- a/Cocoa/GBPreferencesWindow.m
+++ b/Cocoa/GBPreferencesWindow.m
@@ -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])
diff --git a/Cocoa/Preferences.xib b/Cocoa/Preferences.xib
index 99c6543..73eb0ab 100644
--- a/Cocoa/Preferences.xib
+++ b/Cocoa/Preferences.xib
@@ -79,15 +79,16 @@
+
-
+
-
+
diff --git a/Core/display.c b/Core/display.c
index f5e81a8..6ac6be8 100644
--- a/Core/display.c
+++ b/Core/display.c
@@ -2,6 +2,7 @@
#include
#include
#include
+#include
#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
diff --git a/Core/display.h b/Core/display.h
index 5bdeba8..fdaf172 100644
--- a/Core/display.h
+++ b/Core/display.h
@@ -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 */
diff --git a/Core/gb.h b/Core/gb.h
index ed736e0..c2e96db 100644
--- a/Core/gb.h
+++ b/Core/gb.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;
diff --git a/SDL/gui.c b/SDL/gui.c
index 3848d15..63e42d8 100644
--- a/SDL/gui.c
+++ b/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},
diff --git a/SDL/gui.h b/SDL/gui.h
index f55464d..84930e0 100644
--- a/SDL/gui.h
+++ b/SDL/gui.h
@@ -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;
diff --git a/SDL/main.c b/SDL/main.c
index 45d016d..a20d644 100644
--- a/SDL/main.c
+++ b/SDL/main.c
@@ -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) {