diff --git a/doc/Doxyfile b/doc/Doxyfile index 035401f31..05474e99a 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -3,7 +3,7 @@ # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # -# All text after a hash (#) is considered a comment and will be ignored +# All text after a guid (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: diff --git a/shaders/palette.frag b/shaders/palette.frag index 3287421b8..0ee91582c 100644 --- a/shaders/palette.frag +++ b/shaders/palette.frag @@ -3,6 +3,7 @@ layout (location = 0) out vec4 color; in vec2 tex_coord; +flat in int transparency_index; flat in int blend_mode; flat in int palette_offset; flat in int palette_limit; @@ -11,11 +12,11 @@ uniform sampler2D atlas; void main() { vec4 texel = texture(atlas, tex_coord); - if (texel.g == 0) discard; // Don't render if it's transparent pixel + int pal_index = int(texel.r * 255.0); + if (pal_index == transparency_index) discard; // Don't render if it's transparent pixel if (blend_mode == 0) { color = vec4(0.0, texel.r, 0.0, 1.0); } else { - int pal_index = int(texel.r * 255.0); if (pal_index <= palette_limit) { pal_index = clamp(palette_limit, 0, pal_index + palette_offset); } diff --git a/shaders/palette.vert b/shaders/palette.vert index 8b6600018..90875f54e 100644 --- a/shaders/palette.vert +++ b/shaders/palette.vert @@ -2,17 +2,20 @@ layout (location = 0) in vec2 position; layout (location = 1) in vec2 tex_offset; -layout (location = 2) in int mode; -layout (location = 3) in int pal_offset; -layout (location = 4) in int pal_limit; +layout (location = 2) in int transparency; +layout (location = 3) in int mode; +layout (location = 4) in int pal_offset; +layout (location = 5) in int pal_limit; uniform mat4 projection; out vec2 tex_coord; +flat out int transparency_index; flat out int blend_mode; flat out int palette_offset; flat out int palette_limit; void main() { + transparency_index = transparency; blend_mode = mode; palette_offset = pal_offset; palette_limit = pal_limit; diff --git a/src/formats/fonts.c b/src/formats/fonts.c index dfff8e846..b1e3d146b 100644 --- a/src/formats/fonts.c +++ b/src/formats/fonts.c @@ -67,10 +67,8 @@ int sd_font_decode(const sd_font *font, sd_vga_image *o, uint8_t ch, uint8_t col for(int k = font->h - 1; k >= 0; k--) { if(font->chars[ch].data[i] & (1 << k)) { o->data[t] = color; - o->stencil[t] = 1; } else { o->data[t] = 0; - o->stencil[t] = 0; } t++; } diff --git a/src/formats/pcx.c b/src/formats/pcx.c index 8d2a4c24d..69a216b52 100644 --- a/src/formats/pcx.c +++ b/src/formats/pcx.c @@ -152,14 +152,11 @@ int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t pa for(int j = font->glyphs[ch].x; j < font->glyphs[ch].x + font->glyphs[ch].width; j++) { if(font->pcx.image.data[(i * 320) + j]) { o->data[(k * font->glyphs[ch].width) + l] = palette_offset + (int)font->pcx.image.data[(i * 320) + j]; - o->stencil[(k * font->glyphs[ch].width) + l] = 1; } else { o->data[(k * font->glyphs[ch].width) + l] = 0; - o->stencil[(k * font->glyphs[ch].width) + l] = 0; } l++; - ; } k++; } diff --git a/src/formats/sprite.c b/src/formats/sprite.c index ec1c1203d..e5e9ca8bd 100644 --- a/src/formats/sprite.c +++ b/src/formats/sprite.c @@ -295,10 +295,6 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) { return SD_SUCCESS; } - // everything defaults to transparent - int bsize = src->width * src->height; - memset(dst->stencil, 0, bsize); - // Walk through raw sprite data while(i < src->len) { // read a word @@ -320,7 +316,6 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) { uint8_t b = src->data[i]; int pos = ((y * src->width) + x); dst->data[pos] = b; - dst->stencil[pos] = 1; i++; // we read 1 byte x++; data--; @@ -364,13 +359,12 @@ int sd_sprite_vga_encode(sd_sprite *dst, const sd_vga_image *src) { buf[i++] = 0; rowstart = i; - // Walk through the RGBA data + // Walk through the index data for(int pos = 0; pos < vga_size; pos++) { uint8_t idx = src->data[pos]; - uint8_t stc = src->stencil[pos]; // ignore anything but fully opaque pixels - if(stc == 1) { + if(idx != 0) { int16_t x = pos % src->w; int16_t y = pos / src->w; if(y != lasty) { diff --git a/src/formats/vga_image.c b/src/formats/vga_image.c index c0096b446..98efc0de9 100644 --- a/src/formats/vga_image.c +++ b/src/formats/vga_image.c @@ -16,8 +16,6 @@ int sd_vga_image_create(sd_vga_image *img, unsigned int w, unsigned int h) { img->h = h; img->len = w * h; img->data = omf_calloc(1, w * h); - img->stencil = omf_calloc(1, w * h); - memset(img->stencil, 1, w * h); return SD_SUCCESS; } @@ -29,9 +27,7 @@ int sd_vga_image_copy(sd_vga_image *dst, const sd_vga_image *src) { dst->h = src->h; dst->len = src->len; dst->data = omf_calloc(src->len, 1); - dst->stencil = omf_calloc(src->len, 1); memcpy(dst->data, src->data, src->len); - memcpy(dst->stencil, src->stencil, src->len); return SD_SUCCESS; } @@ -40,44 +36,6 @@ void sd_vga_image_free(sd_vga_image *img) { return; } omf_free(img->data); - omf_free(img->stencil); -} - -int sd_vga_image_stencil_index(sd_vga_image *img, int stencil_index) { - if(stencil_index > 255 || img == NULL) { - return SD_INVALID_INPUT; - } - - // If stencil_index is < 0, we are just making the image opaque - if(stencil_index < 0) { - memset(img->stencil, 1, img->w * img->h); - return SD_SUCCESS; - } - - // Search & destroy! - for(int i = 0; i < img->w * img->h; i++) { - img->stencil[i] = (img->data[i] != stencil_index); - } - return SD_SUCCESS; -} - -int sd_vga_image_encode(sd_vga_image *dst, const sd_rgba_image *src, const palette *pal, int remapping) { - int ret; - if(dst == NULL || src == NULL || pal == NULL) { - return SD_INVALID_INPUT; - } - if((ret = sd_vga_image_create(dst, src->w, src->h)) != SD_SUCCESS) { - return ret; - } - unsigned int rgb_size = (src->w * src->h * 4); - for(int pos = 0; pos <= rgb_size; pos += 4) { - uint8_t r = src->data[pos]; - uint8_t g = src->data[pos + 1]; - uint8_t b = src->data[pos + 2]; - // ignore alpha channel, VGA images have no transparency - dst->data[pos / 4] = palette_resolve_color(r, g, b, pal); - } - return SD_SUCCESS; } int sd_vga_image_decode(sd_rgba_image *dst, const sd_vga_image *src, const palette *pal, int remapping) { @@ -92,22 +50,17 @@ int sd_vga_image_decode(sd_rgba_image *dst, const sd_vga_image *src, const palet for(int y = src->h - 1; y >= 0; y--) { for(int x = 0; x < src->w; x++) { uint8_t b = src->data[y * src->w + x]; - uint8_t s = src->stencil[y * src->w + x]; pos = ((y * src->w) + x) * 4; if(remapping > -1) { dst->data[pos + 0] = (uint8_t)pal->data[(uint8_t)pal->remaps[remapping][b]][0]; dst->data[pos + 1] = (uint8_t)pal->data[(uint8_t)pal->remaps[remapping][b]][1]; dst->data[pos + 2] = (uint8_t)pal->data[(uint8_t)pal->remaps[remapping][b]][2]; + dst->data[pos + 3] = (uint8_t)255; } else { dst->data[pos + 0] = (uint8_t)pal->data[b][0]; dst->data[pos + 1] = (uint8_t)pal->data[b][1]; dst->data[pos + 2] = (uint8_t)pal->data[b][2]; - } - // check the stencil to see if this is a real pixel - if(s == 1) { - dst->data[pos + 3] = (uint8_t)255; // fully opaque - } else { - dst->data[pos + 3] = (uint8_t)0; // fully transparent + dst->data[pos + 3] = (uint8_t)255; } } } diff --git a/src/formats/vga_image.h b/src/formats/vga_image.h index 44843ee0a..19328a780 100644 --- a/src/formats/vga_image.h +++ b/src/formats/vga_image.h @@ -14,19 +14,12 @@ #include "formats/palette.h" #include "formats/rgba_image.h" -#ifdef __cplusplus -extern "C" { -#endif - /*! \brief VGA image structure * - * Contains a paletted image and transparency stencil. The image can be exported to + * Contains a paletted image. The image can be exported to * an omf:2097 sprite by using a proper function sd_sprite_vga_encode() and back * sd_sprite_vga_decode() . For RGBA conversion, a valid palette is required. * - * Invisibility is handled by setting a single palette index as the invisibility stencil. - * This can be modified with library function sd_vga_image_stencil_index(). - * * In VGA images, the len field should always be exactly w*h bytes long. */ typedef struct { @@ -34,7 +27,6 @@ typedef struct { unsigned int h; ///< Pixel height unsigned int len; ///< Byte length char *data; ///< Palette representation of image data - char *stencil; ///< holds 0 or 1 indicating whether a pixel is present } sd_vga_image; /*! \brief Initialize VGA image structure @@ -76,39 +68,6 @@ int sd_vga_image_copy(sd_vga_image *dst, const sd_vga_image *src); */ void sd_vga_image_free(sd_vga_image *img); -/*! \brief Regenerates the stencil from a color index - * - * This function regenerates the invisibility mask for the VGA image. - * A necative value for stencil_index will lead to a completely opaque background, - * while a value of 0-255 will create a stencil from colors of this index. - * - * \retval SD_INVALID_INPUT Bad index value or img was NULL - * \retval SD_SUCCESS All good. - * - * \param img VGA image struct to modify. - * \param stencil_index Color key to use for invisibility - */ -int sd_vga_image_stencil_index(sd_vga_image *img, int stencil_index); - -/*! \brief Encode RGBA data to VGA data - * - * Encodes RGBA image data to VGA image data. Color values will be matched to exact values in - * the palette. If no matching value is found for the pixel, the pixel color will be black. - * - * Note! The output VGA image will be created here. If the image had been - * already created by using sd_vga_image_create() previously, there may - * potentially be a memory leak, since the old image internals will not be freed. - * - * \retval SD_INVALID_INPUT Dst, src or palette was NULL. - * \retval SD_SUCCESS Success. - * - * \param dst Destination VGA image pointer. - * \param src Source RGBA image pointer - * \param pal Palette that should be used for the conversion - * \param remapping Palette remapping table that should be used. -1 for none. - */ -int sd_vga_image_encode(sd_vga_image *dst, const sd_rgba_image *src, const palette *pal, int remapping); - /*! \brief Decode VGA data to RGBA format * * Decodes the VGA image to RGBA image format. @@ -164,8 +123,4 @@ int sd_vga_image_from_png(sd_vga_image *img, const char *filename); */ int sd_vga_image_to_png(const sd_vga_image *img, const palette *pal, const char *filename); -#ifdef __cplusplus -} -#endif - #endif // SD_VGA_IMAGE_H diff --git a/src/game/gui/text_render.c b/src/game/gui/text_render.c index 43ae75178..bbe8ae9fa 100644 --- a/src/game/gui/text_render.c +++ b/src/game/gui/text_render.c @@ -66,7 +66,7 @@ int text_render_char(const text_settings *settings, text_mode state, int x, int } // Draw the actual font - video_draw_offset(*sur, x, y, color, 255); + video_draw_offset(*sur, x, y, color - 1, 255); return (*sur)->w; } @@ -335,7 +335,7 @@ int font_render_char_shadowed(const font *font, char ch, int x, int y, uint8_t c video_draw_offset(*sur, x, y - 1, shadow_color, 255); // Handle the font face itself - video_draw_offset(*sur, x, y, c, 255); + video_draw_offset(*sur, x, y, c - 1, 255); return (*sur)->w; } diff --git a/src/game/protos/intersect.c b/src/game/protos/intersect.c index 21ae45b2e..73f622753 100644 --- a/src/game/protos/intersect.c +++ b/src/game/protos/intersect.c @@ -129,7 +129,7 @@ int intersect_sprite_hitpoint(object *obj, object *target, int level, vec2i *poi if(target_dir == OBJECT_FACE_LEFT) { hitpoint = (ycoord * sfc->w) + (sfc->w - xcoord); } - if(hitpoint < sfc->w * sfc->h && sfc->stencil[hitpoint] > 0) { + if(hitpoint < sfc->w * sfc->h && sfc->data[hitpoint] != sfc->transparent) { hcoords[found++] = vec2i_create(xcoord, ycoord); if(found >= level) { vec2f sum = vec2f_create(0, 0); diff --git a/src/game/protos/scene.c b/src/game/protos/scene.c index e2472bf71..b9af2b77c 100644 --- a/src/game/protos/scene.c +++ b/src/game/protos/scene.c @@ -1,6 +1,4 @@ #include "game/protos/scene.h" -#include "formats/af.h" -#include "formats/move.h" #include "game/game_player.h" #include "game/game_state_type.h" #include "resources/af_loader.h" @@ -33,6 +31,7 @@ int scene_create(scene *scene, game_state *gs, int scene_id) { scene->gs = gs; scene->af_data[0] = NULL; scene->af_data[1] = NULL; + scene->static_ticks_since_start = 0; // Init functions scene->userdata = NULL; @@ -107,7 +106,6 @@ void scene_init(scene *scene) { } int scene_clone(scene *src, scene *dst, game_state *gs) { - memcpy(dst, src, sizeof(scene)); dst->gs = gs; if(src->clone) { @@ -170,6 +168,7 @@ int scene_anim_prio_override(scene *scene, int anim_id) { } void scene_static_tick(scene *scene, int paused) { + scene->static_ticks_since_start++; if(scene->static_tick != NULL) { scene->static_tick(scene, paused); } @@ -187,6 +186,11 @@ void scene_dynamic_tick(scene *scene, int paused) { } void scene_input_poll(scene *scene) { + if(scene->static_ticks_since_start < 25) { + // Wait a bit at scene startup so that inputs from previous scene + // don't bleed to this one. + return; + } if(scene->input_poll != NULL) { scene->input_poll(scene); } diff --git a/src/game/protos/scene.h b/src/game/protos/scene.h index 9a1990f79..57bfae9ee 100644 --- a/src/game/protos/scene.h +++ b/src/game/protos/scene.h @@ -33,6 +33,7 @@ struct scene_t { bk *bk_data; af *af_data[2]; void *userdata; + int static_ticks_since_start; scene_free_cb free; scene_event_cb event; diff --git a/src/game/scenes/melee.c b/src/game/scenes/melee.c index 9d3d50df3..0d1acb6cb 100644 --- a/src/game/scenes/melee.c +++ b/src/game/scenes/melee.c @@ -153,7 +153,7 @@ void melee_tick(scene *scene, int paused) { game_state_set_next(scene->gs, SCENE_MENU); return; } - } while((i = i->next)); + } while((i = i->next) != NULL); } i = player2->ctrl->extra_events; if(i) { @@ -164,7 +164,7 @@ void melee_tick(scene *scene, int paused) { game_state_set_next(scene->gs, SCENE_MENU); return; } - } while((i = i->next)); + } while((i = i->next) != NULL); } if(local->page == HAR_SELECT && local->ticks % 10 == 1) { @@ -388,7 +388,7 @@ void melee_input_tick(scene *scene) { } else if(i->type == EVENT_TYPE_CLOSE) { game_state_set_next(scene->gs, SCENE_MENU); } - } while((i = i->next)); + } while((i = i->next) != NULL); } controller_free_chain(p1); i = p2; @@ -399,7 +399,7 @@ void melee_input_tick(scene *scene) { } else if(i->type == EVENT_TYPE_CLOSE) { game_state_set_next(scene->gs, SCENE_MENU); } - } while((i = i->next)); + } while((i = i->next) != NULL); } controller_free_chain(p2); } @@ -609,7 +609,7 @@ static void load_har_portraits(scene *scene, melee_local *local) { 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); + surface_set_transparency(&target->enabled, 0xD0); // Copy the enabled image, and compress the colors to grayscale surface_create_from(&target->disabled, &target->enabled); @@ -665,6 +665,7 @@ int melee_create(scene *scene) { // Create a black surface for the highlight box. We modify the palette in renderer. unsigned char *black = omf_calloc(1, 51 * 36); surface_create_from_data(&local->select_hilight, 51, 36, black); + surface_set_transparency(&local->select_hilight, -1); omf_free(black); // set up the magic controller hooks diff --git a/src/resources/bk.c b/src/resources/bk.c index 3129fe99b..25e8a1534 100644 --- a/src/resources/bk.c +++ b/src/resources/bk.c @@ -10,8 +10,7 @@ void bk_create(bk *b, void *src) { b->file_id = sdbk->file_id; // Copy VGA image - surface_create_from_data(&b->background, sdbk->background->w, sdbk->background->h, - (unsigned char *)sdbk->background->data); + surface_create_from_vga(&b->background, sdbk->background); // Copy sound translation table memcpy(b->sound_translation_table, sdbk->soundtable, 30); diff --git a/src/resources/fonts.c b/src/resources/fonts.c index e69de88af..a15d6d3df 100644 --- a/src/resources/fonts.c +++ b/src/resources/fonts.c @@ -62,8 +62,9 @@ int font_load(font *font, const char *filename, unsigned int size) { sd_vga_image_create(&img, pixsize, pixsize); for(int i = 0; i < 224; i++) { sur = omf_calloc(1, sizeof(surface)); - sd_font_decode(&sdfont, &img, i, 0); + sd_font_decode(&sdfont, &img, i, 1); surface_create_from_vga(sur, &img); + surface_set_transparency(sur, 0); vector_append(&font->surfaces, &sur); } @@ -96,8 +97,9 @@ int pcx_font_load(font *font, const char *filename, int8_t palette_offset) { for(int i = 0; i < pcx_font.glyph_count; i++) { sd_vga_image_create(&img, pcx_font.glyphs[i].width, pixsize); sur = omf_calloc(1, sizeof(surface)); - pcx_font_decode(&pcx_font, &img, i, 0); + pcx_font_decode(&pcx_font, &img, i, 1); surface_create_from_vga(sur, &img); + surface_set_transparency(sur, 0); vector_append(&font->surfaces, &sur); sd_vga_image_free(&img); } diff --git a/src/resources/sprite.c b/src/resources/sprite.c index 32a721292..cc2295894 100644 --- a/src/resources/sprite.c +++ b/src/resources/sprite.c @@ -2,7 +2,6 @@ #include "resources/sprite.h" #include "utils/allocator.h" #include -#include void sprite_create_custom(sprite *sp, vec2i pos, surface *data) { sp->id = -1; @@ -21,7 +20,6 @@ void sprite_create(sprite *sp, void *src, int id) { sd_vga_image raw; sd_sprite_vga_decode(&raw, sdsprite); surface_create_from_data(sp->data, raw.w, raw.h, (unsigned char *)raw.data); - memcpy(sp->data->stencil, raw.stencil, raw.w * raw.h); sd_vga_image_free(&raw); } diff --git a/src/video/color.c b/src/video/color.c deleted file mode 100644 index f2e8181f7..000000000 --- a/src/video/color.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "video/color.h" - -color color_create(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - color c; - c.r = r; - c.g = g; - c.b = b; - c.a = a; - return c; -} diff --git a/src/video/color.h b/src/video/color.h index b16cc4fac..a5b60eb43 100644 --- a/src/video/color.h +++ b/src/video/color.h @@ -12,12 +12,10 @@ #define COLOR_DARK_GREEN 0xA0 #define COLOR_YELLOW 0xFF -typedef struct color_t color; - -struct color_t { - unsigned char r, g, b, a; -}; - -color color_create(unsigned char r, unsigned char g, unsigned char b, unsigned char a); +typedef struct color { + unsigned char r; + unsigned char g; + unsigned char b; +} color; #endif // COLOR_H diff --git a/src/video/opengl/object_array.c b/src/video/opengl/object_array.c index 23fbdba4a..86e347c99 100644 --- a/src/video/opengl/object_array.c +++ b/src/video/opengl/object_array.c @@ -17,6 +17,7 @@ typedef struct { GLfloat y; GLfloat tex_x; GLfloat tex_y; + GLint transparency; GLint blend_mode; GLint palette_offset; GLint palette_limit; @@ -49,7 +50,7 @@ typedef struct object_array { index++ static void setup_vao_layout(void) { - int stride = 4 * sizeof(GLfloat) + 3 * sizeof(GLint); + int stride = 4 * sizeof(GLfloat) + 4 * sizeof(GLint); int index = 0; unsigned char *step = 0; ATTRIB(index, stride, step, 2, GL_FLOAT, GL_FALSE); @@ -57,6 +58,7 @@ static void setup_vao_layout(void) { ATTRIB_I(index, stride, step, 1, GL_INT); ATTRIB_I(index, stride, step, 1, GL_INT); ATTRIB_I(index, stride, step, 1, GL_INT); + ATTRIB_I(index, stride, step, 1, GL_INT); } object_array *object_array_create(GLfloat src_w, GLfloat src_h) { @@ -126,17 +128,18 @@ void object_array_draw(const object_array *array, object_array_batch *state) { glMultiDrawArrays(GL_TRIANGLE_FAN, array->fans_starts + state->start, array->fans_sizes + state->start, count); } -#define COORDS(ptr, cx, cy, tx, ty, mode, pal_offset, pal_limit) \ +#define COORDS(ptr, cx, cy, tx, ty, transparency, mode, pal_offset, pal_limit) \ ptr.x = cx; \ ptr.y = cy; \ ptr.tex_x = tx; \ ptr.tex_y = ty; \ + ptr.transparency = transparency; \ ptr.blend_mode = mode; \ ptr.palette_offset = pal_offset; \ ptr.palette_limit = pal_limit; static void add_item(object_array *array, float dx, float dy, int x, int y, int w, int h, int tx, int ty, int tw, - int th, int flags, video_blend_mode blend_mode, int pal_offset, int pal_limit) { + int th, int flags, int transparency, video_blend_mode blend_mode, int pal_offset, int pal_limit) { float tx0, tx1; if(flags & FLIP_HORIZONTAL) { tx0 = (tx + tw) * dx; @@ -157,10 +160,10 @@ static void add_item(object_array *array, float dx, float dy, int x, int y, int object_data *data = (object_data *)array->mapping; int row = array->item_count * 4; - COORDS(data[row + 0], x + w, y + h, tx1, ty1, blend_mode, pal_offset, pal_limit); - COORDS(data[row + 1], x, y + h, tx0, ty1, blend_mode, pal_offset, pal_limit); - COORDS(data[row + 2], x, y, tx0, ty0, blend_mode, pal_offset, pal_limit); - COORDS(data[row + 3], x + w, y, tx1, ty0, blend_mode, pal_offset, pal_limit); + COORDS(data[row + 0], x + w, y + h, tx1, ty1, transparency, blend_mode, pal_offset, pal_limit); + COORDS(data[row + 1], x, y + h, tx0, ty1, transparency, blend_mode, pal_offset, pal_limit); + COORDS(data[row + 2], x, y, tx0, ty0, transparency, blend_mode, pal_offset, pal_limit); + COORDS(data[row + 3], x + w, y, tx1, ty0, transparency, blend_mode, pal_offset, pal_limit); array->fans_starts[array->item_count] = array->item_count * 4; array->fans_sizes[array->item_count] = 4; @@ -169,7 +172,7 @@ static void add_item(object_array *array, float dx, float dy, int x, int y, int } void object_array_add(object_array *array, int x, int y, int w, int h, int tx, int ty, int tw, int th, int flags, - video_blend_mode blend_mode, int pal_offset, int pal_limit) { + int transparency, video_blend_mode blend_mode, int pal_offset, int pal_limit) { if(array->item_count >= MAX_FANS) { PERROR("Too many objects!"); return; @@ -179,5 +182,5 @@ void object_array_add(object_array *array, int x, int y, int w, int h, int tx, i } float dx = 1.0f / array->src_w; float dy = 1.0f / array->src_h; - add_item(array, dx, dy, x, y, w, h, tx, ty, tw, th, flags, blend_mode, pal_offset, pal_limit); + add_item(array, dx, dy, x, y, w, h, tx, ty, tw, th, flags, transparency, blend_mode, pal_offset, pal_limit); } diff --git a/src/video/opengl/object_array.h b/src/video/opengl/object_array.h index 916eda7b1..af1c946e6 100644 --- a/src/video/opengl/object_array.h +++ b/src/video/opengl/object_array.h @@ -19,6 +19,6 @@ void object_array_begin(const object_array *array, object_array_batch *state); bool object_array_get_batch(const object_array *array, object_array_batch *state, video_blend_mode *mode); void object_array_draw(const object_array *array, object_array_batch *state); void object_array_add(object_array *array, int x, int y, int w, int h, int tx, int ty, int tw, int th, int flags, - video_blend_mode blend_mode, int pal_offset, int pal_limit); + int transparency, video_blend_mode blend_mode, int pal_offset, int pal_limit); #endif // OBJECT_ARRAY_H diff --git a/src/video/opengl/texture_atlas.c b/src/video/opengl/texture_atlas.c index 0ee93f7dc..a6a8bbe09 100644 --- a/src/video/opengl/texture_atlas.c +++ b/src/video/opengl/texture_atlas.c @@ -36,7 +36,7 @@ texture_atlas *atlas_create(GLuint tex_unit, uint16_t width, uint16_t height) { atlas->w = width; atlas->h = height; atlas->tex_unit = tex_unit; - atlas->texture_id = texture_create(tex_unit, width, height, GL_RG8, GL_RG); + atlas->texture_id = texture_create(tex_unit, width, height, GL_R8, GL_RED); zone item = {0, 0, width, height}; vector_append(&atlas->free_space, &item); DEBUG("Texture atlas %dx%d created", width, height); @@ -155,25 +155,16 @@ bool atlas_insert(texture_atlas *atlas, const char *bytes, uint16_t w, uint16_t } // Split found, add the area to the atlas. - texture_update(atlas->tex_unit, atlas->texture_id, free.x, free.y, w, h, GL_RG, bytes); + texture_update(atlas->tex_unit, atlas->texture_id, free.x, free.y, w, h, GL_RED, bytes); *nx = free.x; *ny = free.y; return true; } -static void convert_surface(const surface *src, char *dst) { - int size = src->w * src->h; - int w = 0; - for(int i = 0; i < size; i++) { - dst[w++] = src->data[i]; - dst[w++] = src->stencil[i]; - } -} - bool atlas_get(texture_atlas *atlas, const surface *surface, uint16_t *x, uint16_t *y, uint16_t *w, uint16_t *h) { // First, check if item is already in the texture atlas. If it is, return coords immediately. zone *coords; - if(hashmap_get(&atlas->items, (void *)&surface->hash, 4, (void **)&coords, NULL) == 0) { + if(hashmap_iget(&atlas->items, surface->guid, (void **)&coords, NULL) == 0) { *x = coords->x; *y = coords->y; *w = surface->w; @@ -183,15 +174,13 @@ bool atlas_get(texture_atlas *atlas, const surface *surface, uint16_t *x, uint16 // If item is NOT in the texture atlas, add it now. uint16_t nx, ny; - char tmp[surface->w * surface->h * 2]; - convert_surface(surface, tmp); - if(atlas_insert(atlas, tmp, surface->w, surface->h, &nx, &ny)) { + if(atlas_insert(atlas, (const char *)surface->data, surface->w, surface->h, &nx, &ny)) { *x = nx; *y = ny; *w = surface->w; *h = surface->h; zone cached = {nx, ny, surface->w, surface->h}; - hashmap_put(&atlas->items, (void *)&surface->hash, 4, &cached, sizeof(zone)); + hashmap_iput(&atlas->items, surface->guid, &cached, sizeof(zone)); return true; } diff --git a/src/video/surface.c b/src/video/surface.c index df7e299d3..8719b88e6 100644 --- a/src/video/surface.c +++ b/src/video/surface.c @@ -5,36 +5,21 @@ #include #include -#define FNV_INITIAL ((uint32_t)2166136261) - -static void fnv_32a_buf(uint32_t *hash, const void *buf, unsigned int len) { - unsigned char *bp = (unsigned char *)buf; - unsigned char *be = bp + len; - while(bp < be) { - *hash ^= (uint32_t)*bp++; - *hash *= ((uint32_t)0x01000193); - } -} - -static inline void create_hash(surface *sur) { - sur->hash = FNV_INITIAL; - fnv_32a_buf(&sur->hash, sur->data, sur->w * sur->h); - fnv_32a_buf(&sur->hash, sur->stencil, sur->w * sur->h); -} +// Each surface is tagged with a unique key. This is then used for texture atlas. +// This keeps track of the last index used. +static unsigned int guid = 0; void surface_create(surface *sur, int w, int h) { sur->data = omf_calloc(1, w * h); - sur->stencil = omf_calloc(1, w * h); - sur->hash = 0; + sur->guid = guid++; sur->w = w; sur->h = h; + sur->transparent = 0; } void surface_create_from_data(surface *sur, int w, int h, const unsigned char *src) { surface_create(sur, w, h); memcpy(sur->data, src, w * h); - memset(sur->stencil, 1, w * h); - create_hash(sur); } void surface_create_from_data_flip(surface *sur, int w, int h, const unsigned char *src) { @@ -42,55 +27,49 @@ void surface_create_from_data_flip(surface *sur, int w, int h, const unsigned ch for(int y = 0; y < h; y++) { memcpy(sur->data + (h - y - 1) * w, src + y * w, w); } - memset(sur->stencil, 1, w * h); - create_hash(sur); } void surface_create_from_vga(surface *sur, const sd_vga_image *src) { surface_create(sur, src->w, src->h); memcpy(sur->data, src->data, src->w * src->h); - memcpy(sur->stencil, src->stencil, src->w * src->h); - create_hash(sur); + sur->transparent = -1; } void surface_create_from_surface(surface *sur, int w, int h, int src_x, int src_y, const surface *src) { surface_create(sur, w, h); surface_sub(sur, src, 0, 0, src_x, src_y, w, h, SUB_METHOD_NONE); - create_hash(sur); -} - -void surface_generate_stencil(const surface *sur, int index) { - for(int i = 0; i < sur->w * sur->h; i++) { - sur->stencil[i] = (sur->data[i] == index) ? 0 : 1; - } + sur->transparent = src->transparent; } void surface_create_from_image(surface *sur, image *img) { surface_create_from_data(sur, img->w, img->h, img->data); + sur->transparent = -1; } -int surface_to_image(surface *sur, image *img) { +int surface_to_image(const surface *sur, image *img) { img->w = sur->w; img->h = sur->h; img->data = sur->data; return 0; } +void surface_set_transparency(surface *sur, int index) { + sur->transparent = index; +} + void surface_free(surface *sur) { omf_free(sur->data); - omf_free(sur->stencil); } void surface_clear(surface *sur) { memset(sur->data, 0, sur->w * sur->h); - create_hash(sur); + sur->guid = guid++; } void surface_create_from(surface *dst, const surface *src) { surface_create(dst, src->w, src->h); memcpy(dst->data, src->data, src->w * src->h); - memcpy(dst->stencil, src->stencil, src->w * src->h); - create_hash(dst); + dst->transparent = src->transparent; } // Copies a an area of old surface to an entirely new surface @@ -109,10 +88,9 @@ void surface_sub(surface *dst, const surface *src, int dst_x, int dst_y, int src break; } dst->data[dst_offset] = src->data[src_offset]; - dst->stencil[dst_offset] = src->stencil[src_offset]; } } - create_hash(dst); + dst->guid = guid++; } static uint8_t find_closest_gray(const screen_palette *pal, int range_start, int range_end, int ref) { @@ -156,7 +134,7 @@ 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); + sur->guid = guid++; } void surface_compress_index_blocks(surface *sur, int range_start, int range_end, int block_size, int amount) { @@ -170,7 +148,7 @@ void surface_compress_index_blocks(surface *sur, int range_start, int range_end, sur->data[i] = idx - old_idx + new_idx; } } - create_hash(sur); + sur->guid = guid++; } void surface_compress_remap(surface *sur, int range_start, int range_end, int remap_to, int amount) { @@ -185,7 +163,7 @@ void surface_compress_remap(surface *sur, int range_start, int range_end, int re } } } - create_hash(sur); + sur->guid = guid++; } bool surface_write_png(const surface *sur, const screen_palette *pal, const char *filename) { diff --git a/src/video/surface.h b/src/video/surface.h index 6f2196429..8b5fdba89 100644 --- a/src/video/surface.h +++ b/src/video/surface.h @@ -8,11 +8,11 @@ #include typedef struct { - uint32_t hash; + unsigned int guid; int w; int h; + int transparent; unsigned char *data; - unsigned char *stencil; } surface; enum @@ -28,12 +28,12 @@ void surface_create_from_image(surface *sur, image *img); void surface_create_from_data(surface *sur, int w, int h, const unsigned char *src); void surface_create_from_data_flip(surface *sur, int w, int h, const unsigned char *src); void surface_create_from_surface(surface *sur, int w, int h, int src_x, int src_y, const surface *src); -int surface_to_image(surface *sur, image *img); +int surface_to_image(const surface *sur, image *img); void surface_free(surface *sur); void surface_clear(surface *sur); void surface_sub(surface *dst, const surface *src, int dst_x, int dst_y, int src_x, int src_y, int w, int h, int method); -void surface_generate_stencil(const surface *sur, int index); +void surface_set_transparency(surface *dst, int index); /** * Flatten each block of {block_size} colors by decrementing the index by {amount} in each block. diff --git a/src/video/video.c b/src/video/video.c index e7b9e180b..bfb29b54f 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -258,6 +258,7 @@ void video_area_capture(surface *sur, int x, int y, int w, int h) { unsigned char *buffer = omf_calloc(1, w * h); glReadPixels(x, y, w, h, GL_RED, GL_UNSIGNED_BYTE, buffer); surface_create_from_data_flip(sur, w, h, buffer); + surface_set_transparency(sur, -1); free(buffer); } @@ -287,7 +288,7 @@ screen_palette *video_get_pal_ref(void) { void video_render_background(surface *sur) { uint16_t tx, ty, tw, th; if(atlas_get(g_video_state.atlas, sur, &tx, &ty, &tw, &th)) { - object_array_add(g_video_state.objects, 0, 0, 320, 200, tx, ty, tw, th, 0, BLEND_SET, 0, -1); + object_array_add(g_video_state.objects, 0, 0, 320, 200, tx, ty, tw, th, 0, sur->transparent, BLEND_SET, 0, -1); } } @@ -295,8 +296,8 @@ static void draw_args(video_state *state, const surface *sur, SDL_Rect *dst, vid int pal_offset, int pal_limit, unsigned int flip_mode) { uint16_t tx, ty, tw, th; if(atlas_get(g_video_state.atlas, sur, &tx, &ty, &tw, &th)) { - object_array_add(state->objects, dst->x, dst->y, dst->w, dst->h, tx, ty, tw, th, flip_mode, blend_mode, - pal_offset, pal_limit); + object_array_add(state->objects, dst->x, dst->y, dst->w, dst->h, tx, ty, tw, th, flip_mode, sur->transparent, + blend_mode, pal_offset, pal_limit); } } diff --git a/tools/bktool/main.c b/tools/bktool/main.c index 699d73f56..e66c7e63a 100644 --- a/tools/bktool/main.c +++ b/tools/bktool/main.c @@ -654,12 +654,11 @@ int main(int argc, char *argv[]) { struct arg_lit *pop = arg_lit0(NULL, "pop", "Pop the last element (requires --key)"); struct arg_file *export = arg_file0(NULL, "export", "", "Exports data to a file (requires --key)"); struct arg_file *import = arg_file0(NULL, "import", "", "Imports data from a file (requires --key)"); - struct arg_int *stencil = arg_int0(NULL, "stencil", "", "Stencil index for image (requires --import)"); struct arg_int *scale = arg_int0(NULL, "scale", "", "Scales sprites (requires --play)"); struct arg_lit *parse = arg_lit0(NULL, "parse", "Parse value (requires --key)"); struct arg_end *end = arg_end(30); - void *argtable[] = {help, vers, file, new, output, anim, all_anims, sprite, keylist, key, - value, push, pop, export, import, stencil, play, scale, parse, end}; + void *argtable[] = {help, vers, file, new, output, anim, all_anims, sprite, keylist, key, + value, push, pop, export, import, play, scale, parse, end}; const char *progname = "bktool"; // Make sure everything got allocated @@ -801,11 +800,7 @@ int main(int argc, char *argv[]) { } else if(export->count > 0) { sprite_export_key(sp, key->sval, key->count, export->filename[0], &bk); } else if(import->count > 0) { - int st = -1; - if(stencil->count > 0) { - st = stencil->ival[0]; - } - sprite_import_key(sp, key->sval, key->count, import->filename[0], st); + sprite_import_key(sp, key->sval, key->count, import->filename[0]); } else { sprite_get_key(sp, key->sval, key->count); } diff --git a/tools/shared/animation_misc.c b/tools/shared/animation_misc.c index 178f3497b..60a7a40dc 100644 --- a/tools/shared/animation_misc.c +++ b/tools/shared/animation_misc.c @@ -105,7 +105,7 @@ void sprite_export_key(sd_sprite *s, const char **key, int kcount, const char *f } } -void sprite_import_key(sd_sprite *s, const char **key, int kcount, const char *filename, int transparent_index) { +void sprite_import_key(sd_sprite *s, const char **key, int kcount, const char *filename) { switch(sprite_key_get_id(key[0])) { case 1: case 2: @@ -120,12 +120,6 @@ void sprite_import_key(sd_sprite *s, const char **key, int kcount, const char *f return; } - ret = sd_vga_image_stencil_index(&img, transparent_index); - if(ret != SD_SUCCESS) { - printf("Stencil oculd not be set: %s\n", sd_get_error(ret)); - return; - } - ret = sd_sprite_vga_encode(s, &img); sd_vga_image_free(&img); if(ret != SD_SUCCESS) { diff --git a/tools/shared/animation_misc.h b/tools/shared/animation_misc.h index 4100b0327..bfa27f0c0 100644 --- a/tools/shared/animation_misc.h +++ b/tools/shared/animation_misc.h @@ -13,7 +13,7 @@ void sprite_keylist(void); void sprite_info(sd_sprite *s, int anim, int sprite); void sprite_export_key(sd_sprite *s, const char **key, int kcount, const char *filename, sd_bk_file *bk); -void sprite_import_key(sd_sprite *s, const char **key, int kcount, const char *filename, int transparent_index); +void sprite_import_key(sd_sprite *s, const char **key, int kcount, const char *filename); void anim_common_info(sd_animation *ani); int anim_key_get_id(const char *key);