mirror of https://github.com/aap/librw.git
png support
This commit is contained in:
parent
4946235d49
commit
49ca300b88
|
@ -10,11 +10,6 @@
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
#include "rwengine.h"
|
#include "rwengine.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
/* srsly? */
|
|
||||||
#define strdup _strdup
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PLUGIN_ID 0
|
#define PLUGIN_ID 0
|
||||||
|
|
||||||
namespace rw {
|
namespace rw {
|
||||||
|
|
|
@ -283,6 +283,7 @@ Engine::start(void)
|
||||||
// Register some image formats. Or should we leave that to the user?
|
// Register some image formats. Or should we leave that to the user?
|
||||||
Image::registerFileFormat("tga", readTGA, writeTGA);
|
Image::registerFileFormat("tga", readTGA, writeTGA);
|
||||||
Image::registerFileFormat("bmp", readBMP, writeBMP);
|
Image::registerFileFormat("bmp", readBMP, writeBMP);
|
||||||
|
Image::registerFileFormat("png", readPNG, writePNG);
|
||||||
|
|
||||||
Engine::state = Started;
|
Engine::state = Started;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,149 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "rwbase.h"
|
||||||
|
#include "rwerror.h"
|
||||||
|
#include "rwplg.h"
|
||||||
|
#include "rwpipeline.h"
|
||||||
|
#include "rwobjects.h"
|
||||||
|
#include "rwengine.h"
|
||||||
|
|
||||||
|
#include "lodepng/lodepng.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* srsly? */
|
||||||
|
#define strdup _strdup
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PLUGIN_ID 0
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
|
||||||
|
|
||||||
|
Image*
|
||||||
|
readPNG(const char *filename)
|
||||||
|
{
|
||||||
|
Image *image;
|
||||||
|
uint32 length;
|
||||||
|
uint8 *data = getFileContents(filename, &length);
|
||||||
|
assert(data != nil);
|
||||||
|
|
||||||
|
lodepng::State state;
|
||||||
|
std::vector<uint8> raw;
|
||||||
|
uint32 w, h;
|
||||||
|
|
||||||
|
// First try: decode without conversion to see if we understand the format
|
||||||
|
state.decoder.color_convert = 0;
|
||||||
|
uint32 error = lodepng::decode(raw, w, h, state, data, length);
|
||||||
|
if(error){
|
||||||
|
RWERROR((ERR_GENERAL, lodepng_error_text(error)));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state.info_raw.bitdepth == 4 && state.info_raw.colortype == LCT_PALETTE){
|
||||||
|
image = Image::create(w, h, 4);
|
||||||
|
image->allocate();
|
||||||
|
memcpy(image->palette, state.info_raw.palette, state.info_raw.palettesize*4);
|
||||||
|
expandPal4_BE(image->pixels, image->stride, &raw[0], w/2, w, h);
|
||||||
|
}else if(state.info_raw.bitdepth == 8){
|
||||||
|
switch(state.info_raw.colortype){
|
||||||
|
case LCT_PALETTE:
|
||||||
|
image = Image::create(w, h, state.info_raw.palettesize <= 16 ? 4 : 8);
|
||||||
|
image->allocate();
|
||||||
|
memcpy(image->palette, state.info_raw.palette, state.info_raw.palettesize*4);
|
||||||
|
memcpy(image->pixels, &raw[0], w*h);
|
||||||
|
break;
|
||||||
|
case LCT_RGB:
|
||||||
|
image = Image::create(w, h, 24);
|
||||||
|
image->allocate();
|
||||||
|
memcpy(image->pixels, &raw[0], w*h*3);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Second try: just load as 32 bit
|
||||||
|
lodepng_state_init(&state);
|
||||||
|
error = lodepng::decode(raw, w, h, state, data, length);
|
||||||
|
if(error){
|
||||||
|
RWERROR((ERR_GENERAL, lodepng_error_text(error)));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
// fall through
|
||||||
|
case LCT_RGBA:
|
||||||
|
image = Image::create(w, h, 32);
|
||||||
|
image->allocate();
|
||||||
|
memcpy(image->pixels, &raw[0], w*h*4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writePNG(Image *image, const char *filename)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
StreamFile file;
|
||||||
|
if(!file.open(filename, "wb")){
|
||||||
|
RWERROR((ERR_FILE, filename));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8> raw;
|
||||||
|
uint8 *pixels;
|
||||||
|
lodepng::State state;
|
||||||
|
|
||||||
|
pixels = image->pixels;
|
||||||
|
switch(image->depth){
|
||||||
|
case 4:
|
||||||
|
state.info_raw.bitdepth = 4;
|
||||||
|
state.info_raw.colortype = LCT_PALETTE;
|
||||||
|
state.info_png.color.bitdepth = 4;
|
||||||
|
state.info_png.color.colortype = LCT_PALETTE;
|
||||||
|
state.encoder.auto_convert = 0;
|
||||||
|
for(i = 0; i < (1<<image->depth); i++){
|
||||||
|
uint8 *col = &image->palette[i*4];
|
||||||
|
lodepng_palette_add(&state.info_png.color, col[0], col[1], col[2], col[3]);
|
||||||
|
lodepng_palette_add(&state.info_raw, col[0], col[1], col[2], col[3]);
|
||||||
|
}
|
||||||
|
pixels = rwNewT(uint8, image->width/2*image->height, ID_IMAGE | MEMDUR_FUNCTION);
|
||||||
|
compressPal4_BE(pixels, image->width/2, image->pixels, image->width, image->width, image->height);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
state.info_raw.colortype = LCT_PALETTE;
|
||||||
|
state.info_png.color.colortype = LCT_PALETTE;
|
||||||
|
state.encoder.auto_convert = 0;
|
||||||
|
for(i = 0; i < (1<<image->depth); i++){
|
||||||
|
uint8 *col = &image->palette[i*4];
|
||||||
|
lodepng_palette_add(&state.info_png.color, col[0], col[1], col[2], col[3]);
|
||||||
|
lodepng_palette_add(&state.info_raw, col[0], col[1], col[2], col[3]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
// Don't think we can have 16 bits with PNG
|
||||||
|
// TODO: don't change original image
|
||||||
|
image->convertTo32();
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
state.info_raw.colortype = LCT_RGB;
|
||||||
|
state.info_png.color.colortype = LCT_RGB;
|
||||||
|
state.encoder.auto_convert = 0;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
// already done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 error = lodepng::encode(raw, pixels, image->width, image->height, state);
|
||||||
|
if(error){
|
||||||
|
RWERROR((ERR_GENERAL, lodepng_error_text(error)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(pixels != image->pixels)
|
||||||
|
rwFree(pixels);
|
||||||
|
file.write8(&raw[0], raw.size());
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1565,34 +1565,6 @@ rasterUnlockPalette(Raster *raster)
|
||||||
raster->privateFlags &= ~(PS2LOCK_READ_PALETTE|PS2LOCK_WRITE_PALETTE);
|
raster->privateFlags &= ~(PS2LOCK_READ_PALETTE|PS2LOCK_WRITE_PALETTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
expandPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
|
||||||
{
|
|
||||||
int32 x, y;
|
|
||||||
for(y = 0; y < h; y++)
|
|
||||||
for(x = 0; x < w/2; x++){
|
|
||||||
dst[y*dststride + x*2 + 0] = src[y*srcstride + x] & 0xF;
|
|
||||||
dst[y*dststride + x*2 + 1] = src[y*srcstride + x] >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void
|
|
||||||
compressPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
|
||||||
{
|
|
||||||
int32 x, y;
|
|
||||||
for(y = 0; y < h; y++)
|
|
||||||
for(x = 0; x < w/2; x++)
|
|
||||||
dst[y*dststride + x] = src[y*srcstride + x*2 + 0] | src[y*srcstride + x*2 + 1] << 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
copyPSMT8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
|
||||||
{
|
|
||||||
int32 x, y;
|
|
||||||
for(y = 0; y < h; y++)
|
|
||||||
for(x = 0; x < w; x++)
|
|
||||||
dst[y*dststride + x] = src[y*srcstride + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Almost the same as d3d9 and gl3 function
|
// Almost the same as d3d9 and gl3 function
|
||||||
bool32
|
bool32
|
||||||
imageFindRasterFormat(Image *img, int32 type,
|
imageFindRasterFormat(Image *img, int32 type,
|
||||||
|
@ -1694,9 +1666,9 @@ rasterFromImage(Raster *raster, Image *image)
|
||||||
uint8 *src = image->pixels;
|
uint8 *src = image->pixels;
|
||||||
out = raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
|
out = raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
|
||||||
if(image->depth == 4){
|
if(image->depth == 4){
|
||||||
compressPSMT4(out, tw/2, src, image->stride, image->width, image->height);
|
compressPal4(out, tw/2, src, image->stride, image->width, image->height);
|
||||||
}else if(image->depth == 8){
|
}else if(image->depth == 8){
|
||||||
copyPSMT8(out, tw, src, image->stride, image->width, image->height);
|
copyPal8(out, tw, src, image->stride, image->width, image->height);
|
||||||
}else{
|
}else{
|
||||||
for(int32 y = 0; y < image->height; y++){
|
for(int32 y = 0; y < image->height; y++){
|
||||||
in = src;
|
in = src;
|
||||||
|
@ -1795,9 +1767,9 @@ rasterToImage(Raster *raster)
|
||||||
uint8 *dst = image->pixels;
|
uint8 *dst = image->pixels;
|
||||||
in = raster->lock(0, Raster::LOCKREAD);
|
in = raster->lock(0, Raster::LOCKREAD);
|
||||||
if(depth == 4){
|
if(depth == 4){
|
||||||
expandPSMT4(dst, image->stride, in, tw/2, raster->width, raster->height);
|
expandPal4(dst, image->stride, in, tw/2, raster->width, raster->height);
|
||||||
}else if(depth == 8){
|
}else if(depth == 8){
|
||||||
copyPSMT8(dst, image->stride, in, tw, raster->width, raster->height);
|
copyPal8(dst, image->stride, in, tw, raster->width, raster->height);
|
||||||
}else{
|
}else{
|
||||||
for(int32 y = 0; y < image->height; y++){
|
for(int32 y = 0; y < image->height; y++){
|
||||||
out = dst;
|
out = dst;
|
||||||
|
|
|
@ -223,9 +223,5 @@ Texture *readNativeTexture(Stream *stream);
|
||||||
void writeNativeTexture(Texture *tex, Stream *stream);
|
void writeNativeTexture(Texture *tex, Stream *stream);
|
||||||
uint32 getSizeNativeTexture(Texture *tex);
|
uint32 getSizeNativeTexture(Texture *tex);
|
||||||
|
|
||||||
void expandPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
|
||||||
void compressPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
|
||||||
void copyPSMT8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,4 +283,52 @@ conv_ABGR1555_from_ARGB1555(uint8 *out, uint8 *in)
|
||||||
out[0] = in[0]&0xE0 | r;
|
out[0] = in[0]&0xE0 | r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expandPal4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
||||||
|
{
|
||||||
|
int32 x, y;
|
||||||
|
for(y = 0; y < h; y++)
|
||||||
|
for(x = 0; x < w/2; x++){
|
||||||
|
dst[y*dststride + x*2 + 0] = src[y*srcstride + x] & 0xF;
|
||||||
|
dst[y*dststride + x*2 + 1] = src[y*srcstride + x] >> 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void
|
||||||
|
compressPal4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
||||||
|
{
|
||||||
|
int32 x, y;
|
||||||
|
for(y = 0; y < h; y++)
|
||||||
|
for(x = 0; x < w/2; x++)
|
||||||
|
dst[y*dststride + x] = src[y*srcstride + x*2 + 0] | src[y*srcstride + x*2 + 1] << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expandPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
||||||
|
{
|
||||||
|
int32 x, y;
|
||||||
|
for(y = 0; y < h; y++)
|
||||||
|
for(x = 0; x < w/2; x++){
|
||||||
|
dst[y*dststride + x*2 + 1] = src[y*srcstride + x] & 0xF;
|
||||||
|
dst[y*dststride + x*2 + 0] = src[y*srcstride + x] >> 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void
|
||||||
|
compressPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
||||||
|
{
|
||||||
|
int32 x, y;
|
||||||
|
for(y = 0; y < h; y++)
|
||||||
|
for(x = 0; x < w/2; x++)
|
||||||
|
dst[y*dststride + x] = src[y*srcstride + x*2 + 1] | src[y*srcstride + x*2 + 0] << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copyPal8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h)
|
||||||
|
{
|
||||||
|
int32 x, y;
|
||||||
|
for(y = 0; y < h; y++)
|
||||||
|
for(x = 0; x < w; x++)
|
||||||
|
dst[y*dststride + x] = src[y*srcstride + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,8 @@ Image *readTGA(const char *filename);
|
||||||
void writeTGA(Image *image, const char *filename);
|
void writeTGA(Image *image, const char *filename);
|
||||||
Image *readBMP(const char *filename);
|
Image *readBMP(const char *filename);
|
||||||
void writeBMP(Image *image, const char *filename);
|
void writeBMP(Image *image, const char *filename);
|
||||||
|
Image *readPNG(const char *filename);
|
||||||
|
void writePNG(Image *image, const char *filename);
|
||||||
|
|
||||||
enum { QUANTDEPTH = 8 };
|
enum { QUANTDEPTH = 8 };
|
||||||
|
|
||||||
|
@ -310,6 +312,13 @@ void conv_RGBA8888_from_ARGB1555(uint8 *out, uint8 *in);
|
||||||
void conv_ABGR1555_from_ARGB1555(uint8 *out, uint8 *in);
|
void conv_ABGR1555_from_ARGB1555(uint8 *out, uint8 *in);
|
||||||
inline void conv_ARGB1555_from_ABGR1555(uint8 *out, uint8 *in) { conv_ABGR1555_from_ARGB1555(out, in); }
|
inline void conv_ARGB1555_from_ABGR1555(uint8 *out, uint8 *in) { conv_ABGR1555_from_ARGB1555(out, in); }
|
||||||
|
|
||||||
|
void expandPal4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
||||||
|
void compressPal4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
||||||
|
void expandPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
||||||
|
void compressPal4_BE(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
||||||
|
void copyPal8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define IGNORERASTERIMP 0
|
#define IGNORERASTERIMP 0
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,6 @@
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
#include "rwengine.h"
|
#include "rwengine.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
/* srsly? */
|
|
||||||
#define strdup _strdup
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PLUGIN_ID 0
|
#define PLUGIN_ID 0
|
||||||
|
|
||||||
namespace rw {
|
namespace rw {
|
||||||
|
|
Loading…
Reference in New Issue