1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-01-17 21:09:00 +01:00

#15 add PNG support for Android obb's title and loading screens, add mp3 audio support

This commit is contained in:
XProger 2017-12-11 11:04:37 +03:00
parent 8219740b9f
commit a1141c4939
8 changed files with 254 additions and 11 deletions

Binary file not shown.

View File

@ -1 +1 @@
- track_XX.ogg, track_XX.ogg, track_XX.wav for *_EN, *_DE, *_FR, *_IT, *_JA, *_RU
- track_XX.ogg, track_XX.mp3, track_XX.wav for *_EN, *_DE, *_FR, *_IT, *_JA, *_RU

View File

@ -1,2 +1,2 @@
- track_XX.ogg, track_XX.ogg, track_XX.wav for *_EN, *_DE, *_FR, *_IT, *_JA, *_RU
- track_XX.ogg, track_XX.mp3, track_XX.wav for *_EN, *_DE, *_FR, *_IT, *_JA, *_RU
- MAIN.SFX

View File

@ -1,6 +1,10 @@
#ifndef H_CORE
#define H_CORE
#ifndef __EMSCRIPTEN__
#define USE_INFLATE
#endif
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
@ -137,6 +141,10 @@
#define glProgramBinary(...)
#endif
#ifdef USE_INFLATE
#include "libs/tinf/tinf.h"
#endif
#include "utils.h"
enum ControlKey { cLeft, cRight, cUp, cDown, cJump, cWalk, cAction, cWeapon, cLook, cStepLeft, cStepRight, cRoll, cInventory, cMAX };
@ -540,6 +548,10 @@ namespace Core {
}
void init() {
#ifdef USE_INFLATE
tinf_init();
#endif
Input::init();
#ifdef ANDROID
void *libGL = dlopen("libGLESv2.so", RTLD_LAZY);

View File

@ -494,7 +494,7 @@ namespace TR {
if (Stream::existsContent("DATA/GYM.SAT"))
return VER_TR1_SEGA;
if (Stream::existsContent("data/ASSAULT.TR2") || Stream::existsContent("data/assault.TR2"))
if (Stream::existsContent("data/ASSAULT.TR2") || Stream::existsContent("assault.TR2"))
return VER_TR2_PC;
if (Stream::existsContent("DATA/ASSAULT.PSX"))
return VER_TR2_PSX;
@ -630,6 +630,7 @@ namespace TR {
callback(Sound::openCDAudioMP3("audio/cdaudio.dat", "audio/cdaudio.mp3", track), userData);
return;
}
sprintf(title, "track_%02d", track);
if (!checkTrack("", title) && !checkTrack("audio/2/", title) && !checkTrack("audio/", title)) {
callback(NULL, userData);
return;
@ -674,6 +675,7 @@ namespace TR {
switch (id) {
case LVL_TR1_TITLE :
if (Stream::existsContent("DATA/TITLEH.PCX")) return "DATA/TITLEH.PCX";
if (Stream::existsContent("TITLEH.png")) return "TITLEH.png";
break;
default : ;
}
@ -683,6 +685,7 @@ namespace TR {
case LVL_TR2_TITLE :
if (Stream::existsContent("data/TITLE.PCX")) return "data/TITLE.PCX";
if (Stream::existsContent("pix/title.pcx")) return "pix/title.pcx";
if (Stream::existsContent("TITLE.png")) return "TITLE.png";
break;
default : ;
}

View File

@ -3,11 +3,10 @@
#define DECODE_VAG
#define DECODE_ADPCM
//#define DECODE_MP3
#define DECODE_OGG
#ifdef __EMSCRIPTEN__ // TODO: http streaming
#undef DECODE_MP3
#ifndef __EMSCRIPTEN
#define DECODE_MP3
#endif
#include "utils.h"
@ -36,7 +35,7 @@ namespace Sound {
#define MAX_FDN 16
#define MAX_DELAY 1024
static const short FDN[MAX_FDN] = {281,331,373,419,461,503,547,593,641,683,727,769,811,853,907,953};
static const int16 FDN[MAX_FDN] = { 281, 331, 373, 419, 461, 503, 547, 593, 641, 683, 727, 769, 811, 853, 907, 953 };
struct Delay {
int index;

View File

@ -281,11 +281,224 @@ struct Texture {
return tex;
}
#ifdef USE_INFLATE
static int pngPaeth(int a, int b, int c) {
int p = a + b - c;
int pa = abs(p - a);
int pb = abs(p - b);
int pc = abs(p - c);
if (pa <= pb && pa <= pc)
return a;
if (pb <= pc)
return b;
return c;
}
static void pngFilter(int id, int BPP, int BPL, const uint8 *src, uint8 *dst, const uint8 *prev) {
enum { NONE, SUB, UP, AVRG, PAETH };
switch (id) {
case NONE :
memcpy(dst, src, BPL);
break;
case SUB :
memcpy(dst, src, BPP);
for (int i = BPP; i < BPL; i++)
dst[i] = src[i] + dst[i - BPP];
break;
case UP :
for (int i = 0; i < BPL; i++)
dst[i] = src[i] + prev[i];
break;
case AVRG :
for (int i = 0; i < BPP; i++)
dst[i] = src[i] + (prev[i] >> 1);
for (int i = BPP; i < BPL; i++)
dst[i] = src[i] + ((dst[i - BPP] + prev[i]) >> 1);
break;
case PAETH :
for (int i = 0; i < BPP; i++)
dst[i] = src[i] + pngPaeth(0, prev[i], 0);
for (int i = BPP; i < BPL; i++)
dst[i] = src[i] + pngPaeth(dst[i - BPP], prev[i], prev[i - BPP]);
break;
};
}
static Texture* LoadPNG(Stream &stream) {
stream.seek(8);
uint8 bits, colorType, interlace;
int BPP, BPL;
uint32 width, height;
uint8 palette[256 * 3];
uint8 trans[256];
uint8 *cdata = NULL;
int offset = 0;
// read chunks
while (stream.pos < stream.size) {
uint32 chunkSize, chunkName;
chunkSize = swap32(stream.read(chunkSize));
stream.read(chunkName);
if (chunkName == FOURCC("IHDR")) { // Image Header
width = swap32(stream.read(width));
height = swap32(stream.read(height));
stream.read(bits);
stream.read(colorType);
stream.seek(2);
stream.read(interlace);
ASSERT(interlace == 0);
ASSERT(bits <= 8);
int components;
switch (colorType) {
case 2 : components = 3; break;
case 4 : components = 2; break;
case 6 : components = 4; break;
default : components = 1;
}
BPP = (bits + 7) / 8 * components;
BPL = (width * bits + 7) / 8 * components;
cdata = new uint8[stream.size];
memset(trans, 0xFF, sizeof(trans));
} else if (chunkName == FOURCC("PLTE")) { // Palette
stream.raw(palette, chunkSize);
} else if (chunkName == FOURCC("tRNS")) { // Transparency info
stream.raw(trans, chunkSize);
} else if (chunkName == FOURCC("IDAT")) { // Compressed image data part
ASSERT(cdata);
stream.raw(cdata + offset, chunkSize);
offset += chunkSize;
} else if (chunkName == FOURCC("IEND")) {
break;
} else
stream.seek(chunkSize);
stream.seek(4); // skip chunk CRC
}
ASSERT(cdata);
uint8 *buffer = new uint8[(BPL + 1) * height];
uint32 cbytes;
tinf_uncompress(buffer, &cbytes, cdata + 2, 0);
delete[] cdata;
ASSERT(cbytes > 0);
// apply line filters to image
uint8 *data = new uint8[BPL * height];
uint8 *prev = new uint8[BPL];
memset(prev, 0, BPL);
for (uint32 i = 0; i < height; i++) {
pngFilter(buffer[(BPL + 1) * i], BPP, BPL, &buffer[(BPL + 1) * i + 1], &data[BPL * i], prev);
if (i == 0)
delete[] prev;
prev = &data[BPL * i];
}
delete[] buffer;
// convert to 32-bit image
uint8 *data32 = new uint8[width * height * 4];
uint8 *src = data;
uint8 *dst = data32;
switch (colorType) {
case 0 : // grayscale
for (uint32 i = 0; i < width * height; i += 4, dst += 4, src++) {
dst[0] =
dst[1] =
dst[2] = src[0];
dst[3] = trans[0];
}
break;
case 2 : // RGB
for (uint32 i = 0; i < width * height; i++, dst += 4, src += 3) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = trans[0];
}
break;
case 3 : // indexed color with alpha
for (uint32 j = 0, palWord = 0; j < height; j++) {
for (uint32 i = 0, curBit = 8; i < width; i++) {
if (curBit > 7) {
curBit -= 8;
palWord = *src++;
if (i < width - 1)
palWord |= *src << 8;
}
uint16 palIdx = (palWord >> (8 - bits - curBit)) & ~(0xFFFF << bits);
curBit += bits;
dst[0] = palette[palIdx * 3 + 0];
dst[1] = palette[palIdx * 3 + 1];
dst[2] = palette[palIdx * 3 + 2];
dst[3] = trans[palIdx];
dst += 4;
}
}
break;
case 4 : // grayscale with alpha
for (uint32 i = 0; i < width * height; i++, dst += 4, src += 2) {
dst[0] =
dst[1] =
dst[2] = src[0];
dst[3] = src[1];
}
break;
case 6 : // RGBA
memcpy(dst, src, width * height * 4);
break;
}
// convert to POT size if NPOT isn't supported
uint32 dw = Core::support.texNPOT ? width : nextPow2(width);
uint32 dh = Core::support.texNPOT ? height : nextPow2(height);
if (dw != width || dh != height) {
uint8 *dataPOT = new uint8[dw * dh * 4];
uint32 *dst = (uint32*)dataPOT;
uint32 *src = (uint32*)data32;
for (uint32 j = 0; j < dh; j++)
for (uint32 i = 0; i < dw; i++)
*dst++ = (i < width && j < height) ? *src++ : 0xFF000000;
width = dw;
height = dh;
delete[] data32;
data32 = dataPOT;
}
Texture *tex = new Texture(width, height, Texture::RGBA, false, data32);
delete[] data32;
delete[] data;
return tex;
}
#endif
static Texture* Load(Stream &stream) {
uint16 magic;
uint32 magic;
stream.read(magic);
stream.seek(-int(sizeof(magic)));
if (magic == 0x4D42)
#ifdef USE_INFLATE
if (magic == 0x474E5089)
return LoadPNG(stream);
#endif
if ((magic & 0xFFFF) == 0x4D42)
return LoadBMP(stream);
return LoadPCX(stream);
}

View File

@ -97,6 +97,14 @@ inline void swap(T &a, T &b) {
b = tmp;
}
inline uint16 swap16(uint16 x) {
return ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8);
}
inline uint32 swap32(uint32 x) {
return ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24);
}
float clampAngle(float a) {
return a < -PI ? a + PI2 : (a >= PI ? a - PI2 : a);
}
@ -1010,9 +1018,11 @@ struct Stream {
char *name;
int size, pos;
Stream(const void *data, int size) : callback(NULL), userData(NULL), f(NULL), data((char*)data), name(NULL), size(size), pos(0) {}
enum Endian { LITTLE_ENDIAN, BIG_ENDIAN } endian;
Stream(const char *name, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), data(NULL), name(NULL), size(-1), pos(0) {
Stream(const void *data, int size) : callback(NULL), userData(NULL), f(NULL), data((char*)data), name(NULL), size(size), pos(0), endian(LITTLE_ENDIAN) {}
Stream(const char *name, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), data(NULL), name(NULL), size(-1), pos(0), endian(LITTLE_ENDIAN) {
if (contentDir[0] && (!cacheDir[0] || !strstr(name, cacheDir))) {
char path[255];
path[0] = 0;
@ -1098,6 +1108,12 @@ struct Stream {
template <typename T>
inline T& read(T &x) {
raw(&x, sizeof(x));
/*
if (endian == BIG_ENDIAN) {
if (sizeof(T) == 2) x = T(swap16(x));
if (sizeof(T) == 4) x = T(swap32(x));
}
*/
return x;
}