1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-06 13:16:52 +02:00

PSV fast IDCT and minor changes

This commit is contained in:
XProger
2021-03-22 04:59:35 +03:00
parent 4fff11b74e
commit d5e46a9645
11 changed files with 664 additions and 326 deletions

View File

@@ -132,6 +132,8 @@
#define _GAPI_GXM 1 #define _GAPI_GXM 1
#undef OS_PTHREAD_MT #undef OS_PTHREAD_MT
//#define USE_LIBVORBIS // TODO crash
#elif __SWITCH__ #elif __SWITCH__
#define _OS_SWITCH 1 #define _OS_SWITCH 1
#define _GAPI_GL 1 #define _GAPI_GL 1
@@ -260,9 +262,9 @@ namespace Core {
void *obj; void *obj;
Mutex() { obj = osMutexInit(); } Mutex() { obj = osMutexInit(); }
~Mutex() { osMutexFree(obj); } ~Mutex() { if (obj) osMutexFree(obj); }
void lock() { osMutexLock(obj); } void lock() { if (obj) osMutexLock(obj); }
void unlock() { osMutexUnlock(obj); } void unlock() { if (obj) osMutexUnlock(obj); }
}; };
struct Lock { struct Lock {
@@ -1009,7 +1011,7 @@ namespace Core {
#ifdef _OS_PSV #ifdef _OS_PSV
settings.detail.setFilter (Core::Settings::HIGH); settings.detail.setFilter (Core::Settings::HIGH);
settings.detail.setLighting (Core::Settings::LOW); settings.detail.setLighting (Core::Settings::LOW);
settings.detail.setShadows (Core::Settings::LOW); settings.detail.setShadows (Core::Settings::MEDIUM);
settings.detail.setWater (Core::Settings::MEDIUM); settings.detail.setWater (Core::Settings::MEDIUM);
#endif #endif

View File

@@ -548,6 +548,9 @@ namespace Debug {
for (int i = 0; i < level.roomsCount; i++) for (int i = 0; i < level.roomsCount; i++)
for (int j = 0; j < level.rooms[i].lightsCount; j++) { for (int j = 0; j < level.rooms[i].lightsCount; j++) {
TR::Room::Light &l = level.rooms[i].lights[j]; TR::Room::Light &l = level.rooms[i].lights[j];
if (!level.rooms[i].flags.visible) continue;
vec3 p = vec3(float(l.x), float(l.y), float(l.z)); vec3 p = vec3(float(l.x), float(l.y), float(l.z));
vec4 color = vec4(l.color.r, l.color.g, l.color.b, 255) * (1.0f / 255.0f); vec4 color = vec4(l.color.r, l.color.g, l.color.b, 255) * (1.0f / 255.0f);

View File

@@ -767,7 +767,6 @@ namespace GAPI {
bool isCube = (opt & OPT_CUBEMAP) != 0; bool isCube = (opt & OPT_CUBEMAP) != 0;
bool isTarget = (opt & OPT_TARGET) != 0; bool isTarget = (opt & OPT_TARGET) != 0;
bool isDynamic = (opt & OPT_DYNAMIC) != 0; bool isDynamic = (opt & OPT_DYNAMIC) != 0;
bool isShadow = fmt == FMT_SHADOW;
bool isTiled = isTarget; bool isTiled = isTarget;
bool isSwizzled = !isDynamic && !isTiled && filter; bool isSwizzled = !isDynamic && !isTiled && filter;
@@ -814,7 +813,7 @@ namespace GAPI {
size *= 6; size *= 6;
} }
SceGxmMemoryAttribFlags flags = (isTarget || mipCount > 1) ? SCE_GXM_MEMORY_ATTRIB_RW : SCE_GXM_MEMORY_ATTRIB_READ; SceGxmMemoryAttribFlags flags = (isTarget || isDynamic || mipCount > 1) ? SCE_GXM_MEMORY_ATTRIB_RW : SCE_GXM_MEMORY_ATTRIB_READ;
this->data = (uint8*)Context::allocGPU(SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, size, flags, &uid); this->data = (uint8*)Context::allocGPU(SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, size, flags, &uid);
if (data && this->data) { if (data && this->data) {
@@ -858,7 +857,7 @@ namespace GAPI {
if (opt & OPT_REPEAT) { if (opt & OPT_REPEAT) {
addrMode = SCE_GXM_TEXTURE_ADDR_REPEAT; addrMode = SCE_GXM_TEXTURE_ADDR_REPEAT;
} else { } else {
addrMode = (isShadow && support.texBorder) ? SCE_GXM_TEXTURE_ADDR_CLAMP_FULL_BORDER : SCE_GXM_TEXTURE_ADDR_CLAMP; addrMode = SCE_GXM_TEXTURE_ADDR_CLAMP;
} }
sceGxmTextureSetUAddrMode(&ID, addrMode); sceGxmTextureSetUAddrMode(&ID, addrMode);
@@ -1365,6 +1364,7 @@ namespace GAPI {
} }
void clear(bool color, bool depth) { void clear(bool color, bool depth) {
// TODO save and restore states
int oColorMask = colorMask; int oColorMask = colorMask;
int oBlendMode = blendMode; int oBlendMode = blendMode;
bool oDepthTest = depthTest; bool oDepthTest = depthTest;

View File

@@ -2304,7 +2304,7 @@ struct Lara : Character {
if (stand == STAND_UNDERWATER || stand == STAND_ONWATER) if (stand == STAND_UNDERWATER || stand == STAND_ONWATER)
return stand; return stand;
if (stand == STAND_AIR) { if (stand == STAND_AIR) {
if (velocity.y > 0.0f && pos.y - waterLevel > 300.0) { if (velocity.y > 0.0f && pos.y - waterLevel > 300.0f) {
stopScreaming(); stopScreaming();
return STAND_UNDERWATER; return STAND_UNDERWATER;
} }
@@ -2326,7 +2326,7 @@ struct Lara : Character {
return STAND_AIR; return STAND_AIR;
if (stand == STAND_AIR) { if (stand == STAND_AIR) {
if (velocity.y > 0.0f && pos.y - waterLevel > 300.0) { if (velocity.y > 0.0f && pos.y - waterLevel > 300.0f) {
waterSplash(); waterSplash();
pos.y = waterLevel + waterDepth; pos.y = waterLevel + waterDepth;
game->playSound(TR::SND_WATER_SPLASH, pos, Sound::PAN); game->playSound(TR::SND_WATER_SPLASH, pos, Sound::PAN);

View File

@@ -221,6 +221,8 @@ int checkLanguage()
return str - STR_LANG_EN; return str - STR_LANG_EN;
} }
extern "C" int32_t sceKernelChangeThreadVfpException(int32_t clear, int32_t set);
int main() int main()
{ {
psvDebugScreenInit(); psvDebugScreenInit();
@@ -236,6 +238,8 @@ int main()
sceAppUtilInit(&initParam, &bootParam); sceAppUtilInit(&initParam, &bootParam);
} }
sceKernelChangeThreadVfpException(0x0800009FU, 0x0);
cacheDir[0] = saveDir[0] = contentDir[0] = 0; cacheDir[0] = saveDir[0] = contentDir[0] = 0;
strcpy(cacheDir, "ux0:data/OpenLara/"); strcpy(cacheDir, "ux0:data/OpenLara/");
strcpy(saveDir, "ux0:data/OpenLara/"); strcpy(saveDir, "ux0:data/OpenLara/");
@@ -265,6 +269,8 @@ int main()
Game::render(); Game::render();
GAPI::present(); GAPI::present();
sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DEFAULT);
} }
sndFree(); sndFree();

View File

@@ -71,7 +71,7 @@ struct VS_INPUT {
#define SAMPLE_2D_POINT_WRAP(T,uv) T.Sample(smpPointWrap, uv) #define SAMPLE_2D_POINT_WRAP(T,uv) T.Sample(smpPointWrap, uv)
#define SAMPLE_2D_LINEAR(T,uv) T.Sample(smpLinear, uv) #define SAMPLE_2D_LINEAR(T,uv) T.Sample(smpLinear, uv)
#define SAMPLE_2D_LINEAR_WRAP(T,uv) T.Sample(smpLinearWrap, uv) #define SAMPLE_2D_LINEAR_WRAP(T,uv) T.Sample(smpLinearWrap, uv)
#define SAMPLE_2D_CMP(T,uv) T.SampleCmp(smpCmp, uv.xy, uv.z) #define SAMPLE_SHADOW(T,uv) T.SampleCmpLevelZero(smpCmp, uv.xy/uv.w, uv.z/uv.w)
#define SAMPLE_2D_LOD0(T,uv) T.SampleLevel(smpLinear, uv, 0) #define SAMPLE_2D_LOD0(T,uv) T.SampleLevel(smpLinear, uv, 0)
#define SAMPLE_3D(T,uv) T.SampleLevel(smpLinearWrap, uv, 0) #define SAMPLE_3D(T,uv) T.SampleLevel(smpLinearWrap, uv, 0)
#define SAMPLE_CUBE(T,uv) T.Sample(smpLinear, uv) #define SAMPLE_CUBE(T,uv) T.Sample(smpLinear, uv)
@@ -95,7 +95,13 @@ struct VS_INPUT {
#define SAMPLE_2D_LINEAR(T,uv) tex2D(T, uv) #define SAMPLE_2D_LINEAR(T,uv) tex2D(T, uv)
#define SAMPLE_2D_LINEAR_WRAP(T,uv) tex2D(T, uv) #define SAMPLE_2D_LINEAR_WRAP(T,uv) tex2D(T, uv)
#define SAMPLE_2D_LOD0(T,uv) tex2Dlod(T, float4(uv.xy, 0, 0)) #define SAMPLE_2D_LOD0(T,uv) tex2Dlod(T, float4(uv.xy, 0, 0))
#define SAMPLE_2D_CMP(T,uv) ((tex2D(T, uv.xy) => uv.z) ? 1 : 0)
#if defined(_GAPI_GXM)
#define SAMPLE_SHADOW(T,uv) f1tex2Dproj(T, uv)
#else
#define SAMPLE_SHADOW(T,uv) ((tex2D(T, uv.xy/uv.w) => uv.z/uv.w) ? 1 : 0)
#endif
#define SAMPLE_3D(T,uv) tex3D(T, uv) #define SAMPLE_3D(T,uv) tex3D(T, uv)
#define SAMPLE_CUBE(T,uv) texCUBE(T, uv) #define SAMPLE_CUBE(T,uv) texCUBE(T, uv)
@@ -122,7 +128,7 @@ float4 uContacts[MAX_CONTACTS] : register( c98 );
// options for compose, shadow, ambient passes // options for compose, shadow, ambient passes
#ifdef _GAPI_GXM #ifdef _GAPI_GXM
//#define OPT_AMBIENT //#define OPT_AMBIENT
//#define OPT_SHADOW #define OPT_SHADOW
//#define OPT_CONTACT //#define OPT_CONTACT
//#define OPT_CAUSTICS //#define OPT_CAUSTICS
#else #else
@@ -220,16 +226,10 @@ float getShadowValue(float3 lightVec, float4 lightProj) {
*/ */
float factor = step(0.0, lightProj.w); //float((sMin > 0.0f) && (sMax < lightProj.w)); // float factor = step(0.0, lightProj.w); //float((sMin > 0.0f) && (sMax < lightProj.w)); //
lightProj.xyz *= factor; lightProj.xyz *= factor;
lightProj.xyz /= lightProj.w; lightProj.z -= SHADOW_CONST_BIAS * SHADOW_TEXEL * lightProj.w;
lightProj.z -= SHADOW_CONST_BIAS * SHADOW_TEXEL;
#ifdef _GAPI_GXM
float rShadow = f1tex2Dproj(sShadow, lightProj); float rShadow = SAMPLE_SHADOW(sShadow, lightProj);
#elif _GAPI_D3D11
float rShadow = sShadow.SampleCmpLevelZero(smpCmp, lightProj.xy, lightProj.z);
#else
float rShadow = 1.0;
#endif
float fade = saturate(dot(lightVec, lightVec)); float fade = saturate(dot(lightVec, lightVec));
return rShadow + (1.0 - rShadow) * fade; return rShadow + (1.0 - rShadow) * fade;

View File

@@ -306,18 +306,19 @@ namespace Sound {
}; };
#ifdef DECODE_ADPCM #ifdef DECODE_ADPCM
struct ADPCM : Decoder { // https://wiki.multimedia.cx/?title=Microsoft_ADPCM struct ADPCM : Decoder // https://wiki.multimedia.cx/?title=Microsoft_ADPCM
{
int size, block; int size, block;
ADPCM(Stream *stream, int channels, int freq, int size, int block) : Decoder(stream, channels, freq), size(size), block(block) {} struct Channel
{
struct Channel {
int16 c1, c2; int16 c1, c2;
int16 delta; int16 delta;
int16 sample1; int16 sample1;
int16 sample2; int16 sample2;
int predicate(uint8 nibble) { int predicate(uint8 nibble)
{
static const int table[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; static const int table[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 };
int8 ns = nibble; int8 ns = nibble;
@@ -332,15 +333,23 @@ namespace Sound {
} }
} channel[2]; } channel[2];
virtual int decode(Frame *frames, int count) { ADPCM(Stream *stream, int channels, int freq, int size, int block) : Decoder(stream, channels, freq), size(size), block(block)
{
memset(channel, 0, sizeof(channel));
}
virtual int decode(Frame *frames, int count)
{
static const int coeff1[] = { 256, 512, 0, 192, 240, 460, 392 }; static const int coeff1[] = { 256, 512, 0, 192, 240, 460, 392 };
static const int coeff2[] = { 0, -256, 0, 64, 0, -208, -232 }; static const int coeff2[] = { 0, -256, 0, 64, 0, -208, -232 };
int seek = stream->pos - offset; int seek = stream->pos - offset;
if (seek >= size) return 0; if (seek >= size) return 0;
if (seek % block == 0) { if (seek % block == 0)
for (int i = 0; i < channels; i++) { {
for (int i = 0; i < channels; i++)
{
uint8 index; uint8 index;
stream->read(index); stream->read(index);
channel[i].c1 = coeff1[index]; channel[i].c1 = coeff1[index];
@@ -350,8 +359,10 @@ namespace Sound {
for (int i = 0; i < channels; i++) stream->read(channel[i].sample1); for (int i = 0; i < channels; i++) stream->read(channel[i].sample1);
for (int i = 0; i < channels; i++) stream->read(channel[i].sample2); for (int i = 0; i < channels; i++) stream->read(channel[i].sample2);
if (channels == 1) { if (channels == 1)
if (freq == 22050) { {
if (freq == 22050)
{
ASSERT(count >= 4); ASSERT(count >= 4);
frames[0].L = frames[0].R = frames[0].L = frames[0].R =
frames[1].L = frames[1].R = channel[0].sample2; frames[1].L = frames[1].R = channel[0].sample2;
@@ -378,8 +389,10 @@ namespace Sound {
stream->read(value); stream->read(value);
uint8 n1 = value >> 4, n2 = value & 0xF; uint8 n1 = value >> 4, n2 = value & 0xF;
if (channels == 1) { if (channels == 1)
if (freq == 22050) { {
if (freq == 22050)
{
ASSERT(count >= 4); ASSERT(count >= 4);
frames[0].L = frames[0].R = frames[0].L = frames[0].R =
frames[1].L = frames[1].R = channel[0].predicate(n1); frames[1].L = frames[1].R = channel[0].predicate(n1);
@@ -460,7 +473,7 @@ namespace Sound {
stream->read(n); stream->read(n);
int a = getSample(n >> 4, state[0]); int a = getSample(n >> 4, state[0]);
int b = getSample(n & 0x0F, state[1 % channels]); int b = getSample(n, state[1 % channels]);
Frame frame; Frame frame;
if (channels == 2) { if (channels == 2) {
@@ -484,7 +497,9 @@ namespace Sound {
Frame buffer[28 * 4]; Frame buffer[28 * 4];
int bufferSize; int bufferSize;
VAG(Stream *stream) : Decoder(stream, 1, 11025), s1(0), s2(0), bufferSize(0) {} VAG(Stream *stream) : Decoder(stream, 1, 11025), s1(0), s2(0), bufferSize(0) {
memset(buffer, 0, sizeof(buffer));
}
void predicate(short value) { void predicate(short value) {
int s = (s1 * SPU_POS[pred] + s2 * SPU_NEG[pred]) >> 6; int s = (s1 * SPU_POS[pred] + s2 * SPU_NEG[pred]) >> 6;
@@ -551,29 +566,34 @@ namespace Sound {
#ifdef DECODE_XA #ifdef DECODE_XA
// http://problemkaputt.de/psx-spx.htm#cdromxaaudioadpcmcompression // http://problemkaputt.de/psx-spx.htm#cdromxaaudioadpcmcompression
struct XA : Decoder { struct XA : Decoder
uint8 pred, shift, flags; {
int s1, s2; typedef bool (Callback)(void* userData);
Frame buffer[18 * 112]; struct Group
int pos; {
struct Group {
uint8 params[16]; uint8 params[16];
uint8 data[112]; uint8 data[112];
} groups[18]; };
Frame buffer[18 * 112];
Frame prevFrames[2]; Frame prevFrames[2];
Frame lerpFrames[32]; Frame lerpFrames[32];
uint32 lerpPos;
XA(Stream *stream) : Decoder(stream, 1, 11025), s1(0), s2(0), pos(COUNT(buffer)), lerpPos(0) { int32 pos;
int32 lerpPos;
int32 frameIndex;
void* userData;
Callback* nextSectorCallback;
XA(void* userData, Callback* nextSectorCallback) : Decoder(NULL, 1, 11025), pos(COUNT(buffer)), lerpPos(0), frameIndex(7), userData(userData), nextSectorCallback(nextSectorCallback)
{
memset(prevFrames, 0, sizeof(prevFrames)); memset(prevFrames, 0, sizeof(prevFrames));
memset(lerpFrames, 0, sizeof(lerpFrames)); memset(lerpFrames, 0, sizeof(lerpFrames));
} }
void decode28(Group &group, int block, int channel) { void decode28(Group &group, int block, int channel)
{
int16 *dst = channel ? &buffer[pos].R : &buffer[pos].L; int16 *dst = channel ? &buffer[pos].R : &buffer[pos].L;
int16 &old = channel ? prevFrames[0].R : prevFrames[0].L; int16 &old = channel ? prevFrames[0].R : prevFrames[0].L;
int16 &older = channel ? prevFrames[1].R : prevFrames[1].L; int16 &older = channel ? prevFrames[1].R : prevFrames[1].L;
@@ -584,10 +604,10 @@ namespace Sound {
int f0 = SPU_POS[filter]; int f0 = SPU_POS[filter];
int f1 = SPU_NEG[filter]; int f1 = SPU_NEG[filter];
for (int i = 0; i < 28; i++) { for (int i = 0; i < 28; i++)
{
int t = (group.data[block + i * 4] >> (channel * 4)) & 0x0F; int t = (group.data[block + i * 4] >> (channel * 4)) & 0x0F;
if (t & 8) if (t & 8) t -= 16;
t -= 16;
int s = (t << shift) + ((old * f0 + older * f1 + 32) / 64); int s = (t << shift) + ((old * f0 + older * f1 + 32) / 64);
s = clamp(s, -32768, 32767); s = clamp(s, -32768, 32767);
older = old; older = old;
@@ -597,30 +617,33 @@ namespace Sound {
} }
} }
void processBlock() { void processSector(void* data)
if (stream->pos >= stream->size) {
return; Group* groups = (Group*)data;
stream->raw(groups, sizeof(groups));
pos = 0; pos = 0;
for (int i = 0; i < COUNT(groups); i++) for (int i = 0; i < 18; i++)
for (int j = 0; j < 4; j++) { {
for (int j = 0; j < 4; j++)
{
decode28(groups[i], j, 0); decode28(groups[i], j, 0);
decode28(groups[i], j, 1); decode28(groups[i], j, 1);
pos += 28; pos += 28;
} }
}
pos = 0; pos = 0;
} }
void ZigZagOut(Frame &frame, uint8 p, const int16 *LUT) { void ZigZagOut(Frame &frame, int32 p, const int16 *LUT)
{
FrameHI sum; FrameHI sum;
sum.L = sum.R = 0; sum.L = sum.R = 0;
for (uint8 i = 1; i < 30; i++) { for (int32 i = 1; i < 30; i++)
Frame &f = lerpFrames[uint8(p - i) & 0x1F]; {
Frame &f = lerpFrames[(p - i) & 31];
sum.L += f.L * LUT[i]; sum.L += f.L * LUT[i];
sum.R += f.R * LUT[i]; sum.R += f.R * LUT[i];
} }
@@ -630,40 +653,43 @@ namespace Sound {
} }
virtual int decode(Frame *frames, int count) { virtual int decode(Frame *frames, int count) {
if (pos >= COUNT(buffer)) #if _OS_PSV // TODO crash
processBlock(); memset(frames, 0, count * sizeof(Frame));
ASSERT((int(COUNT(buffer)) - pos) % 6 == 0)
ASSERT(count % 7 == 0)
count = min(count, (int(COUNT(buffer)) - pos) / 6 * 7);
int i = 0;
while (i < count) {
ASSERT(pos < COUNT(buffer));
lerpFrames[lerpPos++ & 0x1F] = buffer[pos++];
lerpFrames[lerpPos++ & 0x1F] = buffer[pos++];
lerpFrames[lerpPos++ & 0x1F] = buffer[pos++];
lerpFrames[lerpPos++ & 0x1F] = buffer[pos++];
lerpFrames[lerpPos++ & 0x1F] = buffer[pos++];
lerpFrames[lerpPos++ & 0x1F] = buffer[pos++];
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[0]);
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[1]);
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[2]);
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[3]);
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[4]);
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[5]);
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[6]);
}
ASSERT(i == count);
return count; return count;
#endif
int i = 0;
while (i < count) {
if (frameIndex == 7) {
frameIndex = 0;
if (pos >= COUNT(buffer)) {
if (!nextSectorCallback || !nextSectorCallback(userData)) {
break;
}
} }
virtual void replay() { ASSERT(pos <= (COUNT(buffer) - 6));
stream->setPos(0);
s1 = s2 = 0; lerpFrames[lerpPos++ & 31] = buffer[pos++];
lerpFrames[lerpPos++ & 31] = buffer[pos++];
lerpFrames[lerpPos++ & 31] = buffer[pos++];
lerpFrames[lerpPos++ & 31] = buffer[pos++];
lerpFrames[lerpPos++ & 31] = buffer[pos++];
lerpFrames[lerpPos++ & 31] = buffer[pos++];
} else {
ZigZagOut(frames[i++], lerpPos, SPU_ZIG_ZAG[frameIndex++]);
}
}
return i;
}
virtual void replay()
{
pos = COUNT(buffer);
lerpPos = 0;
frameIndex = 7;
} }
}; };
#endif #endif
@@ -807,14 +833,17 @@ namespace Sound {
Core::Mutex lock; Core::Mutex lock;
struct Listener { struct Listener
{
mat4 matrix; mat4 matrix;
bool underwater; bool underwater;
} listener[2]; };
Listener listener[2];
int listenersCount; int listenersCount;
Listener& getListener(const vec3 &pos) { Listener& getListener(const vec3 &pos)
{
if (listenersCount == 1 || (listener[0].matrix.getPos() - pos).length2() < (listener[1].matrix.getPos() - pos).length2()) if (listenersCount == 1 || (listener[0].matrix.getPos() - pos).length2() < (listener[1].matrix.getPos() - pos).length2())
return listener[0]; return listener[0];
return listener[1]; return listener[1];
@@ -832,7 +861,8 @@ namespace Sound {
bool flipped; bool flipped;
struct Sample { struct Sample
{
const vec3 *uniquePtr; const vec3 *uniquePtr;
Decoder *decoder; Decoder *decoder;
vec3 pos; vec3 pos;
@@ -846,19 +876,22 @@ namespace Sound {
bool isPaused; bool isPaused;
bool stopAfterFade; bool stopAfterFade;
Sample(Decoder *decoder, float volume, float pitch, int flags, int id) : uniquePtr(NULL), decoder(decoder), volume(volume), volumeTarget(volume), volumeDelta(0.0f), pitch(pitch), flags(flags), id(id) { Sample(Decoder *decoder, float volume, float pitch, int flags, int id) : uniquePtr(NULL), decoder(decoder), volume(volume), volumeTarget(volume), volumeDelta(0.0f), pitch(pitch), flags(flags), id(id)
{
isPlaying = decoder != NULL; isPlaying = decoder != NULL;
isPaused = false; isPaused = false;
stopAfterFade = true;
} }
Sample(Stream *stream, const vec3 *pos, float volume, float pitch, int flags, int id) : uniquePtr(pos), decoder(NULL), volume(volume), volumeTarget(volume), volumeDelta(0.0f), pitch(pitch), flags(flags), id(id) { Sample(Stream *stream, const vec3 *pos, float volume, float pitch, int flags, int id) : uniquePtr(pos), decoder(NULL), volume(volume), volumeTarget(volume), volumeDelta(0.0f), pitch(pitch), flags(flags), id(id)
{
this->pos = pos ? *pos : vec3(0.0f); this->pos = pos ? *pos : vec3(0.0f);
#ifndef NO_SOUND #ifndef NO_SOUND
uint32 fourcc; uint32 fourcc;
stream->read(fourcc); stream->read(fourcc);
if (fourcc == FOURCC("RIFF")) { // wav if (fourcc == FOURCC("RIFF")) // wav
{
struct { struct {
uint16 format; uint16 format;
uint16 channels; uint16 channels;
@@ -866,7 +899,7 @@ namespace Sound {
uint32 bytesPerSec; uint32 bytesPerSec;
uint16 block; uint16 block;
uint16 sampleBits; uint16 sampleBits;
} waveFmt; } waveFmt = {};
stream->seek(8); stream->seek(8);
while (stream->pos < stream->size) { while (stream->pos < stream->size) {
@@ -882,25 +915,22 @@ namespace Sound {
if (waveFmt.format == 2) decoder = new ADPCM(stream, waveFmt.channels, waveFmt.samplesPerSec, size, waveFmt.block); if (waveFmt.format == 2) decoder = new ADPCM(stream, waveFmt.channels, waveFmt.samplesPerSec, size, waveFmt.block);
#endif #endif
break; break;
} else } else {
stream->seek(size); stream->seek(size);
} }
} }
else if (fourcc == FOURCC("OggS")) { // ogg } else if (fourcc == FOURCC("OggS")) { // ogg
stream->seek(-4); stream->seek(-4);
#ifdef DECODE_OGG #ifdef DECODE_OGG
decoder = new OGG(stream, 2); decoder = new OGG(stream, 2);
#endif #endif
} } else if (fourcc == FOURCC("ID3\3")) { // mp3
else if (fourcc == FOURCC("ID3\3")) { // mp3
#ifdef DECODE_MP3 #ifdef DECODE_MP3
decoder = new MP3(stream, 2); decoder = new MP3(stream, 2);
#endif #endif
} } else if (fourcc == FOURCC("SEGA")) { // Sega Saturn PCM mono signed 8-bit 11025 Hz
else if (fourcc == FOURCC("SEGA")) { // Sega Saturn PCM mono signed 8-bit 11025 Hz
decoder = new PCM(stream, 1, 11025, stream->size, -8); decoder = new PCM(stream, 1, 11025, stream->size, -8);
} } else { // vag
else { // vag
stream->setPos(0); stream->setPos(0);
#ifdef DECODE_VAG #ifdef DECODE_VAG
decoder = new VAG(stream); decoder = new VAG(stream);
@@ -909,32 +939,41 @@ namespace Sound {
#endif #endif
if (!decoder) if (!decoder)
{
delete stream; delete stream;
}
isPlaying = decoder != NULL; isPlaying = decoder != NULL;
isPaused = false; isPaused = false;
} }
~Sample() { ~Sample()
{
delete decoder; delete decoder;
} }
void setVolume(float value, float time) { void setVolume(float value, float time)
{
if (value < 0.0f) { if (value < 0.0f) {
stopAfterFade = true; stopAfterFade = true;
value = 0.0f; value = 0.0f;
} else } else {
stopAfterFade = false; stopAfterFade = false;
}
volumeTarget = value; volumeTarget = value;
volumeDelta = volumeTarget - volume; volumeDelta = volumeTarget - volume;
if (time > 0.0f) if (time > 0.0f)
{
volumeDelta /= 44100.0f * time; volumeDelta /= 44100.0f * time;
} }
}
vec2 getPan()
{
if (!(flags & PAN)) return vec2(1.0f);
vec2 getPan() {
if (!(flags & PAN))
return vec2(1.0f);
mat4 m = Sound::getListener(pos).matrix; mat4 m = Sound::getListener(pos).matrix;
vec3 v = pos - m.offset().xyz(); vec3 v = pos - m.offset().xyz();
vec3 n = v.normal(); vec3 n = v.normal();
@@ -949,27 +988,35 @@ namespace Sound {
return (value * SND_PAN_FACTOR + (1.0f - SND_PAN_FACTOR)) * facing * dist; return (value * SND_PAN_FACTOR + (1.0f - SND_PAN_FACTOR)) * facing * dist;
} }
bool render(Frame *frames, int count) { bool render(Frame *frames, int count)
{
if (!isPlaying) return false; if (!isPlaying) return false;
if (isPaused) { if (isPaused)
{
memset(frames, 0, sizeof(Frame) * count); memset(frames, 0, sizeof(Frame) * count);
return true; return true;
} }
// decode // decode
int i = 0; int i = 0;
while (i < count) { while (i < count)
int res = decoder->decode(&frames[i], count - i); {
if (res == 0) { int ret = decoder->decode(&frames[i], count - i);
if (!(flags & LOOP)) {
if (ret == 0)
{
if (!(flags & LOOP))
{
isPlaying = false; isPlaying = false;
break; break;
} else }
decoder->replay(); decoder->replay();
} }
i += res;
i += ret;
} }
// apply volume // apply volume
#define VOL_CONV(x) (1.0f - sqrtf(1.0f - x * x)); #define VOL_CONV(x) (1.0f - sqrtf(1.0f - x * x));
@@ -977,19 +1024,27 @@ namespace Sound {
float v = volume * m; float v = volume * m;
vec2 pan = getPan(); vec2 pan = getPan();
vec2 vol = pan * VOL_CONV(v); vec2 vol = pan * VOL_CONV(v);
for (int j = 0; j < i; j++) { for (int j = 0; j < i; j++)
if (volumeDelta != 0.0f) { // increase / decrease channel volume {
if (volumeDelta != 0.0f) // increase / decrease channel volume
{
volume += volumeDelta; volume += volumeDelta;
if ((volumeDelta < 0.0f && volume < volumeTarget) || if ((volumeDelta < 0.0f && volume < volumeTarget) ||
(volumeDelta > 0.0f && volume > volumeTarget)) { (volumeDelta > 0.0f && volume > volumeTarget))
{
volume = volumeTarget; volume = volumeTarget;
volumeDelta = 0.0f; volumeDelta = 0.0f;
if (stopAfterFade) if (stopAfterFade)
{
isPlaying = false; isPlaying = false;
} }
}
v = volume * m; v = volume * m;
vol = pan * VOL_CONV(v); vol = pan * VOL_CONV(v);
} }
frames[j].L = int(frames[j].L * vol.x); frames[j].L = int(frames[j].L * vol.x);
frames[j].R = int(frames[j].R * vol.y); frames[j].R = int(frames[j].R * vol.y);
} }
@@ -998,19 +1053,23 @@ namespace Sound {
return true; return true;
} }
void stop() { void stop()
{
isPlaying = false; isPlaying = false;
} }
void replay() { void replay()
{
decoder->replay(); decoder->replay();
} }
void pause() { void pause()
{
isPaused = true; isPaused = true;
} }
void resume() { void resume()
{
isPaused = false; isPaused = false;
} }
} *channels[SND_CHANNELS_MAX]; } *channels[SND_CHANNELS_MAX];
@@ -1026,7 +1085,8 @@ namespace Sound {
Filter::Reverberation reverb; Filter::Reverberation reverb;
Filter::LowPass lowPass; Filter::LowPass lowPass;
void init() { void init()
{
flipped = false; flipped = false;
channelsCount = 0; channelsCount = 0;
callback = NULL; callback = NULL;
@@ -1037,9 +1097,12 @@ namespace Sound {
#endif #endif
} }
void deinit() { void deinit()
{
for (int i = 0; i < channelsCount; i++) for (int i = 0; i < channelsCount; i++)
{
delete channels[i]; delete channels[i];
}
#ifdef DECODE_MP3 #ifdef DECODE_MP3
mp3_decode_free(); mp3_decode_free();
#endif #endif
@@ -1047,39 +1110,52 @@ namespace Sound {
delete[] result; delete[] result;
} }
void renderChannels(FrameHI *result, int count, bool music) { void renderChannels(FrameHI *result, int count, bool music)
{
PROFILE_CPU_TIMING(stats.render[music]); PROFILE_CPU_TIMING(stats.render[music]);
int bufSize = count + count / 2 + 4; int bufSize = count + count / 2 + 4;
if (!buffer) buffer = new Frame[bufSize]; // + 50% for pitch if (!buffer) {
buffer = new Frame[bufSize]; // + 50% for pitch
}
for (int i = 0; i < channelsCount; i++) { for (int i = 0; i < channelsCount; i++)
if (music != ((channels[i]->flags & MUSIC) != 0)) {
continue; if (music != ((channels[i]->flags & MUSIC) != 0)) {
if (channels[i]->flags & (FLIPPED | UNFLIPPED)) {
if (!(channels[i]->flags & (flipped ? FLIPPED : UNFLIPPED)))
continue;
vec3 d = channels[i]->pos - getListener(channels[i]->pos).matrix.getPos();
if (fabsf(d.x) > SND_FADEOFF_DIST || fabsf(d.y) > SND_FADEOFF_DIST || fabsf(d.z) > SND_FADEOFF_DIST)
continue; continue;
} }
if ((channels[i]->flags & LOOP) && channels[i]->volume < EPS && channels[i]->volumeTarget < EPS) if (channels[i]->flags & (FLIPPED | UNFLIPPED)) {
if (!(channels[i]->flags & (flipped ? FLIPPED : UNFLIPPED))) {
continue; continue;
}
vec3 d = channels[i]->pos - getListener(channels[i]->pos).matrix.getPos();
if (fabsf(d.x) > SND_FADEOFF_DIST || fabsf(d.y) > SND_FADEOFF_DIST || fabsf(d.z) > SND_FADEOFF_DIST) {
continue;
}
}
if ((channels[i]->flags & LOOP) && channels[i]->volume < EPS && channels[i]->volumeTarget < EPS) {
continue;
}
memset(buffer, 0, sizeof(Frame) * bufSize); memset(buffer, 0, sizeof(Frame) * bufSize);
channels[i]->render(buffer, (int(count * channels[i]->pitch) + 3) / 4 * 4); channels[i]->render(buffer, (int(count * channels[i]->pitch) + 3) / 4 * 4);
if (channels[i]->pitch == 1.0f) { // no pitch if (channels[i]->pitch == 1.0f) { // no pitch
for (int j = 0; j < count; j++) {
for (int j = 0; j < count; j++)
{
result[j].L += buffer[j].L; result[j].L += buffer[j].L;
result[j].R += buffer[j].R; result[j].R += buffer[j].R;
} }
} else { // has pitch (interpolate values for smooth wave) } else { // has pitch (interpolate values for smooth wave)
float t = 0.0f; float t = 0.0f;
for (int j = 0; j < count; j++, t += channels[i]->pitch) {
for (int j = 0; j < count; j++, t += channels[i]->pitch)
{
int idxA = int(t); int idxA = int(t);
int idxB = (j == (count - 1)) ? idxA : (idxA + 1); int idxB = (j == (count - 1)) ? idxA : (idxA + 1);
int st = int((t - idxA) * DSP_SCALE); int st = int((t - idxA) * DSP_SCALE);
@@ -1089,67 +1165,95 @@ namespace Sound {
result[j].L += a.L + ((b.L - a.L) * st >> DSP_SCALE_BIT); result[j].L += a.L + ((b.L - a.L) * st >> DSP_SCALE_BIT);
result[j].R += a.R + ((b.R - a.R) * st >> DSP_SCALE_BIT); result[j].R += a.R + ((b.R - a.R) * st >> DSP_SCALE_BIT);
} }
} }
} }
} }
void convFrames(FrameHI *from, Frame *to, int count) { void convFrames(FrameHI *from, Frame *to, int count)
for (int i = 0; i < count; i++) { {
for (int i = 0; i < count; i++)
{
to[i].L = clamp(from[i].L, -32767, 32767); to[i].L = clamp(from[i].L, -32767, 32767);
to[i].R = clamp(from[i].R, -32767, 32767); to[i].R = clamp(from[i].R, -32767, 32767);
} }
} }
void fill(Frame *frames, int count) { void fill(Frame *frames, int count)
{
OS_LOCK(lock); OS_LOCK(lock);
PROFILE_CPU_TIMING(stats.mixer); PROFILE_CPU_TIMING(stats.mixer);
if (!channelsCount) { if (!channelsCount) {
if (result && (Core::settings.audio.music != 0 || Core::settings.audio.sound != 0)) { if (result && (Core::settings.audio.music != 0 || Core::settings.audio.sound != 0)) {
memset(result, 0, sizeof(FrameHI) * count); memset(result, 0, sizeof(FrameHI) * count);
if (Core::settings.audio.reverb) if (Core::settings.audio.reverb)
{
reverb.process(result, count); reverb.process(result, count);
}
convFrames(result, frames, count); convFrames(result, frames, count);
} else } else {
memset(frames, 0, sizeof(frames[0]) * count); memset(frames, 0, sizeof(frames[0]) * count);
}
return; return;
} }
if (!result) result = new FrameHI[count]; if (!result)
{
result = new FrameHI[count];
}
memset(result, 0, sizeof(FrameHI) * count); memset(result, 0, sizeof(FrameHI) * count);
if (Core::settings.audio.sound != 0) { if (Core::settings.audio.sound != 0)
{
renderChannels(result, count, false); renderChannels(result, count, false);
if (Core::settings.audio.reverb) { if (Core::settings.audio.reverb)
if (listener[0].underwater) { {
if (listener[0].underwater)
{
lowPass.process(result, count, SND_LOWPASS_FREQ); lowPass.process(result, count, SND_LOWPASS_FREQ);
} }
reverb.process(result, count); reverb.process(result, count);
} }
} }
if (Core::settings.audio.music != 0) { if (Core::settings.audio.music != 0)
{
renderChannels(result, count, true); renderChannels(result, count, true);
} }
convFrames(result, frames, count); convFrames(result, frames, count);
for (int i = 0; i < channelsCount; i++) for (int i = 0; i < channelsCount; i++)
if (!channels[i]->isPlaying) { {
if (callback) callback(channels[i]); if (!channels[i]->isPlaying)
{
if (callback)
{
callback(channels[i]);
}
delete channels[i]; delete channels[i];
channels[i] = channels[--channelsCount]; channels[i] = channels[--channelsCount];
i--; i--;
} }
} }
}
Stream *openCDAudioWAD(const char *name, int index = -1) { Stream *openCDAudioWAD(const char *name, int index = -1)
{
if (!Stream::existsContent(name)) if (!Stream::existsContent(name))
{
return NULL; return NULL;
}
Stream *stream = new Stream(name); Stream *stream = new Stream(name);
if (stream->size) { if (stream->size)
{
struct Item { struct Item {
char name[260]; char name[260];
int size; int size;
@@ -1165,21 +1269,30 @@ namespace Sound {
return NULL; return NULL;
} }
Stream *openCDAudioMP3(const char *dat, const char *name, int index = -1) { Stream *openCDAudioMP3(const char *dat, const char *name, int index = -1)
{
if (!Stream::existsContent(dat) || !Stream::existsContent(name)) if (!Stream::existsContent(dat) || !Stream::existsContent(name))
{
return NULL; return NULL;
}
Stream *stream = new Stream(name); Stream *stream = new Stream(name);
return stream; return stream;
} }
Sample* getChannel(int id, const vec3 *pos) { Sample* getChannel(int id, const vec3 *pos)
{
for (int i = 0; i < channelsCount; i++) for (int i = 0; i < channelsCount; i++)
{
if (channels[i]->id == id && channels[i]->uniquePtr == pos) if (channels[i]->id == id && channels[i]->uniquePtr == pos)
{
return channels[i]; return channels[i];
}
}
return NULL; return NULL;
} }
Sample* play(Stream *stream, const vec3 *pos = NULL, float volume = 1.0f, float pitch = 0.0f, int flags = 0, int id = - 1) { Sample* play(Stream *stream, const vec3 *pos = NULL, float volume = 1.0f, float pitch = 0.0f, int flags = 0, int id = - 1)
{
#ifndef NO_SOUND #ifndef NO_SOUND
OS_LOCK(lock); OS_LOCK(lock);
@@ -1196,16 +1309,23 @@ namespace Sound {
} }
} }
if (flags & (UNIQUE | REPLAY)) { if (flags & (UNIQUE | REPLAY))
{
Sample *ch = getChannel(id, pos); Sample *ch = getChannel(id, pos);
if (ch) { if (ch)
{
if (pos) if (pos)
{
ch->pos = *pos; ch->pos = *pos;
}
ch->pitch = pitch; ch->pitch = pitch;
if (flags & REPLAY) if (flags & REPLAY)
{
ch->replay(); ch->replay();
}
delete stream; delete stream;
return ch; return ch;
@@ -1213,7 +1333,9 @@ namespace Sound {
} }
if (channelsCount < SND_CHANNELS_MAX) if (channelsCount < SND_CHANNELS_MAX)
{
return channels[channelsCount++] = new Sample(stream, pos, volume, pitch, flags, id); return channels[channelsCount++] = new Sample(stream, pos, volume, pitch, flags, id);
}
LOG("! no free channels\n"); LOG("! no free channels\n");
} }
@@ -1222,28 +1344,39 @@ namespace Sound {
return NULL; return NULL;
} }
Sample* play(Decoder *decoder) { Sample* play(Decoder *decoder)
{
OS_LOCK(lock); OS_LOCK(lock);
if (channelsCount < SND_CHANNELS_MAX) if (channelsCount < SND_CHANNELS_MAX)
{
return channels[channelsCount++] = new Sample(decoder, 1.0f, 1.0f, MUSIC, -1); return channels[channelsCount++] = new Sample(decoder, 1.0f, 1.0f, MUSIC, -1);
}
return NULL; return NULL;
} }
void stop(int id = -1) { void stop(int id = -1)
{
OS_LOCK(lock); OS_LOCK(lock);
for (int i = 0; i < channelsCount; i++) for (int i = 0; i < channelsCount; i++)
{
if (id == -1 || channels[i]->id == id) if (id == -1 || channels[i]->id == id)
{
channels[i]->stop(); channels[i]->stop();
} }
}
}
void stopAll() { void stopAll()
{
OS_LOCK(lock); OS_LOCK(lock);
reverb.clear(); reverb.clear();
for (int i = 0; i < channelsCount; i++) for (int i = 0; i < channelsCount; i++)
{
delete channels[i]; delete channels[i];
}
channelsCount = 0; channelsCount = 0;
} }
} }

View File

@@ -9,7 +9,7 @@
#define SUBTITLES_SPEED 0.1f #define SUBTITLES_SPEED 0.1f
#define TEXT_LINE_HEIGHT 18 #define TEXT_LINE_HEIGHT 18
#if defined(_OS_PSV) || defined(_OS_TNS) #if defined(_OS_TNS)
#define UI_SHOW_FPS #define UI_SHOW_FPS
#endif #endif
@@ -768,6 +768,7 @@ namespace UI {
game->setShader(Core::passCompose, Shader::ENTITY, false, false); game->setShader(Core::passCompose, Shader::ENTITY, false, false);
Core::setMaterial(1.0f, 0.0f, 0.0f, 1.0f); Core::setMaterial(1.0f, 0.0f, 0.0f, 1.0f);
Core::setFog(FOG_NONE);
vec4 o = vec4(offset, 0.0f); vec4 o = vec4(offset, 0.0f);

View File

@@ -134,7 +134,7 @@ static const AC_ENTRY STR_AC[] = {
{ 0X3E , 27 , 1 , 17 }, // 00111110 { 0X3E , 27 , 1 , 17 }, // 00111110
}; };
static const uint8 STR_ZIG_ZAG[] = { static const uint8 STR_ZSCAN[] = {
0, 1, 8, 16, 9, 2, 3, 10, 0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5, 17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34, 12, 19, 26, 33, 40, 48, 41, 34,
@@ -145,25 +145,17 @@ static const uint8 STR_ZIG_ZAG[] = {
53, 60, 61, 54, 47, 55, 62, 63, 53, 60, 61, 54, 47, 55, 62, 63,
}; };
static const uint8 STR_QUANTIZATION[] = { static const int32 STR_QTABLE[] = {
2, 16, 19, 22, 26, 27, 29, 34, 0x00020000, 0x00163150, 0x00163150, 0x0018D321, 0x001EC830, 0x0018D321, 0x0019DE84, 0x0027DEA0,
16, 16, 22, 24, 27, 29, 34, 37, 0x0027DEA0, 0x0019DE84, 0x00160000, 0x0023E1B0, 0x002C6282, 0x002724C0, 0x001A0000, 0x001536B1,
19, 22, 26, 27, 29, 34, 34, 38, 0x00257337, 0x00297B55, 0x0027F206, 0x00241022, 0x00146D8E, 0x000E1238, 0x001D6CAF, 0x002346F9,
22, 22, 26, 27, 29, 34, 37, 40, 0x00255528, 0x0025E3EF, 0x001F9AA9, 0x000FB1DC, 0x00096162, 0x001985B6, 0x0022E73A, 0x002219AE,
22, 26, 27, 29, 32, 35, 40, 48, 0x002219AE, 0x001DC539, 0x00144489, 0x000772FB, 0x000B1918, 0x00148191, 0x001D9060, 0x00200000,
26, 27, 29, 32, 35, 40, 48, 58, 0x001F6966, 0x00180AAA, 0x000E28D8, 0x000DB2B0, 0x00178BD2, 0x001B7FC9, 0x001B7FC9, 0x0015A314,
26, 27, 29, 34, 38, 46, 56, 69, 0x000C9DD8, 0x000C53EE, 0x001490C8, 0x0018B140, 0x0015A5E0, 0x000CFA08, 0x000D3E30, 0x00146910,
27, 29, 35, 38, 46, 56, 69, 83 0x00138F5A, 0x000CB0EE, 0x000C2390, 0x001066E8, 0x000C928C, 0x000A4DA2, 0x000A4DA2, 0x00065187,
}; };
#define STR_IDCT_A 23170
#define STR_IDCT_B 32138
#define STR_IDCT_C 27245
#define STR_IDCT_D 18204
#define STR_IDCT_E 6392
#define STR_IDCT_F 30273
#define STR_IDCT_G 12539
struct Video { struct Video {
struct Decoder : Sound::Decoder { struct Decoder : Sound::Decoder {
@@ -766,12 +758,13 @@ struct Video {
uint16 chunksCount; uint16 chunksCount;
uint32 frameIndex; uint32 frameIndex;
uint32 chunkSize; uint32 chunkSize;
uint16 width, height; uint16 width;
uint16 height;
uint16 blocks; uint16 blocks;
uint16 unk1; uint16 unk3800;
uint16 qscale; uint16 qscale;
uint16 version; uint16 version;
uint32 unk2; uint32 unk00000000;
}; };
struct VideoChunk { struct VideoChunk {
@@ -800,7 +793,7 @@ struct Video {
int curVideoChunk; int curVideoChunk;
int curAudioChunk; int curAudioChunk;
Sound::Decoder *audioDecoder; Sound::XA *audioDecoder;
struct { struct {
uint8 code; uint8 code;
@@ -809,9 +802,13 @@ struct Video {
bool hasSyncHeader; bool hasSyncHeader;
STR(Stream *stream) : Decoder(stream), videoChunksCount(0), audioChunksCount(0), curVideoChunk(-1), curAudioChunk(-1), audioDecoder(NULL) { STR(Stream *stream) : Decoder(stream), videoChunksCount(0), audioChunksCount(0), curVideoChunk(-1), curAudioChunk(-1), audioDecoder(NULL)
{
memset(videoChunks, 0, sizeof(videoChunks));
memset(audioChunks, 0, sizeof(audioChunks));
if (stream->pos >= stream->size) { if (stream->pos >= stream->size)
{
LOG("Can't load STR format \"%s\"\n", stream->name); LOG("Can't load STR format \"%s\"\n", stream->name);
ASSERT(false); ASSERT(false);
return; return;
@@ -831,15 +828,11 @@ struct Video {
hasSyncHeader = syncMagic[0] == 0xFFFFFF00 && syncMagic[1] == 0xFFFFFFFF && syncMagic[2] == 0x00FFFFFF; hasSyncHeader = syncMagic[0] == 0xFFFFFF00 && syncMagic[1] == 0xFFFFFFFF && syncMagic[2] == 0x00FFFFFF;
if (!hasSyncHeader) { if (!hasSyncHeader)
{
LOG("! No sync header found, please use jpsxdec tool to extract FMVs\n"); LOG("! No sync header found, please use jpsxdec tool to extract FMVs\n");
} }
for (int i = 0; i < MAX_CHUNKS; i++) {
videoChunks[i].size = 0;
audioChunks[i].size = 0;
}
nextChunk(); nextChunk();
VideoChunk &chunk = videoChunks[0]; VideoChunk &chunk = videoChunks[0];
@@ -853,49 +846,63 @@ struct Video {
#ifdef NO_SOUND #ifdef NO_SOUND
audioDecoder = NULL; audioDecoder = NULL;
#else #else
audioDecoder = new Sound::XA(NULL); audioDecoder = new Sound::XA(this, audioNextBlockCallback);
#endif #endif
} }
virtual ~STR() { virtual ~STR()
{
OS_LOCK(Sound::lock); OS_LOCK(Sound::lock);
audioDecoder->stream = NULL; audioDecoder->stream = NULL;
delete audioDecoder; delete audioDecoder;
} }
void buildLUT(uint8 *LUT, int start, int end, int shift) { void buildLUT(uint8 *LUT, int start, int end, int shift)
for (int i = start; i < end; i++) { {
for (int i = start; i < end; i++)
{
const AC_ENTRY &e = STR_AC[i]; const AC_ENTRY &e = STR_AC[i];
uint8 trash = (1 << (8 + shift - e.length + 1)); uint8 trash = (1 << (8 + shift - e.length + 1));
// fill the value and all possible endings // fill the value and all possible endings
while (trash--) while (trash--)
{
LUT[e.code | trash] = i; LUT[e.code | trash] = i;
} }
} }
}
bool nextChunk() { bool nextChunk()
{
OS_LOCK(Sound::lock); OS_LOCK(Sound::lock);
if (videoChunks[videoChunksCount % MAX_CHUNKS].size > 0) if (videoChunks[videoChunksCount % MAX_CHUNKS].size > 0)
{
return false; return false;
}
if (stream->pos >= stream->size) if (stream->pos >= stream->size)
{
return false; return false;
}
bool readingVideo = false; bool readingVideo = false;
while (stream->pos < stream->size) { while (stream->pos < stream->size)
{
if (hasSyncHeader) if (hasSyncHeader)
{
stream->seek(24); stream->seek(24);
}
Sector sector; Sector sector;
stream->raw(&sector, sizeof(Sector)); stream->raw(&sector, sizeof(Sector));
if (sector.magic == MAGIC_STR) { if (sector.magic == MAGIC_STR)
{
VideoChunk *chunk = videoChunks + (videoChunksCount % MAX_CHUNKS); VideoChunk *chunk = videoChunks + (videoChunksCount % MAX_CHUNKS);
if (sector.chunkIndex == 0) { if (sector.chunkIndex == 0)
{
readingVideo = true; readingVideo = true;
chunk->size = 0; chunk->size = 0;
chunk->width = sector.width; chunk->width = sector.width;
@@ -908,9 +915,12 @@ struct Video {
chunk->size += VIDEO_SECTOR_SIZE; chunk->size += VIDEO_SECTOR_SIZE;
if (hasSyncHeader) if (hasSyncHeader)
{
stream->seek(280); stream->seek(280);
}
if (sector.chunkIndex == sector.chunksCount - 1) { if (sector.chunkIndex == sector.chunksCount - 1)
{
videoChunksCount++; videoChunksCount++;
return true; return true;
} }
@@ -924,19 +934,26 @@ struct Video {
stream->seek(24); stream->seek(24);
if (!hasSyncHeader) if (!hasSyncHeader)
{
stream->seek(2048 - (AUDIO_SECTOR_SIZE + 24)); stream->seek(2048 - (AUDIO_SECTOR_SIZE + 24));
}
if (!readingVideo) if (!readingVideo)
{
return true; return true;
}
}; };
} }
return false; return false;
} }
// http://jpsxdec.blogspot.com/2011/06/decoding-mpeg-like-bitstreams.html // http://jpsxdec.blogspot.com/2011/06/decoding-mpeg-like-bitstreams.html
bool readCode(BitStream &bs, int16 &skip, int16 &ac) { bool readCode(BitStream &bs, int16 &skip, int16 &ac)
if (bs.readU(1)) { {
if (bs.readU(1)) { if (bs.readU(1))
{
if (bs.readU(1))
{
skip = 0; skip = 0;
ac = bs.readU(1) ? -1 : 1; ac = bs.readU(1) ? -1 : 1;
return true; return true;
@@ -946,9 +963,12 @@ struct Video {
int nz = 1; int nz = 1;
while (!bs.readU(1)) while (!bs.readU(1))
{
nz++; nz++;
}
if (nz == 5) { // escape code == 0b1000001 if (nz == 5) // escape code == 0b1000001
{
uint16 esc = bs.readU(16); uint16 esc = bs.readU(16);
skip = esc >> 10; skip = esc >> 10;
ac = esc & 0x3FF; ac = esc & 0x3FF;
@@ -987,49 +1007,208 @@ struct Video {
return true; return true;
} }
void IDCT_PASS(int16 *src, int16 *dst, int32 x) { \ // https://psx-spx.consoledev.net/macroblockdecodermdec/
int32 a0 = src[0 * x] * STR_IDCT_A; // https://github.com/grumpycoders/pcsx-redux/
int32 b1 = src[1 * x] * STR_IDCT_B; #define AAN_CONST_BITS 12
int32 c1 = src[1 * x] * STR_IDCT_C; #define AAN_PRESCALE_BITS 16
int32 d1 = src[1 * x] * STR_IDCT_D;
int32 e1 = src[1 * x] * STR_IDCT_E; #define AAN_EXTRA 12
int32 f2 = src[2 * x] * STR_IDCT_F; #define SCALE(x, n) ((x) >> (n))
int32 g2 = src[2 * x] * STR_IDCT_G; #define SCALER(x, n) (((x) + ((1 << (n)) >> 1)) >> (n))
int32 b3 = src[3 * x] * STR_IDCT_B; #define RLE_RUN(a) ((a) >> 10)
int32 c3 = src[3 * x] * STR_IDCT_C; #define RLE_VAL(a) (((int)(a) << (sizeof(int) * 8 - 10)) >> (sizeof(int) * 8 - 10))
int32 d3 = src[3 * x] * STR_IDCT_D; #define MULS(var, c) (SCALE((var) * (c), AAN_CONST_BITS))
int32 e3 = src[3 * x] * STR_IDCT_E;
int32 a4 = src[4 * x] * STR_IDCT_A; #define AAN_CONST_SIZE 24
int32 b5 = src[5 * x] * STR_IDCT_B; #define AAN_CONST_SCALE (AAN_CONST_SIZE - AAN_CONST_BITS)
int32 c5 = src[5 * x] * STR_IDCT_C;
int32 d5 = src[5 * x] * STR_IDCT_D; #define MULR(a) ((1434 * (a)))
int32 e5 = src[5 * x] * STR_IDCT_E; #define MULB(a) ((1807 * (a)))
int32 f6 = src[6 * x] * STR_IDCT_F; #define MULG2(a, b) ((-351 * (a)-728 * (b)))
int32 g6 = src[6 * x] * STR_IDCT_G; #define MULY(a) ((a) << 10)
int32 b7 = src[7 * x] * STR_IDCT_B;
int32 c7 = src[7 * x] * STR_IDCT_C; #define MAKERGB15(r, g, b, a) ((a | ((b) << 10) | ((g) << 5) | (r)))
int32 d7 = src[7 * x] * STR_IDCT_D; #define SCALE8(c) SCALER(c, 20)
int32 e7 = src[7 * x] * STR_IDCT_E; #define SCALE5(c) SCALER(c, 23)
dst[0 * x] = ( a0 + b1 + f2 + c3 + a4 + d5 + g6 + e7 ) >> 16;
dst[1 * x] = ( a0 + c1 + g2 - e3 - a4 - b5 - f6 - d7 ) >> 16; #define CLAMP5(c) (((c) < -16) ? 0 : (((c) > (31 - 16)) ? 31 : ((c) + 16)))
dst[2 * x] = ( a0 + d1 - g2 - b3 - a4 + e5 + f6 + c7 ) >> 16; #define CLAMP8(c) (((c) < -128) ? 0 : (((c) > (255 - 128)) ? 255 : ((c) + 128)))
dst[3 * x] = ( a0 + e1 - f2 - d3 + a4 + c5 - g6 - b7 ) >> 16;
dst[4 * x] = ( a0 - e1 - f2 + d3 + a4 - c5 - g6 + b7 ) >> 16; #define CLAMP_SCALE8(a) (CLAMP8(SCALE8(a)))
dst[5 * x] = ( a0 - d1 - g2 + b3 - a4 - e5 + f6 - c7 ) >> 16; #define CLAMP_SCALE5(a) (CLAMP5(SCALE5(a)))
dst[6 * x] = ( a0 - c1 + g2 + e3 - a4 + b5 - f6 + d7 ) >> 16;
dst[7 * x] = ( a0 - b1 + f2 - c3 + a4 - d5 + g6 - e7 ) >> 16; static inline void fillCol(int *blk, int val)
{
blk[0 * 8] = blk[1 * 8] = blk[2 * 8] = blk[3 * 8] = blk[4 * 8] = blk[5 * 8] = blk[6 * 8] = blk[7 * 8] = val;
} }
void IDCT(int16 *b) { static inline void fillRow(int *blk, int val)
int16 t[64]; {
for (int i = 0; i < 8 * 1; i += 1) IDCT_PASS(b + i, t + i, 8); blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = val;
for (int i = 0; i < 8 * 8; i += 8) IDCT_PASS(t + i, b + i, 1);
} }
virtual bool decodeVideo(Color32 *pixels) { static void IDCT(int *block, int used_col)
{
#define FIX_1_082392200 4433
#define FIX_1_414213562 5793
#define FIX_1_847759065 7568
#define FIX_2_613125930 10703
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
int z5, z10, z11, z12, z13;
int *ptr;
int i;
if (used_col == -1)
{
int v = block[0];
for (i = 0; i < 64; i++)
{
block[i] = v;
}
return;
}
ptr = block;
for (i = 0; i < 8; i++, ptr++)
{
if ((used_col & (1 << i)) == 0)
{
if (ptr[8 * 0])
{
fillCol(ptr, ptr[0]);
used_col |= (1 << i);
}
continue;
}
z10 = ptr[8 * 0] + ptr[8 * 4];
z11 = ptr[8 * 0] - ptr[8 * 4];
z13 = ptr[8 * 2] + ptr[8 * 6];
z12 = MULS(ptr[8 * 2] - ptr[8 * 6], FIX_1_414213562) - z13;
tmp0 = z10 + z13;
tmp3 = z10 - z13;
tmp1 = z11 + z12;
tmp2 = z11 - z12;
z13 = ptr[8 * 3] + ptr[8 * 5];
z10 = ptr[8 * 3] - ptr[8 * 5];
z11 = ptr[8 * 1] + ptr[8 * 7];
z12 = ptr[8 * 1] - ptr[8 * 7];
tmp7 = z11 + z13;
z5 = (z12 - z10) * (FIX_1_847759065);
tmp6 = SCALE(z10 * (FIX_2_613125930) + z5, AAN_CONST_BITS) - tmp7;
tmp5 = MULS(z11 - z13, FIX_1_414213562) - tmp6;
tmp4 = SCALE(z12 * (FIX_1_082392200)-z5, AAN_CONST_BITS) + tmp5;
ptr[8 * 0] = (tmp0 + tmp7);
ptr[8 * 7] = (tmp0 - tmp7);
ptr[8 * 1] = (tmp1 + tmp6);
ptr[8 * 6] = (tmp1 - tmp6);
ptr[8 * 2] = (tmp2 + tmp5);
ptr[8 * 5] = (tmp2 - tmp5);
ptr[8 * 4] = (tmp3 + tmp4);
ptr[8 * 3] = (tmp3 - tmp4);
}
ptr = block;
if (used_col == 1)
{
for (i = 0; i < 8; i++)
{
fillRow(block + 8 * i, block[8 * i]);
}
} else {
for (i = 0; i < 8; i++, ptr += 8)
{
z10 = ptr[0] + ptr[4];
z11 = ptr[0] - ptr[4];
z13 = ptr[2] + ptr[6];
z12 = MULS(ptr[2] - ptr[6], FIX_1_414213562) - z13;
tmp0 = z10 + z13;
tmp3 = z10 - z13;
tmp1 = z11 + z12;
tmp2 = z11 - z12;
z13 = ptr[3] + ptr[5];
z10 = ptr[3] - ptr[5];
z11 = ptr[1] + ptr[7];
z12 = ptr[1] - ptr[7];
tmp7 = z11 + z13;
z5 = (z12 - z10) * FIX_1_847759065;
tmp6 = SCALE(z10 * FIX_2_613125930 + z5, AAN_CONST_BITS) - tmp7;
tmp5 = MULS(z11 - z13, FIX_1_414213562) - tmp6;
tmp4 = SCALE(z12 * FIX_1_082392200 - z5, AAN_CONST_BITS) + tmp5;
ptr[0] = tmp0 + tmp7;
ptr[7] = tmp0 - tmp7;
ptr[1] = tmp1 + tmp6;
ptr[6] = tmp1 - tmp6;
ptr[2] = tmp2 + tmp5;
ptr[5] = tmp2 - tmp5;
ptr[4] = tmp3 + tmp4;
ptr[3] = tmp3 - tmp4;
}
}
}
static inline void putQuadRGB24(uint8 *image, int *Yblk, int Cr, int Cb)
{
int Y, R, G, B;
R = MULR(Cr);
G = MULG2(Cb, Cr);
B = MULB(Cb);
Y = MULY(Yblk[0]);
image[0 * 3 + 0] = CLAMP_SCALE8(Y + R);
image[0 * 3 + 1] = CLAMP_SCALE8(Y + G);
image[0 * 3 + 2] = CLAMP_SCALE8(Y + B);
Y = MULY(Yblk[1]);
image[1 * 3 + 0] = CLAMP_SCALE8(Y + R);
image[1 * 3 + 1] = CLAMP_SCALE8(Y + G);
image[1 * 3 + 2] = CLAMP_SCALE8(Y + B);
Y = MULY(Yblk[8]);
image[16 * 3 + 0] = CLAMP_SCALE8(Y + R);
image[16 * 3 + 1] = CLAMP_SCALE8(Y + G);
image[16 * 3 + 2] = CLAMP_SCALE8(Y + B);
Y = MULY(Yblk[9]);
image[17 * 3 + 0] = CLAMP_SCALE8(Y + R);
image[17 * 3 + 1] = CLAMP_SCALE8(Y + G);
image[17 * 3 + 2] = CLAMP_SCALE8(Y + B);
}
inline void YUV2RGB24(int32 *blk, uint8 *image)
{
int x, y;
int *Yblk = blk + 64 * 2;
int *Crblk = blk;
int *Cbblk = blk + 64;
for (y = 0; y < 16; y += 2, Crblk += 4, Cbblk += 4, Yblk += 8, image += 8 * 3 * 3)
{
if (y == 8) Yblk += 64;
for (x = 0; x < 4; x++, image += 6, Crblk++, Cbblk++, Yblk += 2)
{
putQuadRGB24(image, Yblk, *Crblk, *Cbblk);
putQuadRGB24(image + 8 * 3, Yblk + 64, *(Crblk + 4), *(Cbblk + 4));
}
}
}
virtual bool decodeVideo(Color32 *pixels)
{
curVideoChunk++; curVideoChunk++;
while (curVideoChunk >= videoChunksCount) { while (curVideoChunk >= videoChunksCount)
if (!nextChunk()) { {
if (!nextChunk())
{
return false; return false;
} }
} }
@@ -1038,51 +1217,55 @@ struct Video {
BitStream bs(chunk->data + 8, chunk->size - 8); // make bitstream without frame header BitStream bs(chunk->data + 8, chunk->size - 8); // make bitstream without frame header
int16 block[6][64]; // Cr, Cb, YTL, YTR, YBL, YBR int32 qscale = chunk->qscale;
for (int bX = 0; bX < width / 16; bX++) {
for (int bY = 0; bY < height / 16; bY++) {
memset(block, 0, sizeof(block));
for (int i = 0; i < 6; i++) { int32 blocks[64 * 6]; // Cr, Cb, YTL, YTR, YBL, YBR
bool nonZero = false; for (int32 bX = 0; bX < width / 16; bX++)
{
for (int32 bY = 0; bY < height / 16; bY++)
{
memset(blocks, 0, sizeof(blocks));
int16 *channel = block[i]; for (int i = 0; i < 6; i++)
channel[0] = bs.readU(10); {
if (channel[0]) { int32* block = blocks + i * 64;
if (channel[0] & 0x200) {
channel[0] -= 0x400; int16 dc = bs.readU(10);
} if (dc & 0x200) {
channel[0] = channel[0] * STR_QUANTIZATION[0]; // DC dc -= 0x400;
nonZero = true;
} }
block[0] = SCALER(dc * STR_QTABLE[0], AAN_EXTRA - 3);
int32 used_col = 0;
int16 skip, ac; int16 skip, ac;
int index = 0; int32 index = 0;
while (readCode(bs, skip, ac)) { while (readCode(bs, skip, ac))
index += 1 + skip; {
index += skip + 1;
ASSERT(index < 64); ASSERT(index < 64);
int zIndex = STR_ZIG_ZAG[index]; block[STR_ZSCAN[index]] = SCALER(ac * STR_QTABLE[index] * qscale, AAN_EXTRA);
channel[zIndex] = (ac * STR_QUANTIZATION[zIndex] * chunk->qscale + 4) >> 3;
nonZero = true; used_col |= (STR_ZSCAN[index] > 7) ? 1 << (STR_ZSCAN[index] & 7) : 0;
} }
if (nonZero) if (index == 0) used_col = -1;
IDCT(channel);
IDCT(block, used_col);
} }
Color24 pix[16 * 16];
YUV2RGB24(blocks, (uint8*)pix);
int32 i = 0;
Color32 *blockPixels = pixels + (width * bY * 16 + bX * 16); Color32 *blockPixels = pixels + (width * bY * 16 + bX * 16);
for (int y = 0; y < 16; y++)
for (uint32 i = 0; i < 8 * 8; i++) { {
int x = (i % 8) * 2; for (int x = 0; x < 16; x++)
int y = (i / 8) * 2; {
int j = (x & 7) + (y & 7) * 8; blockPixels[y * width + x] = pix[i++];
}
Color32 *c = blockPixels + (width * y + x);
int16 *b = block[(x < 8) ? ((y < 8) ? 2 : 4) : ((y < 8) ? 3 : 5)];
Color32::YCbCr_T871_420(b[j] + 128, b[j + 1] + 128, b[j + 8] + 128, b[j + 8 + 1] + 128, block[1][i], block[0][i], 4,
c[0], c[1], c[width], c[width + 1]);
} }
} }
} }
@@ -1092,34 +1275,40 @@ struct Video {
return true; return true;
} }
virtual int decode(Sound::Frame *frames, int count) { bool getNextAudioStream()
{
curAudioChunk++;
while (curAudioChunk >= audioChunksCount)
{
if (!nextChunk())
{
curAudioChunk--;
return false;
}
}
AudioChunk *chunk = audioChunks + (curAudioChunk % MAX_CHUNKS);
ASSERT(chunk->size > 0);
audioDecoder->processSector(chunk->data);
return true;
}
static bool audioNextBlockCallback(void* userData)
{
return ((STR*)userData)->getNextAudioStream();
}
virtual int decode(Sound::Frame *frames, int count)
{
#ifdef NO_VIDEO #ifdef NO_VIDEO
return 0; return 0;
#else #else
if (!audioDecoder) return 0; if (!audioDecoder) return 0;
Sound::XA *xa = (Sound::XA*)audioDecoder; Sound::XA *xa = (Sound::XA*)audioDecoder;
int i = 0; int ret = audioDecoder->decode(frames, count);
while (i < count) { if (ret < count) {
if (xa->pos >= COUNT(xa->buffer)) { memset(frames + ret, 0, (count - ret) * sizeof(Sound::Frame));
curAudioChunk++;
while (curAudioChunk >= audioChunksCount) {
if (!nextChunk()) {
curAudioChunk--;
memset(frames, 0, count * sizeof(Sound::Frame));
return count;
}
}
}
AudioChunk *chunk = audioChunks + (curAudioChunk % MAX_CHUNKS);
ASSERT(chunk->size > 0);
Stream *memStream = new Stream(NULL, chunk->data, AUDIO_SECTOR_SIZE);
audioDecoder->stream = memStream;
i += audioDecoder->decode(&frames[i], count - i);
delete memStream;
} }
return count; return count;
@@ -1298,7 +1487,7 @@ struct Video {
} }
} }
Video(Stream *stream, TR::LevelID id) : sample(NULL), decoder(NULL), stepTimer(0.0f), time(0.0f), isPlaying(false) { Video(Stream *stream, TR::LevelID id) : sample(NULL), decoder(NULL), stepTimer(0.0f), time(0.0f), isPlaying(false), needUpdate(false) {
frameTex[0] = frameTex[1] = NULL; frameTex[0] = frameTex[1] = NULL;
if (!stream) return; if (!stream) return;
@@ -1323,12 +1512,16 @@ struct Video {
frameData = new Color32[decoder->width * decoder->height]; frameData = new Color32[decoder->width * decoder->height];
memset(frameData, 0, decoder->width * decoder->height * sizeof(Color32)); memset(frameData, 0, decoder->width * decoder->height * sizeof(Color32));
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++) {
frameTex[i] = new Texture(decoder->width, decoder->height, 1, FMT_RGBA, OPT_DYNAMIC, frameData); frameTex[i] = new Texture(decoder->width, decoder->height, 1, FMT_RGBA, OPT_DYNAMIC, frameData);
}
if (!TR::getVideoTrack(id, playAsync, this)) { if (!TR::getVideoTrack(id, playAsync, this)) {
sample = Sound::play(decoder); sample = Sound::play(decoder);
sample->pitch = pitch; sample->pitch = pitch;
if (sample) {
sample->pitch = pitch;
}
} }
step = 1.0f / decoder->fps; step = 1.0f / decoder->fps;