Skip to content

Commit

Permalink
Melee seems more or less correct.
Browse files Browse the repository at this point in the history
  • Loading branch information
katajakasa committed Jun 26, 2024
1 parent 7069060 commit 01f7c67
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 10 deletions.
36 changes: 27 additions & 9 deletions src/game/scenes/melee.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,18 +387,29 @@ static void draw_highlight(const melee_local *local, const cursor_data *cursor,
video_draw_offset(&local->select_hilight, x, y, offset, 255);
}

/**
* Get current color palette index for a given tick. This is used in the pulsing effect of the
* har or pilot selector highlight thingy.
*/
static int get_index_for_tick(int ticks) {
double rate = ((double)ticks) / 18.0;
return round((sin(rate) + 1.0) * 3) + 1;
}

static void render_highlights(const melee_local *local, bool player2_is_selectable) {
int rate = floor((float)local->ticks / 14.0);
int index = abs((rate % 8) - 4);
int index = get_index_for_tick(local->ticks);
if(player2_is_selectable && CURSORS_MATCH(local)) {
int offset = CURSORS_DONE(local) ? 0xBF : 0xBB + index;
int base = 0xE0;
int offset = CURSORS_DONE(local) ? base + 7 : base + index;
draw_highlight(local, &local->cursor[0], offset);
} else {
if(player2_is_selectable) {
int offset = local->cursor[1].done ? 0xAE : 0xAA + index;
int base = 0xA8;
int offset = CURSOR_B_DONE(local) ? base + 7 : base + index;
draw_highlight(local, &local->cursor[1], offset);
}
int offset = local->cursor[0].done ? 0xB6 : 0xB2 + index;
int base = 0xB0;
int offset = CURSOR_A_DONE(local) ? base + 7 : base + index;
draw_highlight(local, &local->cursor[0], offset);
}
}
Expand Down Expand Up @@ -469,8 +480,10 @@ static void render_pilot_select(melee_local *local, bool player2_is_selectable)

render_highlights(local, player2_is_selectable);
render_disabled_portraits(local->pilot_portraits);
render_enabled_portrait(local->pilot_portraits, &local->cursor[0]);
object_render(&local->big_portrait_1);
if(player2_is_selectable) {
render_enabled_portrait(local->pilot_portraits, &local->cursor[0]);
object_render(&local->big_portrait_2);
}
}
Expand All @@ -480,8 +493,8 @@ static void render_har_select(melee_local *local, bool player2_is_selectable) {

// render the stupid unselected HAR portraits before anything
// so we can render anything else on top of them
render_disabled_portraits(local->har_portraits);
render_highlights(local, player2_is_selectable);
render_disabled_portraits(local->har_portraits);

// currently selected player
object_render(&local->big_portrait_1);
Expand Down Expand Up @@ -566,29 +579,34 @@ static void load_pilot_portraits(scene *scene, melee_local *local) {

// Copy the face image in dimmed color (shown when not selected)
surface_create_from(&target->disabled, &target->enabled);
surface_compress_index_blocks(&target->disabled, 0x60, 0xA0, 64, 16);
surface_compress_index_blocks(&target->disabled, 0xA0, 0xD0, 8, 3);
surface_compress_index_blocks(&target->disabled, 0xD0, 0xE0, 16, 3);
surface_compress_index_blocks(&target->disabled, 0xE0, 0xF0, 8, 2);
surface_compress_remap(&target->disabled, 0xF0, 0xF7, 0xB6, 3);
}
}

