Adding JPEG/PNG file loading (PVRTC stub)

This commit is contained in:
Matt Tuttle
2014-06-30 23:17:41 -05:00
committed by Joshua Granick
parent 429f9bac86
commit 9f6debd95b
13 changed files with 340 additions and 146 deletions

View File

@@ -2,6 +2,7 @@ package lime.graphics;
import lime.utils.UInt8Array;
import lime.system.System;
#if js
import js.html.CanvasElement;
@@ -46,6 +47,22 @@ class Image {
}
public static function loadFromFile (path:String) {
#if flash
throw "Can not load image from file in Flash";
#elseif (cpp || neko)
var imageData = lime_load_image (path);
return (imageData == null ? null : new Image (new UInt8Array (imageData.data), imageData.width, imageData.height));
#end
}
public function forcePowerOfTwo () {
@@ -172,6 +189,13 @@ class Image {
}
#if (cpp || neko)
private static var lime_load_image = System.load("lime", "lime_load_image", 1);
#end
}

View File

@@ -27,6 +27,7 @@
<files id="lime">
<compilerflag value="-DLIME_SDL" if="LIME_SDL" />
<compilerflag value="-I/usr/local/include" />
<compilerflag value="-Iinclude" />
<file name="src/ExternalInterface.cpp" />
@@ -63,6 +64,9 @@
<file name="src/system/ios/System.mm" if="ios" />
<file name="src/app/UpdateEvent.cpp" />
<file name="src/graphics/ImageData.cpp" />
<file name="src/graphics/PVRTC.cpp" if="iphone" />
<file name="src/graphics/JPEG.cpp" />
<file name="src/graphics/PNG.cpp" />
<file name="src/graphics/RenderEvent.cpp" />
<file name="src/system/System.cpp" />
@@ -150,8 +154,11 @@
<vflag name="-framework" value="AppKit" />
<vflag name="-framework" value="OpenAL"/>
<lib name="-L/usr/local/lib" />
<lib name="/opt/local/lib/libgc.a" if="LIME_NEKO" />
<lib name="-lm" if="LIME_NEKO" />
<lib name="-lpng" />
<lib name="-ljpeg" />
</section>

View File

