Skip to content

Commit

Permalink
Merge pull request #1380 from Albeleon/flashtone
Browse files Browse the repository at this point in the history
ToneBlit performance and Method Implementation, Sprite Flashes, other fixes
  • Loading branch information
carstene1ns committed Jul 11, 2018
2 parents baff086 + 6a3c6eb commit 4bebc3d
Show file tree
Hide file tree
Showing 15 changed files with 157 additions and 122 deletions.
17 changes: 15 additions & 2 deletions src/background.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "output.h"

Background::Background(const std::string& name) :
visible(true),
visible(true), tone_effect(Tone()),
bg_hscroll(0), bg_vscroll(0), bg_x(0), bg_y(0),
fg_hscroll(0), fg_vscroll(0), fg_x(0), fg_y(0) {

Expand All @@ -43,7 +43,7 @@ Background::Background(const std::string& name) :
}

Background::Background(int terrain_id) :
visible(true),
visible(true), tone_effect(Tone()),
bg_hscroll(0), bg_vscroll(0), bg_x(0), bg_y(0),
fg_hscroll(0), fg_vscroll(0), fg_x(0), fg_y(0) {

Expand Down Expand Up @@ -109,6 +109,15 @@ DrawableType Background::GetType() const {
return type;
}

Tone Background::GetTone() const {
return tone_effect;
}

void Background::SetTone(Tone tone) {
if (tone_effect != tone) {
tone_effect = tone;
}
}
void Background::Update(int& rate, int& value) {
int step =
(rate > 0) ? 1 << rate :
Expand Down Expand Up @@ -143,4 +152,8 @@ void Background::Draw() {

if (fg_bitmap)
dst->TiledBlit(-Scale(fg_x), -Scale(fg_y), fg_bitmap->GetRect(), *fg_bitmap, dst_rect, 255);

if (tone_effect != Tone()) {
dst->ToneBlit(0, 0, *dst, dst->GetRect(), tone_effect, Opacity::opaque);
}
}
5 changes: 5 additions & 0 deletions src/background.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "system.h"
#include "drawable.h"
#include "async_handler.h"
#include "tone.h"

class Background : public Drawable {
public:
Expand All @@ -32,6 +33,8 @@ class Background : public Drawable {

void Draw() override;
void Update();
Tone GetTone() const;
void SetTone(Tone tone);

int GetZ() const override;
DrawableType GetType() const override;
Expand All @@ -48,6 +51,8 @@ class Background : public Drawable {

bool visible;

Tone tone_effect;
Tone current_tone;
BitmapRef bg_bitmap;
int bg_hscroll;
int bg_vscroll;
Expand Down
10 changes: 5 additions & 5 deletions src/battle_animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ void BattleAnimation::DrawAt(int x, int y) {
}

// FIXME: looks okay, but needs to be measured
static int flash_length = 5;
static int flash_length = 12;

void BattleAnimation::RunTimedSfx() {
// Lookup any timed SFX (SE/flash/shake) data for this frame
Expand All @@ -158,10 +158,10 @@ void BattleAnimation::ProcessAnimationTiming(const RPG::AnimationTiming& timing)

// Flash.
if (timing.flash_scope == RPG::AnimationTiming::FlashScope_target) {
SetFlash(Color(timing.flash_red << 3,
timing.flash_green << 3,
timing.flash_blue << 3,
timing.flash_power << 3));
SetFlash(Color(timing.flash_red * 255 / 31,
timing.flash_green * 255 / 31,
timing.flash_blue * 255 / 31,
timing.flash_power * 255 / 31));
} else if (timing.flash_scope == RPG::AnimationTiming::FlashScope_screen && ShouldScreenFlash()) {
Main_Data::game_screen->FlashOnce(
timing.flash_red,
Expand Down
184 changes: 110 additions & 74 deletions src/bitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,38 @@ static void make_hard_light_lookup() {
}
}

void Bitmap::ToneBlit(int x, int y, Bitmap const& src, Rect const& src_rect, const Tone &tone, Opacity const& opacity) {
// Saturation Tone Inline: Changes a pixel saturation
static inline void saturation_tone(uint32_t &src_pixel, int saturation, int rs, int gs, int bs, int as) {
// Algorithm from OpenPDN (MIT license)
// Transformation in Y'CbCr color space
uint8_t r = (src_pixel >> rs) & 0xFF;
uint8_t g = (src_pixel >> gs) & 0xFF;
uint8_t b = (src_pixel >> bs) & 0xFF;
uint8_t a = (src_pixel >> as) & 0xFF;

// Y' = 0.299 R' + 0.587 G' + 0.114 B'
uint8_t lum = (7471 * b + 38470 * g + 19595 * r) >> 16;

// Scale Cb/Cr by scale factor "sat"
int red = ((lum * 1024 + (r - lum) * saturation) >> 10);
red = red > 255 ? 255 : red < 0 ? 0 : red;
int green = ((lum * 1024 + (g - lum) * saturation) >> 10);
green = green > 255 ? 255 : green < 0 ? 0 : green;
int blue = ((lum * 1024 + (b - lum) * saturation) >> 10);
blue = blue > 255 ? 255 : blue < 0 ? 0 : blue;

src_pixel = ((uint32_t)red << rs) | ((uint32_t)green << gs) | ((uint32_t)blue << bs) | ((uint32_t)a << as);
}

// Color Tone Inline: Changes color of a pixel by hard light table
static inline void color_tone(uint32_t &src_pixel, Tone tone, uint8_t hard_light_lookup[256][256], int rs, int gs, int bs, int as) {
src_pixel = ((uint32_t)hard_light_lookup[tone.red][(src_pixel >> rs) & 0xFF] << rs)
| ((uint32_t)hard_light_lookup[tone.green][(src_pixel >> gs) & 0xFF] << gs)
| ((uint32_t)hard_light_lookup[tone.blue][(src_pixel >> bs) & 0xFF] << bs)
| ((uint32_t)((src_pixel >> as) & 0xFF) << as);
}

void Bitmap::ToneBlit(int x, int y, Bitmap const& src, Rect const& src_rect, const Tone &tone, Opacity const& opacity, bool check_alpha) {
if (tone == Tone(128,128,128,128)) {
if (&src != this) {
Blit(x, y, src, src_rect, opacity);
Expand All @@ -857,95 +888,100 @@ void Bitmap::ToneBlit(int x, int y, Bitmap const& src, Rect const& src_rect, con
x, y,
src_rect.width, src_rect.height);

if (tone.gray != 128) {
uint32_t* pixels = (uint32_t*)this->pixels();
// To implement Saturation and Color:
static bool index_made = false;
if (!index_made) {
make_hard_light_lookup();
index_made = true;
}

int sat;
if (tone.gray > 128) {
sat = 1024 + (tone.gray - 128) * 16;
int as = pixel_format.a.shift;
int rs = pixel_format.r.shift;
int gs = pixel_format.g.shift;
int bs = pixel_format.b.shift;
int next_row = pitch() / sizeof(uint32_t);
uint32_t* pixels = (uint32_t*)this->pixels();
pixels = pixels + (y - 1) * next_row + x;

uint16_t limit_height = std::min<uint16_t>(src_rect.height, height());
uint16_t limit_width = std::min<uint16_t>(src_rect.width, width());

// If Saturation + Color:
if (tone.gray != 128 && (tone.red != 128 || tone.green != 128 || tone.blue != 128)) {
int sat = tone.gray > 128 ? 1024 + (tone.gray - 128) * 16 : tone.gray * 8;

if (&src != this || check_alpha) {
for (uint16_t i = 0; i < limit_height; ++i) {
pixels += next_row;
for (uint16_t j = 0; j < limit_width; ++j) {
if ((uint8_t)((pixels[j] >> as) & 0xFF) == 0)
continue;

saturation_tone(pixels[j], sat, rs, gs, bs, as);
color_tone(pixels[j], tone, hard_light_lookup, rs, gs, bs, as);
}
}
}
else {
sat = tone.gray * 8;
}

int as = pixel_format.a.shift;
int rs = pixel_format.r.shift;
int gs = pixel_format.g.shift;
int bs = pixel_format.b.shift;

// Move according to x/y value
pixels = pixels + (y * pitch() / sizeof(uint32_t) + x) - (pitch() / sizeof(uint32_t));

// Algorithm from OpenPDN (MIT license)
// Transformation in Y'CbCr color space
for (int i = 0; i < src_rect.height && i < height(); ++i) {
// Advance one pixel row
pixels += pitch() / sizeof(uint32_t);

for (int j = 0; j < src_rect.width && j < width(); ++j) {
uint32_t pixel = pixels[j];
uint8_t a = (pixel >> as) & 0xFF;
// &src != this works around a corner case with opacity split (character in a bush)
// in that case a == 0 and the effect is not applied
if (a == 0 && &src != this) {
continue;
for (uint16_t i = 0; i < limit_height; ++i) {
pixels += next_row;
for (uint16_t j = 0; j < limit_width; ++j) {
saturation_tone(pixels[j], sat, rs, gs, bs, as);
color_tone(pixels[j], tone, hard_light_lookup, rs, gs, bs, as);
}
uint8_t r = (pixel >> rs) & 0xFF;
uint8_t g = (pixel >> gs) & 0xFF;
uint8_t b = (pixel >> bs) & 0xFF;
// Y' = 0.299 R' + 0.587 G' + 0.114 B'
uint8_t lum = (7471 * b + 38470 * g + 19595 * r) >> 16;
// Scale Cb/Cr by scale factor "sat"
int red = ((lum * 1024 + (r - lum) * sat) >> 10);
red = red > 255 ? 255 : red < 0 ? 0 : red;
int green = ((lum * 1024 + (g - lum) * sat) >> 10);
green = green > 255 ? 255 : green < 0 ? 0 : green;
int blue = ((lum * 1024 + (b - lum) * sat) >> 10);
blue = blue > 255 ? 255 : blue < 0 ? 0 : blue;
pixels[j] = ((uint32_t) red << rs) | ((uint32_t) green << gs) | ((uint32_t) blue << bs) |
((uint32_t) a << as);
}
}
}

if (tone.red != 128 || tone.green != 128 || tone.blue != 128) {
static bool index_made = false;
if (!index_made) {
make_hard_light_lookup();
index_made = true;
}
// If Only Saturation:
else if (tone.gray != 128) {
int sat = tone.gray > 128 ? 1024 + (tone.gray - 128) * 16 : tone.gray * 8;

int as = pixel_format.a.shift;
int rs = pixel_format.r.shift;
int gs = pixel_format.g.shift;
int bs = pixel_format.b.shift;
if (&src != this || check_alpha) {
for (uint16_t i = 0; i < limit_height; ++i) {
pixels += next_row;
for (uint16_t j = 0; j < limit_width; ++j) {
if ((uint8_t)((pixels[j] >> as) & 0xFF) == 0)
continue;

uint32_t* pixels = (uint32_t*)this->pixels();
// Move according to x/y value
pixels = pixels + (y * pitch() / sizeof(uint32_t) + x) - (pitch() / sizeof(uint32_t));
saturation_tone(pixels[j], sat, rs, gs, bs, as);
}
}
}
else {
for (uint16_t i = 0; i < limit_height; ++i) {
pixels += next_row;
for (uint16_t j = 0; j < limit_width; ++j) {
saturation_tone(pixels[j], sat, rs, gs, bs, as);
}
}
}
}

for (int i = 0; i < src_rect.height && i < height(); ++i) {
// Advance one pixel row
pixels += pitch() / sizeof(uint32_t);
// If Only Color:
else if (tone.red != 128 || tone.green != 128 || tone.blue != 128) {
if (&src != this || check_alpha) {
for (uint16_t i = 0; i < limit_height; ++i) {
pixels += next_row;
for (uint16_t j = 0; j < limit_width; ++j) {
if ((uint8_t)((pixels[j] >> as) & 0xFF) == 0)
continue;

for (int j = 0; j < src_rect.width && j < width(); ++j) {
uint32_t pixel = pixels[j];
uint8_t a = (pixel >> as) & 0xFF;
if (a == 0 && &src != this) {
continue;
color_tone(pixels[j], tone, hard_light_lookup, rs, gs, bs, as);
}
uint8_t r = (pixel >> rs) & 0xFF;
uint8_t g = (pixel >> gs) & 0xFF;
uint8_t b = (pixel >> bs) & 0xFF;

int red = hard_light_lookup[tone.red][r];
int green = hard_light_lookup[tone.green][g];
int blue = hard_light_lookup[tone.blue][b];
pixels[j] = ((uint32_t) red << rs) | ((uint32_t) green << gs) | ((uint32_t) blue << bs) |
((uint32_t) a << as);
}
}
else {
for (uint16_t i = 0; i < limit_height; ++i) {
pixels += next_row;
for (uint16_t j = 0; j < limit_width; ++j) {
color_tone(pixels[j], tone, hard_light_lookup, rs, gs, bs, as);
}
}
}

}

}

void Bitmap::BlendBlit(int x, int y, Bitmap const& src, Rect const& src_rect, const Color& color, Opacity const& opacity) {
Expand Down
2 changes: 1 addition & 1 deletion src/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ class Bitmap {
* @param tone tone to apply.
* @param opacity opacity to apply.
*/
void ToneBlit(int x, int y, Bitmap const& src, Rect const& src_rect, const Tone &tone, Opacity const& opacity);
void ToneBlit(int x, int y, Bitmap const& src, Rect const& src_rect, const Tone &tone, Opacity const& opacity, bool check_alpha = false);

/**
* Blends bitmap with color.
Expand Down
1 change: 1 addition & 0 deletions src/game_character.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@ class Game_Character {
int stop_count;
int max_stop_count;
bool walk_animation;
uint8_t flash_alpha;

int opacity;
bool visible;
Expand Down
3 changes: 2 additions & 1 deletion src/game_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,14 @@ void Game_Event::SetSpriteIndex(int index) {
}

Color Game_Event::GetFlashColor() const {
return Color(data.flash_red, data.flash_green, data.flash_blue, 128);
return Color(data.flash_red, data.flash_green, data.flash_blue, flash_alpha);
}

void Game_Event::SetFlashColor(const Color& flash_color) {
data.flash_red = flash_color.red;
data.flash_blue = flash_color.blue;
data.flash_green = flash_color.green;
flash_alpha = flash_color.alpha;
}

double Game_Event::GetFlashLevel() const {
Expand Down
9 changes: 5 additions & 4 deletions src/game_interpreter_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,10 +655,11 @@ bool Game_Interpreter_Map::CommandShowBattleAnimation(RPG::EventCommand const& c

bool Game_Interpreter_Map::CommandFlashSprite(RPG::EventCommand const& com) { // code 11320
int event_id = com.parameters[0];
Color color(com.parameters[1] << 3,
com.parameters[2] << 3,
com.parameters[3] << 3,
com.parameters[4] << 3);
Color color(com.parameters[1] * 255 / 31,
com.parameters[2] * 255 / 31,
com.parameters[3] * 255 / 31,
com.parameters[4] * 255 / 31);

int tenths = com.parameters[5];
bool wait = com.parameters[6] > 0;
Game_Character* event = GetCharacter(event_id);
Expand Down
3 changes: 2 additions & 1 deletion src/game_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,14 @@ bool Game_Player::GetVisible() const {
}

Color Game_Player::GetFlashColor() const {
return Color(location.flash_red, location.flash_green, location.flash_blue, 128);
return Color(location.flash_red, location.flash_green, location.flash_blue, flash_alpha);
}

void Game_Player::SetFlashColor(const Color& flash_color) {
location.flash_red = flash_color.red;
location.flash_blue = flash_color.blue;
location.flash_green = flash_color.green;
flash_alpha = flash_color.alpha;
}

double Game_Player::GetFlashLevel() const {
Expand Down
3 changes: 2 additions & 1 deletion src/game_vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,14 @@ void Game_Vehicle::SetSpriteIndex(int index) {
}

Color Game_Vehicle::GetFlashColor() const {
return Color(data.flash_red, data.flash_green, data.flash_blue, 128);
return Color(data.flash_red, data.flash_green, data.flash_blue, flash_alpha);
}

void Game_Vehicle::SetFlashColor(const Color& flash_color) {
data.flash_red = flash_color.red;
data.flash_blue = flash_color.blue;
data.flash_green = flash_color.green;
flash_alpha = flash_color.alpha;
}

double Game_Vehicle::GetFlashLevel() const {
Expand Down
Loading

0 comments on commit 4bebc3d

Please sign in to comment.