1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-07-30 18:00:24 +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
#undef OS_PTHREAD_MT
//#define USE_LIBVORBIS // TODO crash
#elif __SWITCH__
#define _OS_SWITCH 1
#define _GAPI_GL 1
@@ -259,10 +261,10 @@ namespace Core {
struct Mutex {
void *obj;
Mutex() { obj = osMutexInit(); }
~Mutex() { osMutexFree(obj); }
void lock() { osMutexLock(obj); }
void unlock() { osMutexUnlock(obj); }
Mutex() { obj = osMutexInit(); }
~Mutex() { if (obj) osMutexFree(obj); }
void lock() { if (obj) osMutexLock(obj); }
void unlock() { if (obj) osMutexUnlock(obj); }
};
struct Lock {
@@ -1009,7 +1011,7 @@ namespace Core {
#ifdef _OS_PSV
settings.detail.setFilter (Core::Settings::HIGH);
settings.detail.setLighting (Core::Settings::LOW);
settings.detail.setShadows (Core::Settings::LOW);
settings.detail.setShadows (Core::Settings::MEDIUM);
settings.detail.setWater (Core::Settings::MEDIUM);
#endif
@@ -1069,7 +1071,7 @@ namespace Core {
GAPI::discardTarget(!(active.targetOp & RT_STORE_COLOR), !(active.targetOp & RT_STORE_DEPTH));
GAPI::Texture *target = reqTarget.texture;
uint32 face = reqTarget.face;
uint32 face = reqTarget.face;
if (target != active.target || face != active.targetFace) {
Core::stats.rt++;

View File

@@ -548,6 +548,9 @@ namespace Debug {
for (int i = 0; i < level.roomsCount; i++)
for (int j = 0; j < level.rooms[i].lightsCount; 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));
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 isTarget = (opt & OPT_TARGET) != 0;
bool isDynamic = (opt & OPT_DYNAMIC) != 0;
bool isShadow = fmt == FMT_SHADOW;
bool isTiled = isTarget;
bool isSwizzled = !isDynamic && !isTiled && filter;
@@ -814,7 +813,7 @@ namespace GAPI {
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);
if (data && this->data) {
@@ -858,7 +857,7 @@ namespace GAPI {
if (opt & OPT_REPEAT) {
addrMode = SCE_GXM_TEXTURE_ADDR_REPEAT;
} 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);
@@ -1365,6 +1364,7 @@ namespace GAPI {
}
void clear(bool color, bool depth) {
// TODO save and restore states
int oColorMask = colorMask;
int oBlendMode = blendMode;
bool oDepthTest = depthTest;

View File

@@ -2304,7 +2304,7 @@ struct Lara : Character {
if (stand == STAND_UNDERWATER || stand == STAND_ONWATER)
return stand;
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();
return STAND_UNDERWATER;
}
@@ -2326,7 +2326,7 @@ struct Lara : Character {
return 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();
pos.y = waterLevel + waterDepth;
game->playSound(TR::SND_WATER_SPLASH, pos, Sound::PAN);

View File

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

View File

@@ -203,8 +203,8 @@ void joyUpdate() {
if (_XInputGetState(j, &state) == ERROR_SUCCESS) {
//osJoyVibrate(j, state.Gamepad.bLeftTrigger / 255.0f, state.Gamepad.bRightTrigger / 255.0f); // vibration test
Input::setJoyPos(j, jkL, joyDir(joyAxis( state.Gamepad.sThumbLX, -32768, 32767),
joyAxis(-state.Gamepad.sThumbLY, -32768, 32767)));
Input::setJoyPos(j, jkL, joyDir(joyAxis( state.Gamepad.sThumbLX, -32768, 32767),
joyAxis(-state.Gamepad.sThumbLY, -32768, 32767)));
Input::setJoyPos(j, jkR, joyDir(joyAxis( state.Gamepad.sThumbRX, -32768, 32767),
joyAxis(-state.Gamepad.sThumbRY, -32768, 32767)));
Input::setJoyPos(j, jkLT, vec2(state.Gamepad.bLeftTrigger / 255.0f, 0.0f));

View File

@@ -65,16 +65,16 @@ struct VS_INPUT {
Texture2D sReflect : register(t2);
Texture2D sShadow : register(t3);
Texture2D sMask : register(t4);
#define SAMPLE_2D(T,uv) T.Sample(smpDefault, uv)
#define SAMPLE_2D_POINT(T,uv) T.Sample(smpPoint, 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_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_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)
#define POSITION SV_POSITION
#else
@@ -95,7 +95,13 @@ struct VS_INPUT {
#define SAMPLE_2D_LINEAR(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_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_CUBE(T,uv) texCUBE(T, uv)
@@ -122,7 +128,7 @@ float4 uContacts[MAX_CONTACTS] : register( c98 );
// options for compose, shadow, ambient passes
#ifdef _GAPI_GXM
//#define OPT_AMBIENT
//#define OPT_SHADOW
#define OPT_SHADOW
//#define OPT_CONTACT
//#define OPT_CAUSTICS
#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)); //
lightProj.xyz *= factor;
lightProj.xyz /= lightProj.w;
lightProj.z -= SHADOW_CONST_BIAS * SHADOW_TEXEL;
lightProj.z -= SHADOW_CONST_BIAS * SHADOW_TEXEL * lightProj.w;
#ifdef _GAPI_GXM
float rShadow = f1tex2Dproj(sShadow, lightProj);
#elif _GAPI_D3D11
float rShadow = sShadow.SampleCmpLevelZero(smpCmp, lightProj.xy, lightProj.z);
#else
float rShadow = 1.0;
#endif
float rShadow = SAMPLE_SHADOW(sShadow, lightProj);
float fade = saturate(dot(lightVec, lightVec));
return rShadow + (1.0 - rShadow) * fade;

View File

@@ -22,9 +22,9 @@ VS_OUTPUT main(VS_INPUT In) {
Out.normal.xyz = mulQuat(rBasisRot, normalize(In.aNormal.xyz));
Out.normal.w = saturate(1.0 / exp(length(Out.viewVec.xyz)));
Out.pos = mul(uViewProj, float4(coord, rBasisPos.w));
return Out;
}
@@ -35,9 +35,9 @@ float4 main(VS_OUTPUT In) : COLOR0 {
float4 color = SAMPLE_CUBE(sDiffuse, normalize(rv));
color *= uMaterial;
color.xyz = saturate(color.xyz);
applyFog(color.xyz, In.normal.w);
color.xyz = saturate(color.xyz);
applyFog(color.xyz, In.normal.w);
return color;
}

View File

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

View File

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

View File

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