@@ -1,15 +1,28 @@
#ifndef LIME_GRAPHICS_IMAGE_DATA_H
#define LIME_GRAPHICS_IMAGE_DATA_H
#include <hx/CFFI.h>
#include <utils/ByteArray.h>
namespace lime {
struct ImageData {
class ImageData {
public:
int width;
int height;
unsigned char data;
ByteArray *data;
ImageData();
~ImageData();
value Value();
private:
value mValue;
};

View File

@@ -0,0 +1,23 @@
#ifndef LIME_GRAPHICS_JPEG_H
#define LIME_GRAPHICS_JPEG_H
namespace lime {
class ImageData;
class JPEG {
public:
static bool Decode (const char *path, ImageData *imageData);
};
}
#endif

View File

@@ -2,19 +2,16 @@
#define LIME_GRAPHICS_PNG_H
#include <graphics/ImageData.h>
#include <utils/ByteArray.h>
namespace lime {
class ImageData;
class PNG {
public:
static void Decode (ByteArray bytes, value imageData);
static bool Decode (const char *path, ImageData *imageData);
};

View File

@@ -0,0 +1,23 @@
#ifndef LIME_GRAPHICS_PVRTC_H
#define LIME_GRAPHICS_PVRTC_H
namespace lime {
class ImageData;
class PVRTC {
public:
static bool Decode (const char *path, ImageData *imageData);
};
}
#endif

View File

@@ -10,7 +10,9 @@
#include <hx/CFFI.h>
#include <app/Application.h>
#include <app/UpdateEvent.h>
#include <graphics/ImageData.h>
#include <graphics/PNG.h>
#include <graphics/JPEG.h>
#include <graphics/Renderer.h>
#include <graphics/RenderEvent.h>
#include <system/System.h>
@@ -49,13 +51,6 @@ namespace lime {
}
value lime_jpg_decode (value bytes, value imageData) {
return alloc_null ();
}
value lime_key_event_manager_register (value callback, value eventObject) {
KeyEvent::callback = new AutoGCRoot (callback);
@@ -110,10 +105,22 @@ namespace lime {
}
value lime_png_decode (value bytes, value imageData) {
value lime_load_image (value path) {
ByteArray byteArray (bytes);
PNG::Decode (bytes, imageData);
ImageData imageData;
const char *filePath = val_string (path);
if (PNG::Decode (filePath, &imageData)) {
return imageData.Value ();
}
if (JPEG::Decode(filePath, &imageData)) {
return imageData.Value ();
}
return alloc_null ();
@@ -190,13 +197,12 @@ namespace lime {
DEFINE_PRIM (lime_application_create, 1);
DEFINE_PRIM (lime_application_exec, 1);
DEFINE_PRIM (lime_application_get_ticks, 0);
DEFINE_PRIM (lime_jpg_decode, 2);
DEFINE_PRIM (lime_load_image, 1);
DEFINE_PRIM (lime_key_event_manager_register, 2);
DEFINE_PRIM (lime_lzma_encode, 1);
DEFINE_PRIM (lime_lzma_decode, 1);
DEFINE_PRIM (lime_mouse_event_manager_register, 2);
DEFINE_PRIM (lime_neko_execute, 1);
DEFINE_PRIM (lime_png_decode, 2);
DEFINE_PRIM (lime_renderer_create, 1);
DEFINE_PRIM (lime_renderer_flip, 1);
DEFINE_PRIM (lime_render_event_manager_register, 2);

View File

@@ -0,0 +1,38 @@
#include <graphics/ImageData.h>
namespace lime {
static int id_data;
static int id_height;
static int id_width;
static bool init = false;
ImageData::ImageData():width(0), height(0), data(0) { }
ImageData::~ImageData() {
delete data;
}
value ImageData::Value() {
if (!init) {
id_width = val_id ("width");
id_height = val_id ("height");
id_data = val_id ("data");
init = true;
}
mValue = alloc_empty_object ();
alloc_field (mValue, id_width, alloc_int (width));
alloc_field (mValue, id_height, alloc_int (height));
alloc_field (mValue, id_data, data->mValue);
return mValue;
}
}

View File

@@ -0,0 +1,71 @@
extern "C" {
#include <sys/types.h>
#include <stdio.h>
#include <jpeglib.h>
}
#include <graphics/ImageData.h>
#include <graphics/JPEG.h>
namespace lime {
extern FILE *OpenRead (const char *);
bool JPEG::Decode (const char *path, ImageData *imageData) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *file = OpenRead (path);
cinfo.err = jpeg_std_error (&jerr);
jpeg_create_decompress (&cinfo);
jpeg_stdio_src (&cinfo, file);
if (jpeg_read_header (&cinfo, TRUE) == JPEG_HEADER_OK) {
jpeg_start_decompress (&cinfo);
imageData->width = cinfo.output_width;
imageData->height = cinfo.output_height;
int components = cinfo.num_components;
imageData->data = new ByteArray (imageData->width * imageData->height * 4);
unsigned char *bytes = imageData->data->Bytes();
unsigned char *scanline = new unsigned char [imageData->width * imageData->height * components];
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines (&cinfo, &scanline, 1);
// convert 24-bit scanline to 32-bit
const unsigned char *line = scanline;
const unsigned char *const end = line + imageData->width * components;
while (line != end) {
*bytes++ = *line++;
*bytes++ = *line++;
*bytes++ = *line++;
*bytes++ = 0xFF;
}
}
delete[] scanline;
jpeg_finish_decompress (&cinfo);
}
fclose (file);
jpeg_destroy_decompress (&cinfo);
return true;
}
}

View File

@@ -1,143 +1,100 @@
extern "C" {
//#include <png.h>
#include <png.h>
#define PNG_SIG_SIZE 8
}
#include <hx/CFFI.h>
#include <graphics/ImageData.h>
#include <graphics/PNG.h>
#include <setjmp.h>
namespace lime {
static int id_data;
static int id_height;
static int id_width;
static bool init = false;
extern FILE *OpenRead (const char *);
/*static void user_error_fn (png_structp png_ptr, png_const_charp error_msg) {
longjmp (png_ptr->jmpbuf, 1);
}
static void user_warning_fn (png_structp png_ptr, png_const_charp warning_msg) { }
static void user_read_data_fn (png_structp png_ptr, png_bytep data, png_size_t length) {
png_voidp buffer = png_get_io_ptr (png_ptr);
((ReadBuf *)buffer)->Read (data, length);
}
void user_write_data (png_structp png_ptr, png_bytep data, png_size_t length) {
QuickVec<unsigned char> *buffer = (QuickVec<unsigned char> *)png_get_io_ptr (png_ptr);
buffer->append ((unsigned char *)data, (int)length);
}
void user_flush_data (png_structp png_ptr) { }*/
void PNG::Decode (ByteArray bytes, value imageData) {
/*if (!init) {
id_data = val_id ("data");
id_height = val_id ("height");
id_width = val_id ("width");
init = true;
}
bool PNG::Decode (const char *path, ImageData *imageData) {
unsigned char png_sig[PNG_SIG_SIZE];
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
int bit_depth, color_type;
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, user_error_fn, user_warning_fn);
FILE *file = OpenRead (path);
if (!file) return false;
if (png_ptr == NULL)
return;
// verify the PNG signature
fread(png_sig, PNG_SIG_SIZE, 1, file);
if (png_sig_cmp (png_sig, 0, PNG_SIG_SIZE)) {
info_ptr = png_create_info_struct (png_ptr);
fclose (file);
return false;
if (info_ptr == NULL) {
}
if ((png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) {
fclose (file);
return false;
}
if ((info_ptr = png_create_info_struct (png_ptr)) == NULL) {
png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return;
fclose (file);
return false;
}
unsigned char* bytes[width * height * 4];
RenderTarget target;
// sets the point which libpng will jump back to in the case of an error
if (setjmp (png_jmpbuf (png_ptr))) {
if (bytes) {
delete bytes;
}
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
return;
fclose (file);
return false;
}
ReadBuf buffer (inData, inDataLen);
//if (inFile) {
//png_init_io (png_ptr, inFile);
//} else {
png_set_read_fn (png_ptr, (void *)&buffer, user_read_data_fn);
//}
png_init_io (png_ptr, file);
png_set_sig_bytes (png_ptr, PNG_SIG_SIZE);
png_read_info (png_ptr, info_ptr);
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
bool has_alpha = (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS));
width = png_get_image_width (png_ptr, info_ptr);
height = png_get_image_height (png_ptr, info_ptr);
color_type = png_get_color_type (png_ptr, info_ptr);
bit_depth = png_get_bit_depth (png_ptr, info_ptr);
png_set_expand (png_ptr);
png_set_filler (png_ptr, 0xff, PNG_FILLER_AFTER);
png_set_palette_to_rgb (png_ptr);
png_set_gray_to_rgb (png_ptr);
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
png_set_bgr (png_ptr);
const unsigned int stride = width * 4;
imageData->width = width;
imageData->height = height;
imageData->data = new ByteArray (height * stride);
//result = new ImageData ();
//result.width = width;
//result.height = height;
//result.data = uint8[width * height * 4];
png_bytepp row_ptrs = new png_bytep[height];
unsigned char *bytes = imageData->data->Bytes();
png_read_png (png_ptr, (png_bytepp)&bytes);
for (size_t i = 0; i < height; i++) {
png_read_end (png_ptr, info_ptr);
row_ptrs[i] = bytes + i * stride;
}
png_read_image (png_ptr, row_ptrs);
png_read_end (png_ptr, NULL);
delete[] row_ptrs;
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
value object = (KeyEvent::eventObject ? KeyEvent::eventObject->get () : alloc_empty_object ());
alloc_field (object, id_code, alloc_int (event->code));
alloc_field (object, id_type, alloc_int (event->type));
alloc_field (imageData, id_width, alloc_int (width));
alloc_field (imageData, id_height, alloc_int (height));
alloc_field (imageData, id_data, alloc_int (bytes));
return result;*/
return true;
}

View File

@@ -0,0 +1,58 @@
extern "C" {
}
#include <graphics/ImageData.h>
#include <graphics/PVRTC.h>
typedef struct _PVRTexHeader {
uint32_t headerLength;
uint32_t height;
uint32_t width;
uint32_t numMipmaps;
uint32_t flags;
uint32_t dataLength;
uint32_t bpp;
uint32_t bitmaskRed;
uint32_t bitmaskGreen;
uint32_t bitmaskBlue;
uint32_t bitmaskAlpha;
uint32_t pvrTag;
uint32_t numSurfs;
} PVRTexHeader;
static char gPVRTexIdentifier[5] = "PVR!";
namespace lime {
extern FILE *OpenRead (const char *);
bool PVRTC::Decode (const char *path, ImageData *imageData) {
PVRTexHeader header;
FILE *file = OpenRead (path);
fread (&header, sizeof(header), 1, file);
if (gPVRTexIdentifier[0] != ((header.pvrTag >> 0) & 0xFF) ||
gPVRTexIdentifier[1] != ((header.pvrTag >> 8) & 0xFF) ||
gPVRTexIdentifier[2] != ((header.pvrTag >> 16) & 0xFF) ||
gPVRTexIdentifier[3] != ((header.pvrTag >> 24) & 0xFF)) {
return false;
}
return false;
}
}

View File

@@ -48,6 +48,9 @@ namespace lime {
void ByteArray::Resize(int inSize)
{
if (mValue == 0)
mValue = val_call1(gByteArrayCreate->get(), alloc_int(inSize) );
else
val_call2(gByteArrayResize->get(), mValue, alloc_int(inSize) );
}

View File

@@ -70,7 +70,11 @@ class DefaultAssetLibrary extends AssetLibrary {
if (Sys.args ().indexOf ("-livereload") > -1) {
#if mac
var path = FileSystem.fullPath ("../Resources/manifest");
#else
var path = FileSystem.fullPath ("manifest");
#end
lastModified = FileSystem.stat (path).mtime.getTime ();
timer = new Timer (2000);
@@ -211,39 +215,9 @@ class DefaultAssetLibrary extends AssetLibrary {
#else
// TODO: Implement in native backend
var bytes = getBytes (id);
var byteInput = new haxe.io.BytesInput (bytes, 0, bytes.length);
var png = new format.png.Reader (byteInput).read ();
var data = format.png.Tools.extract32 (png);
var header = format.png.Tools.getHeader (png);
var imageWidth = header.width;
var imageHeight = header.height;
var imageData = new UInt8Array (ByteArray.fromBytes (data));
var imageLength = imageWidth * imageHeight;
var b, g, r, a;
for (i in 0...imageLength) {
b = imageData[i * 4];
g = imageData[i * 4 + 1];
r = imageData[i * 4 + 2];
a = imageData[i * 4 + 3];
imageData[i * 4] = r;
imageData[i * 4 + 1] = g;
imageData[i * 4 + 2] = b;
imageData[i * 4 + 3] = a;
}
return new Image (imageData, imageWidth, imageHeight);
//if (className.exists(id)) return cast (Type.createInstance (className.get (id), []), BitmapData);
//else return BitmapData.load (path.get (id));
var image = Image.loadFromFile (path.get (id));
if (image == null) return null;
return new Image(image.bytes, image.width, image.height);
#end