-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Split conversion-related code into a separate file. * Renamed loaders to fileformat handlers. * Added API for exporting into one of the supported file formats. * Replaced serialization APIs with an "internal" fileformat capable of of storing any Pixmap. It is identical to the serialization format. * Removed PNG writing code from video_screenshot_task, now using the new pixmap export API instead.
- Loading branch information
Showing
14 changed files
with
723 additions
and
504 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,358 @@ | ||
/* | ||
* This software is licensed under the terms of the MIT License. | ||
* See COPYING for further information. | ||
* --- | ||
* Copyright (c) 2011-2019, Lukas Weber <[email protected]>. | ||
* Copyright (c) 2012-2019, Andrei Alexeyev <[email protected]>. | ||
*/ | ||
|
||
#include "taisei.h" | ||
|
||
#include "pixmap.h" | ||
#include "util.h" | ||
|
||
// NOTE: this is pretty stupid and not at all optimized, patches welcome | ||
|
||
#define _CONV_FUNCNAME convert_u8_to_u8 | ||
#define _CONV_IN_MAX UINT8_MAX | ||
#define _CONV_IN_TYPE uint8_t | ||
#define _CONV_OUT_MAX UINT8_MAX | ||
#define _CONV_OUT_TYPE uint8_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u8_to_u16 | ||
#define _CONV_IN_MAX UINT8_MAX | ||
#define _CONV_IN_TYPE uint8_t | ||
#define _CONV_OUT_MAX UINT16_MAX | ||
#define _CONV_OUT_TYPE uint16_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u8_to_u32 | ||
#define _CONV_IN_MAX UINT8_MAX | ||
#define _CONV_IN_TYPE uint8_t | ||
#define _CONV_OUT_MAX UINT32_MAX | ||
#define _CONV_OUT_TYPE uint32_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u8_to_f32 | ||
#define _CONV_IN_MAX UINT8_MAX | ||
#define _CONV_IN_TYPE uint8_t | ||
#define _CONV_OUT_MAX 1.0f | ||
#define _CONV_OUT_TYPE float | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u16_to_u8 | ||
#define _CONV_IN_MAX UINT16_MAX | ||
#define _CONV_IN_TYPE uint16_t | ||
#define _CONV_OUT_MAX UINT8_MAX | ||
#define _CONV_OUT_TYPE uint8_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u16_to_u16 | ||
#define _CONV_IN_MAX UINT16_MAX | ||
#define _CONV_IN_TYPE uint16_t | ||
#define _CONV_OUT_MAX UINT16_MAX | ||
#define _CONV_OUT_TYPE uint16_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u16_to_u32 | ||
#define _CONV_IN_MAX UINT16_MAX | ||
#define _CONV_IN_TYPE uint16_t | ||
#define _CONV_OUT_MAX UINT32_MAX | ||
#define _CONV_OUT_TYPE uint32_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u16_to_f32 | ||
#define _CONV_IN_MAX UINT16_MAX | ||
#define _CONV_IN_TYPE uint16_t | ||
#define _CONV_OUT_MAX 1.0f | ||
#define _CONV_OUT_TYPE float | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u32_to_u8 | ||
#define _CONV_IN_MAX UINT32_MAX | ||
#define _CONV_IN_TYPE uint32_t | ||
#define _CONV_OUT_MAX UINT8_MAX | ||
#define _CONV_OUT_TYPE uint8_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u32_to_u16 | ||
#define _CONV_IN_MAX UINT32_MAX | ||
#define _CONV_IN_TYPE uint32_t | ||
#define _CONV_OUT_MAX UINT16_MAX | ||
#define _CONV_OUT_TYPE uint16_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u32_to_u32 | ||
#define _CONV_IN_MAX UINT32_MAX | ||
#define _CONV_IN_TYPE uint32_t | ||
#define _CONV_OUT_MAX UINT32_MAX | ||
#define _CONV_OUT_TYPE uint32_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_u32_to_f32 | ||
#define _CONV_IN_MAX UINT32_MAX | ||
#define _CONV_IN_TYPE uint32_t | ||
#define _CONV_OUT_MAX 1.0f | ||
#define _CONV_OUT_TYPE float | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_f32_to_u8 | ||
#define _CONV_IN_MAX 1.0f | ||
#define _CONV_IN_TYPE float | ||
#define _CONV_OUT_MAX UINT8_MAX | ||
#define _CONV_OUT_TYPE uint8_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_f32_to_u16 | ||
#define _CONV_IN_MAX 1.0f | ||
#define _CONV_IN_TYPE float | ||
#define _CONV_OUT_MAX UINT16_MAX | ||
#define _CONV_OUT_TYPE uint16_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_f32_to_u32 | ||
#define _CONV_IN_MAX 1.0f | ||
#define _CONV_IN_TYPE float | ||
#define _CONV_OUT_MAX UINT32_MAX | ||
#define _CONV_OUT_TYPE uint32_t | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define _CONV_FUNCNAME convert_f32_to_f32 | ||
#define _CONV_IN_MAX 1.0f | ||
#define _CONV_IN_TYPE float | ||
#define _CONV_OUT_MAX 1.0f | ||
#define _CONV_OUT_TYPE float | ||
#include "pixmap_conversion.inc.h" | ||
|
||
#define DEPTH_FLOAT_BIT (1 << 10) | ||
|
||
typedef void (*convfunc_t)( | ||
size_t in_elements, | ||
size_t out_elements, | ||
size_t num_pixels, | ||
void *vbuf_in, | ||
void *vbuf_out, | ||
int swizzle[4] | ||
); | ||
|
||
#define CONV(in, in_depth, out, out_depth) { convert_##in##_to_##out, in_depth, out_depth } | ||
|
||
struct conversion_def { | ||
convfunc_t func; | ||
uint depth_in; | ||
uint depth_out; | ||
}; | ||
|
||
struct conversion_def conversion_table[] = { | ||
CONV(u8, 8, u8, 8), | ||
CONV(u8, 8, u16, 16), | ||
CONV(u8, 8, u32, 32), | ||
CONV(u8, 8, f32, 32 | DEPTH_FLOAT_BIT), | ||
|
||
CONV(u16, 16, u8, 8), | ||
CONV(u16, 16, u16, 16), | ||
CONV(u16, 16, u32, 32), | ||
CONV(u16, 16, f32, 32 | DEPTH_FLOAT_BIT), | ||
|
||
CONV(u32, 32, u8, 8), | ||
CONV(u32, 16, u16, 16), | ||
CONV(u32, 32, u32, 32), | ||
CONV(u32, 32, f32, 32 | DEPTH_FLOAT_BIT), | ||
|
||
CONV(f32, 32 | DEPTH_FLOAT_BIT, u8, 8), | ||
CONV(f32, 16 | DEPTH_FLOAT_BIT, u16, 16), | ||
CONV(f32, 32 | DEPTH_FLOAT_BIT, u32, 32), | ||
CONV(f32, 32 | DEPTH_FLOAT_BIT, f32, 32 | DEPTH_FLOAT_BIT), | ||
|
||
{ 0 } | ||
}; | ||
|
||
static struct conversion_def* find_conversion(uint depth_in, uint depth_out) { | ||
for(struct conversion_def *cv = conversion_table; cv->func; ++cv) { | ||
if(cv->depth_in == depth_in && cv->depth_out == depth_out) { | ||
return cv; | ||
} | ||
} | ||
|
||
log_fatal("Pixmap conversion for %upbc -> %upbc undefined, please add", depth_in, depth_out); | ||
} | ||
|
||
static void pixmap_copy_meta(const Pixmap *src, Pixmap *dst) { | ||
dst->format = src->format; | ||
dst->width = src->width; | ||
dst->height = src->height; | ||
dst->origin = src->origin; | ||
} | ||
|
||
void pixmap_copy(const Pixmap *src, Pixmap *dst) { | ||
assert(dst->data.untyped != NULL); | ||
assert(src->data_size > 0); | ||
assert(dst->data_size >= src->data_size); | ||
|
||
if(!pixmap_format_is_compressed(src->format)) { | ||
assert(src->data_size == pixmap_data_size(src->format, src->width, src->height)); | ||
} | ||
|
||
pixmap_copy_meta(src, dst); | ||
memcpy(dst->data.untyped, src->data.untyped, src->data_size); | ||
} | ||
|
||
void pixmap_copy_alloc(const Pixmap *src, Pixmap *dst) { | ||
dst->data.untyped = pixmap_alloc_buffer_for_copy(src, &dst->data_size); | ||
pixmap_copy(src, dst); | ||
} | ||
|
||
void pixmap_convert(const Pixmap *src, Pixmap *dst, PixmapFormat format) { | ||
size_t num_pixels = src->width * src->height; | ||
size_t pixel_size = PIXMAP_FORMAT_PIXEL_SIZE(format); | ||
|
||
assert(dst->data.untyped != NULL); | ||
pixmap_copy_meta(src, dst); | ||
|
||
if(src->format == format) { | ||
memcpy(dst->data.untyped, src->data.untyped, num_pixels * pixel_size); | ||
return; | ||
} | ||
|
||
dst->format = format; | ||
|
||
struct conversion_def *cv = find_conversion( | ||
PIXMAP_FORMAT_DEPTH(src->format) | (PIXMAP_FORMAT_IS_FLOAT(src->format) * DEPTH_FLOAT_BIT), | ||
PIXMAP_FORMAT_DEPTH(dst->format) | (PIXMAP_FORMAT_IS_FLOAT(dst->format) * DEPTH_FLOAT_BIT) | ||
); | ||
|
||
cv->func( | ||
PIXMAP_FORMAT_LAYOUT(src->format), | ||
PIXMAP_FORMAT_LAYOUT(dst->format), | ||
num_pixels, | ||
src->data.untyped, | ||
dst->data.untyped, | ||
NULL | ||
); | ||
} | ||
|
||
static int swizzle_idx(char s) { | ||
switch(s) { | ||
case 'r': return 0; | ||
case 'g': return 1; | ||
case 'b': return 2; | ||
case 'a': return 3; | ||
case '0': return 4; | ||
case '1': return 5; | ||
default: UNREACHABLE; | ||
} | ||
} | ||
|
||
void pixmap_swizzle_inplace(Pixmap *px, SwizzleMask swizzle) { | ||
uint channels = pixmap_format_layout(px->format); | ||
swizzle = swizzle_canonize(swizzle); | ||
|
||
if(!swizzle_is_significant(swizzle, channels)) { | ||
return; | ||
} | ||
|
||
uint cvt_id = pixmap_format_depth(px->format) | (pixmap_format_is_float(px->format) * DEPTH_FLOAT_BIT); | ||
struct conversion_def *cv = find_conversion(cvt_id, cvt_id); | ||
|
||
cv->func( | ||
channels, | ||
channels, | ||
px->width * px->height, | ||
px->data.untyped, | ||
px->data.untyped, | ||
(int[]) { | ||
swizzle_idx(swizzle.r), | ||
swizzle_idx(swizzle.g), | ||
swizzle_idx(swizzle.b), | ||
swizzle_idx(swizzle.a), | ||
} | ||
); | ||
} | ||
|
||
void pixmap_convert_alloc(const Pixmap *src, Pixmap *dst, PixmapFormat format) { | ||
dst->data.untyped = pixmap_alloc_buffer_for_conversion(src, format, &dst->data_size); | ||
pixmap_convert(src, dst, format); | ||
} | ||
|
||
void pixmap_convert_inplace_realloc(Pixmap *src, PixmapFormat format) { | ||
assert(src->data.untyped != NULL); | ||
|
||
if(src->format == format) { | ||
return; | ||
} | ||
|
||
Pixmap tmp; | ||
pixmap_copy_meta(src, &tmp); | ||
pixmap_convert_alloc(src, &tmp, format); | ||
|
||
free(src->data.untyped); | ||
*src = tmp; | ||
} | ||
|
||
void pixmap_flip_y(const Pixmap *src, Pixmap *dst) { | ||
assert(dst->data.untyped != NULL); | ||
pixmap_copy_meta(src, dst); | ||
|
||
size_t rows = src->height; | ||
size_t row_length = src->width * PIXMAP_FORMAT_PIXEL_SIZE(src->format); | ||
|
||
if(UNLIKELY(row_length == 0)) { | ||
return; | ||
} | ||
|
||
char *cdst = dst->data.untyped; | ||
const char *csrc = src->data.untyped; | ||
|
||
for(size_t row = 0, irow = rows - 1; row < rows; ++row, --irow) { | ||
memcpy(cdst + irow * row_length, csrc + row * row_length, row_length); | ||
} | ||
} | ||
|
||
void pixmap_flip_y_alloc(const Pixmap *src, Pixmap *dst) { | ||
dst->data.untyped = pixmap_alloc_buffer_for_copy(src, &dst->data_size); | ||
pixmap_flip_y(src, dst); | ||
} | ||
|
||
void pixmap_flip_y_inplace(Pixmap *src) { | ||
size_t rows = src->height; | ||
size_t row_length = src->width * PIXMAP_FORMAT_PIXEL_SIZE(src->format); | ||
|
||
if(UNLIKELY(row_length == 0)) { | ||
return; | ||
} | ||
|
||
char *data = src->data.untyped; | ||
char swap_buffer[row_length]; | ||
|
||
for(size_t row = 0; row < rows / 2; ++row) { | ||
memcpy(swap_buffer, data + row * row_length, row_length); | ||
memcpy(data + row * row_length, data + (rows - row - 1) * row_length, row_length); | ||
memcpy(data + (rows - row - 1) * row_length, swap_buffer, row_length); | ||
} | ||
} | ||
|
||
void pixmap_flip_to_origin(const Pixmap *src, Pixmap *dst, PixmapOrigin origin) { | ||
assert(dst->data.untyped != NULL); | ||
|
||
if(src->origin == origin) { | ||
pixmap_copy(src, dst); | ||
} else { | ||
pixmap_flip_y(src, dst); | ||
dst->origin = origin; | ||
} | ||
} | ||
|
||
void pixmap_flip_to_origin_alloc(const Pixmap *src, Pixmap *dst, PixmapOrigin origin) { | ||
dst->data.untyped = pixmap_alloc_buffer_for_copy(src, &dst->data_size); | ||
pixmap_flip_to_origin(src, dst, origin); | ||
} | ||
|
||
void pixmap_flip_to_origin_inplace(Pixmap *src, PixmapOrigin origin) { | ||
if(src->origin == origin) { | ||
return; | ||
} | ||
|
||
pixmap_flip_y_inplace(src); | ||
src->origin = origin; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* This software is licensed under the terms of the MIT License. | ||
* See COPYING for further information. | ||
* --- | ||
* Copyright (c) 2011-2019, Lukas Weber <[email protected]>. | ||
* Copyright (c) 2012-2019, Andrei Alexeyev <[email protected]>. | ||
*/ | ||
|
||
#ifndef IGUARD_pixmap_fileformats_fileformats_h | ||
#define IGUARD_pixmap_fileformats_fileformats_h | ||
|
||
#include "taisei.h" | ||
|
||
#include <SDL.h> | ||
|
||
#include "../pixmap.h" | ||
|
||
typedef struct PixmapFileFormatHandler { | ||
bool (*probe)(SDL_RWops *stream); | ||
bool (*load)(SDL_RWops *stream, Pixmap *pixmap, PixmapFormat preferred_format); | ||
bool (*save)(SDL_RWops *stream, const Pixmap *pixmap, const PixmapSaveOptions *opts); | ||
const char **filename_exts; | ||
const char *name; | ||
} PixmapFileFormatHandler; | ||
|
||
extern PixmapFileFormatHandler pixmap_fileformat_internal; | ||
extern PixmapFileFormatHandler pixmap_fileformat_png; | ||
extern PixmapFileFormatHandler pixmap_fileformat_webp; | ||
|
||
#endif // IGUARD_pixmap_fileformats_fileformats_h |
Oops, something went wrong.