static void load_har_portraits(scene *scene, melee_local *local) {
sprite *current;
portrait *target;
int row, col;
animation *hars_disabled = &bk_get_info(&scene->bk_data, 1)->ani;
animation *har_portraits = &bk_get_info(&scene->bk_data, 1)->ani;
for(int i = 0; i < 10; i++) {
row = i / 5;
col = i % 5;
target = &local->har_portraits[i];

// Copy the HAR image in full color (shown when selected)
current = animation_get_sprite(hars_disabled, 0);
current = animation_get_sprite(har_portraits, 0);
target->x = current->pos.x + 62 * col;
target->y = current->pos.y + 42 * row;
surface_create_from_surface(&target->enabled, 51, 36, 62 * col, 42 * row, current->data);
surface_generate_stencil(&target->enabled, 0xD0);

// Copy the enabled image, and compress the colors to grayscale
surface_create_from(&target->disabled, &target->enabled);
surface_convert_to_grayscale(&target->disabled, video_get_pal_ref(), 0xD0, 0xDF);
surface_generate_stencil(&target->disabled, 0xD0);
}
}

Expand Down
33 changes: 32 additions & 1 deletion src/video/surface.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "video/surface.h"
#include "utils/allocator.h"
#include "utils/miscmath.h"
#include <png.h>
#include <stdlib.h>
#include <utils/log.h>
Expand Down Expand Up @@ -138,7 +139,7 @@ static uint8_t find_closest_gray(const screen_palette *pal, int range_start, int
void surface_convert_to_grayscale(surface *sur, const screen_palette *pal, int range_start, int range_end) {
float r, g, b;
uint8_t idx;
char mapping[256];
unsigned char mapping[256];

// Make a mapping for fast search.
for(int i = 0; i < 256; i++) {
Expand All @@ -153,6 +154,36 @@ void surface_convert_to_grayscale(surface *sur, const screen_palette *pal, int r
idx = sur->data[i];
sur->data[i] = mapping[idx];
}
create_hash(sur);
}

void surface_compress_index_blocks(surface *sur, int range_start, int range_end, int block_size, int amount) {
uint8_t idx, real_start, old_idx, new_idx;
for(int i = 0; i < sur->w * sur->h; i++) {
idx = sur->data[i];
if(idx >= range_start && idx < range_end) {
real_start = idx - range_start;
old_idx = real_start % block_size;
new_idx = max2(0, old_idx - amount);
sur->data[i] = idx - old_idx + new_idx;
}
}
create_hash(sur);
}

void surface_compress_remap(surface *sur, int range_start, int range_end, int remap_to, int amount) {
uint8_t idx, real_start, d;
for(int i = 0; i < sur->w * sur->h; i++) {
idx = sur->data[i];
if(idx >= range_start && idx < range_end) {
real_start = idx - range_start;
if(real_start - amount < range_start) {
d = abs(real_start - amount);
sur->data[i] = remap_to - d;
}
}
}
create_hash(sur);
}

bool surface_write_png(const surface *sur, const screen_palette *pal, const char *filename) {
Expand Down
27 changes: 27 additions & 0 deletions src/video/surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,33 @@ void surface_sub(surface *dst, const surface *src, int dst_x, int dst_y, int src
int method);
void surface_generate_stencil(const surface *sur, int index);

/**
* Flatten each block of {block_size} colors by decrementing the index by {amount} in each block.
* Start counting from {range_start} and stop at {range_end}. A block can be e.g. a color slide
* of certain color.
*
* @param sur Surface to convert
* @param range_start Palette range start index
* @param range_end Palette range end index
* @param block_size Palette color block size, e.g. 8
* @param amount How much to decrement the index.
*/
void surface_compress_index_blocks(surface *sur, int range_start, int range_end, int block_size, int amount);

/**
* Flatten a block of colors in palette by decrementing the index by {amount}. Start counting
* from {range_start} and stop at {range_end}. If the resulting index after decrementing goes
* below {range_start}, then continue decrementing from index {remap_to}. This virtually combines
* two separate color blocks in the palette (e.g. color slides).
*
* @param sur Surface to convert
* @param range_start Palette range start index
* @param range_end Palette range end index
* @param remap_to End index of a palette block to remap to
* @param amount How much to decrement the index.
*/
void surface_compress_remap(surface *sur, int range_start, int range_end, int remap_to, int amount);

/**
* Convert surface to grayscale using colors in palette from range-start to range-end (inclusive).
* Conversion is done by luminosity.
Expand Down

0 comments on commit 01f7c67

Please sign in to comment.