mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-30 04:40:39 +00:00
ALL: synced with scummvm
This commit is contained in:
parent
0116625b75
commit
adcb0b8383
@ -403,7 +403,7 @@ public:
|
||||
}
|
||||
|
||||
int readBuffer(int16 *buffer, const int numSamples) {
|
||||
// Cap us off so we don't read past _totalSamples
|
||||
// Cap us off so we don't read past _totalSamples
|
||||
int samplesRead = _parentStream->readBuffer(buffer, MIN<int>(numSamples, _totalSamples - _samplesRead));
|
||||
_samplesRead += samplesRead;
|
||||
return samplesRead;
|
||||
@ -414,7 +414,7 @@ public:
|
||||
int getRate() const { return _parentStream->getRate(); }
|
||||
|
||||
private:
|
||||
int getChannels() const { return isStereo() ? 2 : 1; }
|
||||
int getChannels() const { return isStereo() ? 2 : 1; }
|
||||
|
||||
AudioStream *_parentStream;
|
||||
DisposeAfterUse::Flag _disposeAfterUse;
|
||||
|
@ -23,6 +23,7 @@
|
||||
/**
|
||||
* @file
|
||||
* Sound decoder used in engines:
|
||||
* - pegasus
|
||||
* - saga
|
||||
* - sci
|
||||
* - sword1
|
||||
|
@ -240,7 +240,7 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
|
||||
devStr = ConfMan.hasKey("gm_device") ? ConfMan.get("gm_device") : Common::String("null");
|
||||
else
|
||||
devStr = "auto";
|
||||
|
||||
|
||||
// Default to Null device here, since we also register a default null setting for
|
||||
// the MT32 or GM device in the config manager.
|
||||
hdl = getDeviceHandle(devStr.empty() ? Common::String("null") : devStr);
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "mt32emu.h"
|
||||
#include "AReverbModel.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
namespace MT32Emu {
|
||||
|
||||
// Default reverb settings for modes 0-2
|
||||
|
||||
@ -235,3 +235,5 @@ void AReverbModel::process(const float *inLeft, const float *inRight, float *out
|
||||
outRight++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,15 +20,14 @@
|
||||
#include "mt32emu.h"
|
||||
#include "DelayReverb.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
// CONFIRMED: The values below are found via analysis of digital samples. Checked with all time and level combinations.
|
||||
// Obviously:
|
||||
// rightDelay = (leftDelay - 2) * 2 + 2
|
||||
// echoDelay = rightDelay - 1
|
||||
// Leaving these separate in case it's useful for work on other reverb modes...
|
||||
const Bit32u REVERB_TIMINGS[8][3]= {
|
||||
static const Bit32u REVERB_TIMINGS[8][3]= {
|
||||
// {leftDelay, rightDelay, feedbackDelay}
|
||||
{402, 802, 801},
|
||||
{626, 1250, 1249},
|
||||
@ -40,7 +39,7 @@ const Bit32u REVERB_TIMINGS[8][3]= {
|
||||
{8002, 16002, 16001}
|
||||
};
|
||||
|
||||
const float REVERB_FADE[8] = {0.0f, -0.049400051f, -0.08220577f, -0.131861118f, -0.197344907f, -0.262956344f, -0.345162114f, -0.509508615f};
|
||||
static const float REVERB_FADE[8] = {0.0f, -0.049400051f, -0.08220577f, -0.131861118f, -0.197344907f, -0.262956344f, -0.345162114f, -0.509508615f};
|
||||
const float REVERB_FEEDBACK67 = -0.629960524947437f; // = -EXP2F(-2 / 3)
|
||||
const float REVERB_FEEDBACK = -0.682034520443118f; // = -EXP2F(-53 / 96)
|
||||
const float LPF_VALUE = 0.594603558f; // = EXP2F(-0.75f)
|
||||
@ -148,3 +147,5 @@ bool DelayReverb::isActive() const {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "freeverb.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
namespace MT32Emu {
|
||||
|
||||
FreeverbModel::FreeverbModel(float useScaleTuning, float useFiltVal, float useWet, Bit8u useRoom, float useDamp) {
|
||||
freeverb = NULL;
|
||||
@ -76,3 +76,5 @@ bool FreeverbModel::isActive() const {
|
||||
// FIXME: Not bothering to do this properly since we'll be replacing Freeverb soon...
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -79,11 +79,12 @@ LA32Ramp::LA32Ramp() :
|
||||
|
||||
void LA32Ramp::startRamp(Bit8u target, Bit8u increment) {
|
||||
// CONFIRMED: From sample analysis, this appears to be very accurate.
|
||||
// FIXME: We could use a table for this in future
|
||||
if (increment == 0) {
|
||||
largeIncrement = 0;
|
||||
} else {
|
||||
largeIncrement = (unsigned int)(EXP2F(((increment & 0x7F) + 24) / 8.0f) + 0.125f);
|
||||
// Using integer argument here, no precision loss:
|
||||
// (unsigned int)(EXP2F(((increment & 0x7F) + 24) / 8.0f) + 0.125f)
|
||||
largeIncrement = (unsigned int)(EXP2I(((increment & 0x7F) + 24) << 9) + 0.125f);
|
||||
}
|
||||
descending = (increment & 0x80) != 0;
|
||||
if (descending) {
|
||||
|
@ -411,7 +411,7 @@ void RhythmPart::noteOn(unsigned int midiKey, unsigned int velocity) {
|
||||
// According to info from Mok, keyShift does not appear to affect anything on rhythm part on LAPC-I, but may do on MT-32 - needs investigation
|
||||
synth->printDebug(" Patch: (timbreGroup %u), (timbreNum %u), (keyShift %u), fineTune %u, benderRange %u, assignMode %u, (reverbSwitch %u)", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch);
|
||||
synth->printDebug(" PatchTemp: outputLevel %u, (panpot %u)", patchTemp->outputLevel, patchTemp->panpot);
|
||||
synth->printDebug(" RhythmTemp: timbre %u, outputLevel %u, panpot %u, reverbSwitch %u", rhythmTemp[drumNum].timbre, rhythmTemp[drumNum].outputLevel, rhythmTemp[drumNum].panpot, rhythmTemp[drumNum].reverbSwitch);
|
||||
synth->printDebug(" RhythmTemp: timbre %u, outputLevel %u, panpot %u, reverbSwitch %u", rhythmTemp[drumNum].timbre, rhythmTemp[drumNum].outputLevel, rhythmTemp[drumNum].panpot, rhythmTemp[drumNum].reverbSwitch);
|
||||
#endif
|
||||
#endif
|
||||
playPoly(drumCache[drumNum], &rhythmTemp[drumNum], midiKey, key, velocity);
|
||||
@ -544,9 +544,12 @@ void Part::allNotesOff() {
|
||||
// should treat the hold pedal as usual.
|
||||
for (Common::List<Poly *>::iterator polyIt = activePolys.begin(); polyIt != activePolys.end(); polyIt++) {
|
||||
Poly *poly = *polyIt;
|
||||
// FIXME: This has special handling of key 0 in NoteOff that Mok has not yet confirmed
|
||||
// applies to AllNotesOff.
|
||||
poly->noteOff(holdpedal);
|
||||
// FIXME: This has special handling of key 0 in NoteOff that Mok has not yet confirmed applies to AllNotesOff.
|
||||
// if (poly->canSustain() || poly->getKey() == 0) {
|
||||
// FIXME: The real devices are found to be ignoring non-sustaining polys while processing AllNotesOff. Need to be confirmed.
|
||||
if (poly->canSustain()) {
|
||||
poly->noteOff(holdpedal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
namespace MT32Emu {
|
||||
|
||||
#ifdef INACCURATE_SMOOTH_PAN
|
||||
// Mok wanted an option for smoother panning, and we love Mok.
|
||||
@ -133,6 +133,25 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
|
||||
stereoVolume.leftVol = panVal / 7.0f;
|
||||
stereoVolume.rightVol = 1.0f - stereoVolume.leftVol;
|
||||
|
||||
// SEMI-CONFIRMED: From sample analysis:
|
||||
// Found that timbres with 3 or 4 partials (i.e. one using two partial pairs) are mixed in two different ways.
|
||||
// Either partial pairs are added or subtracted, it depends on how the partial pairs are allocated.
|
||||
// It seems that partials are grouped into quarters and if the partial pairs are allocated in different quarters the subtraction happens.
|
||||
// Though, this matters little for the majority of timbres, it becomes crucial for timbres which contain several partials that sound very close.
|
||||
// In this case that timbre can sound totally different depending of the way it is mixed up.
|
||||
// Most easily this effect can be displayed with the help of a special timbre consisting of several identical square wave partials (3 or 4).
|
||||
// Say, it is 3-partial timbre. Just play any two notes simultaneously and the polys very probably are mixed differently.
|
||||
// Moreover, the partial allocator retains the last partial assignment it did and all the subsequent notes will sound the same as the last released one.
|
||||
// The situation is better with 4-partial timbres since then a whole quarter is assigned for each poly. However, if a 3-partial timbre broke the normal
|
||||
// whole-quarter assignment or after some partials got aborted, even 4-partial timbres can be found sounding differently.
|
||||
// This behaviour is also confirmed with two more special timbres: one with identical sawtooth partials, and one with PCM wave 02.
|
||||
// For my personal taste, this behaviour rather enriches the sounding and should be emulated.
|
||||
// Also, the current partial allocator model probably needs to be refined.
|
||||
if (debugPartialNum & 8) {
|
||||
stereoVolume.leftVol = -stereoVolume.leftVol;
|
||||
stereoVolume.rightVol = -stereoVolume.rightVol;
|
||||
}
|
||||
|
||||
if (patchCache->PCMPartial) {
|
||||
pcmNum = patchCache->pcm;
|
||||
if (synth->controlROMMap->pcmCount > 128) {
|
||||
@ -149,7 +168,7 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
|
||||
}
|
||||
|
||||
// CONFIRMED: pulseWidthVal calculation is based on information from Mok
|
||||
pulseWidthVal = (poly->getVelocity() - 64) * (patchCache->srcPartial.wg.pulseWidthVeloSensitivity - 7) + synth->tables.pulseWidth100To255[patchCache->srcPartial.wg.pulseWidth];
|
||||
pulseWidthVal = (poly->getVelocity() - 64) * (patchCache->srcPartial.wg.pulseWidthVeloSensitivity - 7) + Tables::getInstance().pulseWidth100To255[patchCache->srcPartial.wg.pulseWidth];
|
||||
if (pulseWidthVal < 0) {
|
||||
pulseWidthVal = 0;
|
||||
} else if (pulseWidthVal > 255) {
|
||||
@ -175,6 +194,7 @@ float Partial::getPCMSample(unsigned int position) {
|
||||
}
|
||||
|
||||
unsigned long Partial::generateSamples(float *partialBuf, unsigned long length) {
|
||||
const Tables &tables = Tables::getInstance();
|
||||
if (!isActive() || alreadyOutputed) {
|
||||
return 0;
|
||||
}
|
||||
@ -197,6 +217,9 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
deactivate();
|
||||
break;
|
||||
}
|
||||
|
||||
Bit16u pitch = tvp->nextPitch();
|
||||
|
||||
// SEMI-CONFIRMED: From sample analysis:
|
||||
// (1) Tested with a single partial playing PCM wave 77 with pitchCoarse 36 and no keyfollow, velocity follow, etc.
|
||||
// This gives results within +/- 2 at the output (before any DAC bitshifting)
|
||||
@ -206,10 +229,17 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
// positive amps, so negative still needs to be explored, as well as lower levels.
|
||||
//
|
||||
// Also still partially unconfirmed is the behaviour when ramping between levels, as well as the timing.
|
||||
float amp = EXP2F((32772 - ampRampVal / 2048) / -2048.0f);
|
||||
|
||||
Bit16u pitch = tvp->nextPitch();
|
||||
float freq = synth->tables.pitchToFreq[pitch];
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
float amp = EXP2F((32772 - ampRampVal / 2048) / -2048.0f);
|
||||
float freq = EXP2F(pitch / 4096.0f - 16.0f) * 32000.0f;
|
||||
#else
|
||||
static const float ampFactor = EXP2F(32772 / -2048.0f);
|
||||
float amp = EXP2I(ampRampVal >> 10) * ampFactor;
|
||||
|
||||
static const float freqFactor = EXP2F(-16.0f) * 32000.0f;
|
||||
float freq = EXP2I(pitch) * freqFactor;
|
||||
#endif
|
||||
|
||||
if (patchCache->PCMPartial) {
|
||||
// Render PCM waveform
|
||||
@ -225,8 +255,14 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
|
||||
// Linear interpolation
|
||||
float firstSample = synth->pcmROMData[pcmAddr + intPCMPosition];
|
||||
float nextSample = getPCMSample(intPCMPosition + 1);
|
||||
sample = firstSample + (nextSample - firstSample) * (pcmPosition - intPCMPosition);
|
||||
// We observe that for partial structures with ring modulation the interpolation is not applied to the slave PCM partial.
|
||||
// It's assumed that the multiplication circuitry intended to perform the interpolation on the slave PCM partial
|
||||
// is borrowed by the ring modulation circuit (or the LA32 chip has a similar lack of resources assigned to each partial pair).
|
||||
if (pair == NULL || mixType == 0 || structurePosition == 0) {
|
||||
sample = firstSample + (getPCMSample(intPCMPosition + 1) - firstSample) * (pcmPosition - intPCMPosition);
|
||||
} else {
|
||||
sample = firstSample;
|
||||
}
|
||||
|
||||
float newPCMPosition = pcmPosition + positionDelta;
|
||||
if (pcmWave->loop) {
|
||||
@ -247,8 +283,8 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
// res corresponds to a value set in an LA32 register
|
||||
Bit8u res = patchCache->srcPartial.tvf.resonance + 1;
|
||||
|
||||
// EXP2F(1.0f - (32 - res) / 4.0f);
|
||||
float resAmp = synth->tables.resAmpMax[res];
|
||||
// Using tiny exact table for computation of EXP2F(1.0f - (32 - res) / 4.0f)
|
||||
float resAmp = tables.resAmpMax[res];
|
||||
|
||||
// The cutoffModifier may not be supposed to be directly added to the cutoff -
|
||||
// it may for example need to be multiplied in some way.
|
||||
@ -268,7 +304,8 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
cosineLen *= EXP2F((cutoffVal - 128.0f) / -16.0f); // found from sample analysis
|
||||
#else
|
||||
cosineLen *= synth->tables.cutoffToCosineLen[Bit32u((cutoffVal - 128.0f) * 8.0f)];
|
||||
static const float cosineLenFactor = EXP2F(128.0f / -16.0f);
|
||||
cosineLen *= EXP2I(Bit32u((256.0f - cutoffVal) * 256.0f)) * cosineLenFactor;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -281,7 +318,7 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
|
||||
float pulseLen = 0.5f;
|
||||
if (pulseWidthVal > 128) {
|
||||
pulseLen += synth->tables.pulseLenFactor[pulseWidthVal - 128];
|
||||
pulseLen += tables.pulseLenFactor[pulseWidthVal - 128];
|
||||
}
|
||||
pulseLen *= waveLen;
|
||||
|
||||
@ -303,7 +340,7 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
resAmp *= sinf(FLOAT_PI * (cutoffVal - 128.0f) / 32.0f);
|
||||
#else
|
||||
resAmp *= synth->tables.sinf10[Bit32u(64 * (cutoffVal - 128.0f))];
|
||||
resAmp *= tables.sinf10[Bit32u(64 * (cutoffVal - 128.0f))];
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -314,7 +351,7 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
sample = -cosf(FLOAT_PI * relWavePos / cosineLen);
|
||||
#else
|
||||
sample = -synth->tables.sinf10[Bit32u(2048.0f * relWavePos / cosineLen) + 1024];
|
||||
sample = -tables.sinf10[Bit32u(2048.0f * relWavePos / cosineLen) + 1024];
|
||||
#endif
|
||||
} else
|
||||
|
||||
@ -328,7 +365,7 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
sample = cosf(FLOAT_PI * (relWavePos - (cosineLen + hLen)) / cosineLen);
|
||||
#else
|
||||
sample = synth->tables.sinf10[Bit32u(2048.0f * (relWavePos - (cosineLen + hLen)) / cosineLen) + 1024];
|
||||
sample = tables.sinf10[Bit32u(2048.0f * (relWavePos - (cosineLen + hLen)) / cosineLen) + 1024];
|
||||
#endif
|
||||
} else {
|
||||
|
||||
@ -343,7 +380,8 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
sample *= EXP2F(-0.125f * (128.0f - cutoffVal));
|
||||
#else
|
||||
sample *= synth->tables.cutoffToFilterAmp[Bit32u(cutoffVal * 8.0f)];
|
||||
static const float cutoffAttenuationFactor = EXP2F(-0.125f * 128.0f);
|
||||
sample *= EXP2I(Bit32u(512.0f * cutoffVal)) * cutoffAttenuationFactor;
|
||||
#endif
|
||||
} else {
|
||||
|
||||
@ -363,11 +401,17 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
resSample *= sinf(FLOAT_PI * relWavePos / cosineLen);
|
||||
#else
|
||||
resSample *= synth->tables.sinf10[Bit32u(2048.0f * relWavePos / cosineLen) & 4095];
|
||||
resSample *= tables.sinf10[Bit32u(2048.0f * relWavePos / cosineLen) & 4095];
|
||||
#endif
|
||||
|
||||
// Resonance sine amp
|
||||
float resAmpFade = EXP2F(-synth->tables.resAmpFadeFactor[res >> 2] * (relWavePos / cosineLen)); // seems to be exact
|
||||
float resAmpFadeLog2 = -tables.resAmpFadeFactor[res >> 2] * (relWavePos / cosineLen); // seems to be exact
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
float resAmpFade = EXP2F(resAmpFadeLog2);
|
||||
#else
|
||||
static const float resAmpFadeFactor = EXP2F(-30.0f);
|
||||
float resAmpFade = (resAmpFadeLog2 < -30.0f) ? 0.0f : EXP2I(Bit32u((30.0f + resAmpFadeLog2) * 4096.0f)) * resAmpFadeFactor;
|
||||
#endif
|
||||
|
||||
// Now relWavePos set negative to the left from center of any cosine
|
||||
relWavePos = wavePos;
|
||||
@ -388,7 +432,7 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
resAmpFade *= 0.5f * (1.0f - cosf(FLOAT_PI * relWavePos / (0.5f * cosineLen)));
|
||||
#else
|
||||
resAmpFade *= 0.5f * (1.0f + synth->tables.sinf10[Bit32s(2048.0f * relWavePos / (0.5f * cosineLen)) + 3072]);
|
||||
resAmpFade *= 0.5f * (1.0f + tables.sinf10[Bit32s(2048.0f * relWavePos / (0.5f * cosineLen)) + 3072]);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -400,7 +444,7 @@ unsigned long Partial::generateSamples(float *partialBuf, unsigned long length)
|
||||
#if MT32EMU_ACCURATE_WG == 1
|
||||
sample *= cosf(FLOAT_2PI * wavePos / waveLen);
|
||||
#else
|
||||
sample *= synth->tables.sinf10[(Bit32u(4096.0f * wavePos / waveLen) & 4095) + 1024];
|
||||
sample *= tables.sinf10[(Bit32u(4096.0f * wavePos / waveLen) & 4095) + 1024];
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -516,10 +560,9 @@ bool Partial::produceOutput(float *leftBuf, float *rightBuf, unsigned long lengt
|
||||
}
|
||||
}
|
||||
if (numGenerated > pairNumGenerated) {
|
||||
if (mixType == 1) {
|
||||
mixBuffersRingMix(partialBuf + pairNumGenerated, NULL, numGenerated - pairNumGenerated);
|
||||
} else {
|
||||
mixBuffersRing(partialBuf + pairNumGenerated, NULL, numGenerated - pairNumGenerated);
|
||||
if (mixType == 2) {
|
||||
numGenerated = pairNumGenerated;
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -555,3 +598,5 @@ void Partial::startDecayAll() {
|
||||
tvp->startDecay();
|
||||
tvf->startDecay();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ private:
|
||||
const int debugPartialNum; // Only used for debugging
|
||||
// Number of the sample currently being rendered by generateSamples(), or 0 if no run is in progress
|
||||
// This is only kept available for debugging purposes.
|
||||
unsigned long sampleNum;
|
||||
unsigned long sampleNum;
|
||||
|
||||
int ownerPart; // -1 if unassigned
|
||||
int mixType;
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "mt32emu.h"
|
||||
#include "PartialManager.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
namespace MT32Emu {
|
||||
|
||||
PartialManager::PartialManager(Synth *useSynth, Part **useParts) {
|
||||
synth = useSynth;
|
||||
@ -148,7 +148,7 @@ bool PartialManager::abortFirstPolyPreferHeldWhereReserveExceeded(int minPart) {
|
||||
bool PartialManager::freePartials(unsigned int needed, int partNum) {
|
||||
// CONFIRMED: Barring bugs, this matches the real LAPC-I according to information from Mok.
|
||||
|
||||
// BUG: There's a bug in the LAPC-I implementation:
|
||||
// BUG: There's a bug in the LAPC-I implementation:
|
||||
// When allocating for rhythm part, or when allocating for a part that is using fewer partials than it has reserved,
|
||||
// held and playing polys on the rhythm part can potentially be aborted before releasing polys on the rhythm part.
|
||||
// This bug isn't present on MT-32.
|
||||
@ -248,3 +248,5 @@ const Partial *PartialManager::getPartial(unsigned int partialNum) const {
|
||||
}
|
||||
return partialTable[partialNum];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,6 +58,9 @@ bool Poly::noteOff(bool pedalHeld) {
|
||||
return false;
|
||||
}
|
||||
if (pedalHeld) {
|
||||
if (state == POLY_Held) {
|
||||
return false;
|
||||
}
|
||||
state = POLY_Held;
|
||||
} else {
|
||||
startDecay();
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
const ControlROMMap ControlROMMaps[7] = {
|
||||
static const ControlROMMap ControlROMMaps[7] = {
|
||||
// ID IDc IDbytes PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO, tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax
|
||||
{0x4014, 22, "\000 ver1.04 14 July 87 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A},
|
||||
{0x4014, 22, "\000 ver1.05 06 Aug, 87 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A},
|
||||
@ -423,7 +423,6 @@ bool Synth::open(SynthProperties &useProp) {
|
||||
#if MT32EMU_MONITOR_INIT
|
||||
printDebug("Initialising Constant Tables");
|
||||
#endif
|
||||
tables.init();
|
||||
#if !MT32EMU_REDUCE_REVERB_MEMORY
|
||||
for (int i = 0; i < 4; i++) {
|
||||
reverbModels[i]->open(useProp.sampleRate);
|
||||
@ -627,6 +626,11 @@ void Synth::playMsg(Bit32u msg) {
|
||||
return;
|
||||
}
|
||||
playMsgOnPart(part, code, note, velocity);
|
||||
|
||||
// This ensures minimum 1-sample delay between sequential MIDI events
|
||||
// Without this, a sequence of NoteOn and immediately succeeding NoteOff messages is always silent
|
||||
// Technically, it's also impossible to send events through the MIDI interface faster than about each millisecond
|
||||
prerender();
|
||||
}
|
||||
|
||||
void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity) {
|
||||
@ -1156,7 +1160,7 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le
|
||||
DT(partial[x].tva.envLevel[0]); \
|
||||
DT(partial[x].tva.envLevel[1]); \
|
||||
DT(partial[x].tva.envLevel[2]); \
|
||||
DT(partial[x].tva.envLevel[3]);
|
||||
DT(partial[x].tva.envLevel[3]);
|
||||
|
||||
DTP(0);
|
||||
DTP(1);
|
||||
|
@ -321,7 +321,6 @@ private:
|
||||
|
||||
Bit32u renderedSampleCount;
|
||||
|
||||
Tables tables;
|
||||
|
||||
MemParams mt32ram, mt32default;
|
||||
|
||||
|
@ -154,7 +154,7 @@ void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartial
|
||||
|
||||
playing = true;
|
||||
|
||||
Tables *tables = &partial->getSynth()->tables;
|
||||
const Tables *tables = &Tables::getInstance();
|
||||
|
||||
int key = partial->getPoly()->getKey();
|
||||
int velocity = partial->getPoly()->getVelocity();
|
||||
@ -215,7 +215,7 @@ void TVA::recalcSustain() {
|
||||
return;
|
||||
}
|
||||
// We're sustaining. Recalculate all the values
|
||||
Tables *tables = &partial->getSynth()->tables;
|
||||
const Tables *tables = &Tables::getInstance();
|
||||
int newTarget = calcBasicAmp(tables, partial, system_, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
|
||||
newTarget += partialParam->tva.envLevel[3];
|
||||
// Since we're in TVA_PHASE_SUSTAIN at this point, we know that target has been reached and an interrupt fired, so we can rely on it being the current amp.
|
||||
@ -241,7 +241,7 @@ int TVA::getPhase() const {
|
||||
}
|
||||
|
||||
void TVA::nextPhase() {
|
||||
Tables *tables = &partial->getSynth()->tables;
|
||||
const Tables *tables = &Tables::getInstance();
|
||||
|
||||
if (phase >= TVA_PHASE_DEAD || !playing) {
|
||||
partial->getSynth()->printDebug("TVA::nextPhase(): Shouldn't have got here with phase %d, playing=%s", phase, playing ? "true" : "false");
|
||||
@ -274,7 +274,7 @@ void TVA::nextPhase() {
|
||||
}
|
||||
|
||||
int newTarget;
|
||||
int newIncrement;
|
||||
int newIncrement = 0;
|
||||
int envPointIndex = phase;
|
||||
|
||||
if (!allLevelsZeroFromNowOn) {
|
||||
|
@ -64,11 +64,11 @@ static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u
|
||||
int biasPoint = partialParam->tvf.biasPoint;
|
||||
if ((biasPoint & 0x40) == 0) {
|
||||
// biasPoint range here: 0 to 63
|
||||
int bias = biasPoint + 33 - key; // bias range here: -75 to 84
|
||||
int bias = biasPoint + 33 - key; // bias range here: -75 to 84
|
||||
if (bias > 0) {
|
||||
bias = -bias; // bias range here: -1 to -84
|
||||
baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -7140 to 7140
|
||||
// baseCutoff range now: -10164 to 10164
|
||||
// baseCutoff range now: -10164 to 10164
|
||||
}
|
||||
} else {
|
||||
// biasPoint range here: 64 to 127
|
||||
@ -117,7 +117,7 @@ void TVF::reset(const TimbreParam::PartialParam *newPartialParam, unsigned int b
|
||||
unsigned int key = partial->getPoly()->getKey();
|
||||
unsigned int velocity = partial->getPoly()->getVelocity();
|
||||
|
||||
Tables *tables = &partial->getSynth()->tables;
|
||||
const Tables *tables = &Tables::getInstance();
|
||||
|
||||
baseCutoff = calcBaseCutoff(newPartialParam, basePitch, key);
|
||||
#if MT32EMU_MONITOR_TVF >= 1
|
||||
@ -179,7 +179,7 @@ void TVF::startDecay() {
|
||||
}
|
||||
|
||||
void TVF::nextPhase() {
|
||||
Tables *tables = &partial->getSynth()->tables;
|
||||
const Tables *tables = &Tables::getInstance();
|
||||
int newPhase = phase + 1;
|
||||
|
||||
switch (newPhase) {
|
||||
|
@ -171,9 +171,14 @@ void TVP::updatePitch() {
|
||||
if (newPitch < 0) {
|
||||
newPitch = 0;
|
||||
}
|
||||
|
||||
// Note: Temporary #ifdef until we have proper "quirk" configuration
|
||||
// This is about right emulation of MT-32 GEN0 quirk exploited in Colonel's Bequest timbre "Lightning"
|
||||
#ifndef MT32EMU_QUIRK_PITCH_ENVELOPE_OVERFLOW_MT32
|
||||
if (newPitch > 59392) {
|
||||
newPitch = 59392;
|
||||
}
|
||||
#endif
|
||||
pitch = (Bit16u)newPitch;
|
||||
|
||||
// FIXME: We're doing this here because that's what the CM-32L does - we should probably move this somewhere more appropriate in future.
|
||||
|
@ -22,18 +22,14 @@
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
namespace MT32Emu {
|
||||
|
||||
Tables::Tables() {
|
||||
initialised = false;
|
||||
const Tables &Tables::getInstance() {
|
||||
static const Tables instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Tables::init() {
|
||||
if (initialised) {
|
||||
return;
|
||||
}
|
||||
initialised = true;
|
||||
|
||||
Tables::Tables() {
|
||||
int lf;
|
||||
for (lf = 0; lf <= 100; lf++) {
|
||||
// CONFIRMED:KG: This matches a ROM table found by Mok
|
||||
@ -83,19 +79,9 @@ void Tables::init() {
|
||||
pulseLenFactor[i] = (1.241857812f - pt) * pt; // seems to be 2 ^ (5 / 16) = 1.241857812f
|
||||
}
|
||||
|
||||
for (int i = 0; i < 65536; i++) {
|
||||
// Aka (slightly slower): EXP2F(pitchVal / 4096.0f - 16.0f) * 32000.0f
|
||||
pitchToFreq[i] = EXP2F(i / 4096.0f - 1.034215715f);
|
||||
}
|
||||
|
||||
// found from sample analysis
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
cutoffToCosineLen[i] = EXP2F(i / -128.0f);
|
||||
}
|
||||
|
||||
// found from sample analysis
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
cutoffToFilterAmp[i] = EXP2F(-0.125f * (128.0f - i / 8.0f));
|
||||
// The LA32 chip presumably has such a table inside as the internal computaions seem to be performed using fixed point math with 12-bit fractions
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
exp2[i] = EXP2F(i / 4096.0f);
|
||||
}
|
||||
|
||||
// found from sample analysis
|
||||
@ -117,3 +103,5 @@ void Tables::init() {
|
||||
sinf10[i] = sin(FLOAT_PI * i / 2048.0f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,14 +20,21 @@
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
// Sample rate to use in mixing
|
||||
const unsigned int SAMPLE_RATE = 32000;
|
||||
|
||||
const int MIDDLEC = 60;
|
||||
|
||||
class Synth;
|
||||
|
||||
class Tables {
|
||||
bool initialised;
|
||||
private:
|
||||
Tables();
|
||||
Tables(Tables &);
|
||||
|
||||
public:
|
||||
static const Tables &getInstance();
|
||||
|
||||
// Constant LUTs
|
||||
|
||||
// CONFIRMED: This is used to convert several parameters to amp-modifying values in the TVA envelope:
|
||||
@ -47,16 +54,11 @@ public:
|
||||
// CONFIRMED:
|
||||
Bit8u pulseWidth100To255[101];
|
||||
|
||||
float exp2[4096];
|
||||
float pulseLenFactor[128];
|
||||
float pitchToFreq[65536];
|
||||
float cutoffToCosineLen[1024];
|
||||
float cutoffToFilterAmp[1024];
|
||||
float resAmpMax[32];
|
||||
float resAmpFadeFactor[8];
|
||||
float sinf10[5120];
|
||||
|
||||
Tables();
|
||||
void init();
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ void revmodel::process(const float *inputL, const float *inputR, float *outputL,
|
||||
// Calculate output REPLACING anything already there
|
||||
*outputL = outL*wet1 + outR*wet2;
|
||||
*outputR = outR*wet1 + outL*wet2;
|
||||
|
||||
|
||||
inputL++;
|
||||
inputR++;
|
||||
outputL++;
|
||||
|
@ -52,6 +52,10 @@ static inline float EXP2F(float x) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline float EXP2I(unsigned int i) {
|
||||
return float(1 << (i >> 12)) * Tables::getInstance().exp2[i & 0x0FFF];
|
||||
}
|
||||
|
||||
static inline float EXP10F(float x) {
|
||||
return exp(FLOAT_LN_10 * x);
|
||||
}
|
||||
|
@ -59,9 +59,16 @@
|
||||
#define MT32EMU_MONITOR_TVA 0
|
||||
#define MT32EMU_MONITOR_TVF 0
|
||||
|
||||
|
||||
// 0: Use LUTs to speedup WG
|
||||
// 1: Use precise float math
|
||||
// The WG algorithm involves dozens of transcendent maths, e.g. exponents and trigonometry.
|
||||
// Unfortunately, the majority of systems perform such computations inefficiently,
|
||||
// standard math libs and FPUs make no optimisations for single precision floats,
|
||||
// and use no LUTs to speedup computing internal taylor series. Though, there're rare exceptions,
|
||||
// and there's a hope it will become common soon.
|
||||
// So, this is the crucial point of speed optimisations. We have now eliminated all the transcendent maths
|
||||
// within the critical path and use LUTs instead.
|
||||
// Besides, since the LA32 chip is assumed to use similar LUTs inside, the overall emulation accuracy should be better.
|
||||
// 0: Use LUTs to speedup WG. Most common setting. You can expect about 50% performance boost.
|
||||
// 1: Use precise float math. Use this setting to achieve more accurate wave generator. If your system performs better with this setting, it is really notable. :)
|
||||
#define MT32EMU_ACCURATE_WG 0
|
||||
|
||||
#define MT32EMU_USE_EXTINT 0
|
||||
|
@ -204,6 +204,8 @@ void SdlEventSource::SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) {
|
||||
#endif
|
||||
if (mod & KMOD_CTRL)
|
||||
event.kbd.flags |= Common::KBD_CTRL;
|
||||
if (mod & KMOD_META)
|
||||
event.kbd.flags |= Common::KBD_META;
|
||||
|
||||
// Sticky flags
|
||||
if (mod & KMOD_NUM)
|
||||
|
@ -116,7 +116,7 @@ protected:
|
||||
//@}
|
||||
|
||||
/**
|
||||
* Assigns the mouse coords to the mouse event. Furthermore notify the
|
||||
* Assigns the mouse coords to the mouse event. Furthermore notify the
|
||||
* graphics manager about the position change.
|
||||
* ResidualVM addon:
|
||||
* The parameters relx and rely for relative mouse movement are Residual specific
|
||||
|
@ -172,10 +172,15 @@ int MidiDriver_CORE::open() {
|
||||
|
||||
// Load custom soundfont, if specified
|
||||
if (ConfMan.hasKey("soundfont")) {
|
||||
FSRef fsref;
|
||||
FSSpec fsSpec;
|
||||
const char *soundfont = ConfMan.get("soundfont").c_str();
|
||||
|
||||
// TODO: We should really check whether the file contains an
|
||||
// actual soundfont...
|
||||
|
||||
#if USE_DEPRECATED_COREAUDIO_API
|
||||
// Before 10.5, we need to use kMusicDeviceProperty_SoundBankFSSpec
|
||||
FSRef fsref;
|
||||
FSSpec fsSpec;
|
||||
err = FSPathMakeRef ((const byte *)soundfont, &fsref, NULL);
|
||||
|
||||
if (err == noErr) {
|
||||
@ -183,8 +188,6 @@ int MidiDriver_CORE::open() {
|
||||
}
|
||||
|
||||
if (err == noErr) {
|
||||
// TODO: We should really check here whether the file contains an
|
||||
// actual soundfont...
|
||||
err = AudioUnitSetProperty (
|
||||
_synth,
|
||||
kMusicDeviceProperty_SoundBankFSSpec, kAudioUnitScope_Global,
|
||||
@ -192,9 +195,27 @@ int MidiDriver_CORE::open() {
|
||||
&fsSpec, sizeof(fsSpec)
|
||||
);
|
||||
}
|
||||
#else
|
||||
// kMusicDeviceProperty_SoundBankFSSpec is present on 10.6+, but broken
|
||||
// kMusicDeviceProperty_SoundBankURL was added in 10.5 as a replacement
|
||||
CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)soundfont, strlen(soundfont), false);
|
||||
|
||||
if (url) {
|
||||
err = AudioUnitSetProperty (
|
||||
_synth,
|
||||
kMusicDeviceProperty_SoundBankURL, kAudioUnitScope_Global,
|
||||
0,
|
||||
&url, sizeof(url)
|
||||
);
|
||||
|
||||
CFRelease(url);
|
||||
} else {
|
||||
warning("Failed to allocate CFURLRef from '%s'", soundfont);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (err != noErr)
|
||||
warning("Failed loading custom sound font '%s' (error %ld)\n", soundfont, (long)err);
|
||||
error("Failed loading custom sound font '%s' (error %ld)", soundfont, (long)err);
|
||||
}
|
||||
|
||||
#ifdef COREAUDIO_DISABLE_REVERB
|
||||
|
@ -81,7 +81,7 @@ void MidiDriver_Sndio::send(uint32 b) {
|
||||
|
||||
if (!hdl)
|
||||
return;
|
||||
buf[0] = b & 0xff;
|
||||
buf[0] = b & 0xff;
|
||||
buf[1] = (b >> 8) & 0xff;
|
||||
buf[2] = (b >> 16) & 0xff;
|
||||
buf[3] = (b >> 24) & 0xff;
|
||||
@ -101,7 +101,7 @@ void MidiDriver_Sndio::send(uint32 b) {
|
||||
void MidiDriver_Sndio::sysEx(const byte *msg, uint16 length) {
|
||||
if (!hdl)
|
||||
return;
|
||||
|
||||
|
||||
unsigned char buf[266];
|
||||
|
||||
assert(length + 2 <= ARRAYSIZE(buf));
|
||||
|
@ -69,13 +69,13 @@ void Sdl13MixerManager::init() {
|
||||
warning("Could not open audio device: %s", SDL_GetError());
|
||||
|
||||
_mixer = new Audio::MixerImpl(g_system, desired.freq);
|
||||
assert(_mixer);
|
||||
assert(_mixer);
|
||||
_mixer->setReady(false);
|
||||
} else {
|
||||
debug(1, "Output sample rate: %d Hz", _obtained.freq);
|
||||
|
||||
_mixer = new Audio::MixerImpl(g_system, _obtained.freq);
|
||||
assert(_mixer);
|
||||
assert(_mixer);
|
||||
_mixer->setReady(true);
|
||||
|
||||
startAudio();
|
||||
|
@ -99,9 +99,8 @@ endif
|
||||
ifdef AMIGAOS
|
||||
MODULE_OBJS += \
|
||||
fs/amigaos4/amigaos4-fs.o \
|
||||
fs/amigaos4/amigaos4-fs-factory.o
|
||||
#ResidualVM: disabled below
|
||||
# midi/camd.o
|
||||
fs/amigaos4/amigaos4-fs-factory.o \
|
||||
midi/camd.o
|
||||
endif
|
||||
|
||||
ifdef PLAYSTATION3
|
||||
|
@ -35,9 +35,8 @@
|
||||
- (void)setAppleMenu:(NSMenu *)menu;
|
||||
@end
|
||||
|
||||
NSString *constructNSStringFromCString(const char* rawCString, NSStringEncoding stringEncoding) {
|
||||
NSData *nsData = [NSData dataWithBytes:rawCString length:strlen(rawCString)];
|
||||
return [[NSString alloc] initWithData:nsData encoding:stringEncoding];
|
||||
NSString *constructNSStringFromCString(const char *rawCString, CFStringEncoding stringEncoding) {
|
||||
return (NSString *)CFStringCreateWithCString(NULL, rawCString, stringEncoding);
|
||||
}
|
||||
|
||||
void replaceApplicationMenuItems() {
|
||||
@ -59,11 +58,11 @@ void replaceApplicationMenuItems() {
|
||||
|
||||
// Get current encoding
|
||||
#ifdef USE_TRANSLATION
|
||||
nsString = constructNSStringFromCString((TransMan.getCurrentCharset()).c_str(), NSASCIIStringEncoding);
|
||||
NSStringEncoding stringEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)nsString));
|
||||
nsString = constructNSStringFromCString(TransMan.getCurrentCharset().c_str(), NSASCIIStringEncoding);
|
||||
CFStringEncoding stringEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)nsString);
|
||||
[nsString release];
|
||||
#else
|
||||
NSStringEncoding stringEncoding = NSASCIIStringEncoding;
|
||||
CFStringEncoding stringEncoding = kCFStringEncodingASCII;
|
||||
#endif
|
||||
|
||||
// Add "About ScummVM" menu item
|
||||
|
@ -39,7 +39,6 @@
|
||||
|
||||
#include "ApplicationServices/ApplicationServices.h" // for LSOpenFSRef
|
||||
#include "CoreFoundation/CoreFoundation.h" // for CF* stuff
|
||||
#include "CoreServices/CoreServices.h" // for FSPathMakeRef
|
||||
|
||||
OSystem_MacOSX::OSystem_MacOSX()
|
||||
:
|
||||
@ -107,13 +106,9 @@ bool OSystem_MacOSX::displayLogFile() {
|
||||
if (_logFilePath.empty())
|
||||
return false;
|
||||
|
||||
FSRef ref;
|
||||
OSStatus err;
|
||||
|
||||
err = FSPathMakeRef((const UInt8 *)_logFilePath.c_str(), &ref, NULL);
|
||||
if (err == noErr) {
|
||||
err = LSOpenFSRef(&ref, NULL);
|
||||
}
|
||||
CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)_logFilePath.c_str(), _logFilePath.size(), false);
|
||||
OSStatus err = LSOpenCFURLRef(url, NULL);
|
||||
CFRelease(url);
|
||||
|
||||
return err != noErr;
|
||||
}
|
||||
@ -156,7 +151,7 @@ Common::String OSystem_MacOSX::getSystemLanguage() const {
|
||||
}
|
||||
CFRelease(preferredLocalizations);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// Falback to POSIX implementation
|
||||
return OSystem_POSIX::getSystemLanguage();
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
virtual bool hasFeature(Feature f);
|
||||
|
||||
virtual bool displayLogFile();
|
||||
|
||||
|
||||
virtual Common::String getSystemLanguage() const;
|
||||
|
||||
virtual void initBackend();
|
||||
|
@ -1,66 +0,0 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
// Several SDL based ports use a custom main, and hence do not want to compile
|
||||
// of this file. The following "#if" ensures that.
|
||||
#if !defined(POSIX) && \
|
||||
!defined(WIN32) && \
|
||||
!defined(MAEMO) && \
|
||||
!defined(__SYMBIAN32__) && \
|
||||
!defined(_WIN32_WCE) && \
|
||||
!defined(__amigaos4__) && \
|
||||
!defined(DINGUX) && \
|
||||
!defined(CAANOO) && \
|
||||
!defined(LINUXMOTO) && \
|
||||
!defined(SAMSUNGTV) && \
|
||||
!defined(PLAYSTATION3) && \
|
||||
!defined(OPENPANDORA)
|
||||
|
||||
#include "backends/platform/sdl/sdl.h"
|
||||
#include "backends/plugins/sdl/sdl-provider.h"
|
||||
#include "base/main.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// Create our OSystem instance
|
||||
g_system = new OSystem_SDL();
|
||||
assert(g_system);
|
||||
|
||||
// Pre initialize the backend
|
||||
((OSystem_SDL *)g_system)->init();
|
||||
|
||||
#ifdef DYNAMIC_MODULES
|
||||
PluginManager::instance().addPluginProvider(new SDLPluginProvider());
|
||||
#endif
|
||||
|
||||
// Invoke the actual ScummVM main entry point:
|
||||
int res = scummvm_main(argc, argv);
|
||||
|
||||
// Free OSystem
|
||||
delete (OSystem_SDL *)g_system;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
@ -70,7 +70,7 @@ DECLARE_INTERFACE_(IPropertyStore, IUnknown) {
|
||||
STDMETHOD (GetValue) (REFPROPERTYKEY key, PROPVARIANT *pv) PURE;
|
||||
STDMETHOD (SetValue) (REFPROPERTYKEY key, REFPROPVARIANT propvar) PURE;
|
||||
STDMETHOD (Commit) (void) PURE;
|
||||
|
||||
|
||||
private:
|
||||
~IPropertyStore();
|
||||
};
|
||||
@ -137,7 +137,7 @@ DECLARE_INTERFACE_(ITaskbarList3, IUnknown) {
|
||||
STDMETHOD (SetOverlayIcon) (THIS_ HWND hwnd, HICON hIcon, LPCWSTR pszDescription) PURE;
|
||||
STDMETHOD (SetThumbnailTooltip) (THIS_ HWND hwnd, LPCWSTR pszTip) PURE;
|
||||
STDMETHOD (SetThumbnailClip) (THIS_ HWND hwnd, RECT *prcClip) PURE;
|
||||
|
||||
|
||||
private:
|
||||
~ITaskbarList3();
|
||||
};
|
||||
|
@ -156,7 +156,7 @@ void DefaultTimerManager::removeTimerProc(TimerProc callback) {
|
||||
}
|
||||
|
||||
// We need to remove all names referencing the timer proc here.
|
||||
//
|
||||
//
|
||||
// Else we run into troubles, when the client code removes and readds timer
|
||||
// callbacks.
|
||||
//
|
||||
|
@ -59,10 +59,14 @@ MacOSXUpdateManager::MacOSXUpdateManager() {
|
||||
[sparkleUpdater setFeedURL:[NSURL URLWithString:feedbackURL]];
|
||||
|
||||
// Get current encoding
|
||||
NSStringEncoding stringEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)[NSString stringWithCString:(TransMan.getCurrentCharset()).c_str() encoding:NSASCIIStringEncoding]));
|
||||
CFStringRef encStr = CFStringCreateWithCString(NULL, TransMan.getCurrentCharset().c_str(), kCFStringEncodingASCII);
|
||||
CFStringEncoding stringEncoding = CFStringConvertIANACharSetNameToEncoding(encStr);
|
||||
CFRelease(encStr);
|
||||
|
||||
// Add "Check for Updates..." menu item
|
||||
NSMenuItem *updateMenuItem = [applicationMenu insertItemWithTitle:[NSString stringWithCString:_("Check for Updates...") encoding:stringEncoding] action:@selector(checkForUpdates:) keyEquivalent:@"" atIndex:1];
|
||||
CFStringRef title = CFStringCreateWithCString(NULL, _("Check for Updates..."), stringEncoding);
|
||||
NSMenuItem *updateMenuItem = [applicationMenu insertItemWithTitle:(NSString *)title action:@selector(checkForUpdates:) keyEquivalent:@"" atIndex:1];
|
||||
CFRelease(title);
|
||||
|
||||
// Set the target of the new menu item
|
||||
[updateMenuItem setTarget:sparkleUpdater];
|
||||
|
@ -57,6 +57,7 @@
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
#include "graphics/fontman.h"
|
||||
#include "graphics/yuv_to_rgb.h"
|
||||
#ifdef USE_FREETYPE2
|
||||
#include "graphics/fonts/ttf.h"
|
||||
#endif
|
||||
@ -512,6 +513,8 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
|
||||
#ifdef USE_FREETYPE2
|
||||
Graphics::shutdownTTF();
|
||||
#endif
|
||||
EngineManager::destroy();
|
||||
Graphics::YUVToRGBManager::destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -111,8 +111,7 @@ public:
|
||||
LINK_PLUGIN(DMEDIA)
|
||||
#endif
|
||||
#if defined(__amigaos4__)
|
||||
//ResidualVM: disabled below
|
||||
// LINK_PLUGIN(CAMD)
|
||||
LINK_PLUGIN(CAMD)
|
||||
#endif
|
||||
#if defined(MACOSX)
|
||||
LINK_PLUGIN(COREAUDIO)
|
||||
@ -135,7 +134,7 @@ public:
|
||||
#ifndef DISABLE_SID
|
||||
// LINK_PLUGIN(C64)
|
||||
#endif
|
||||
// LINK_PLUGIN(AMIGA)
|
||||
LINK_PLUGIN(AMIGA)
|
||||
// LINK_PLUGIN(APPLEIIGS)
|
||||
// LINK_PLUGIN(TOWNS)
|
||||
// LINK_PLUGIN(PC98)
|
||||
|
@ -332,7 +332,7 @@ protected:
|
||||
// Copy a part of the new data to the position inside the
|
||||
// initialized space.
|
||||
copy(first, first + (_size - idx), pos);
|
||||
|
||||
|
||||
// Copy a part of the new data to the position inside the
|
||||
// uninitialized space.
|
||||
uninitialized_copy(first + (_size - idx), last, _storage + _size);
|
||||
|
@ -36,7 +36,7 @@ CosineTable::CosineTable(int bitPrecision) {
|
||||
double freq = 2 * M_PI / m;
|
||||
_table = new float[m];
|
||||
|
||||
// Table contains cos(2*pi*x/n) for 0<=x<=n/4,
|
||||
// Table contains cos(2*pi*x/n) for 0<=x<=n/4,
|
||||
// followed by its reverse
|
||||
for (int i = 0; i <= m / 4; i++)
|
||||
_table[i] = cos(i * freq);
|
||||
|
@ -55,7 +55,7 @@
|
||||
#define GUIO_RENDERPC9821 "\037"
|
||||
#define GUIO_RENDERPC9801 "\040"
|
||||
|
||||
// Special GUIO flags for the AdvancedDetector's caching of game specific
|
||||
// Special GUIO flags for the AdvancedDetector's caching of game specific
|
||||
// options.
|
||||
#define GUIO_GAMEOPTIONS1 "\041"
|
||||
#define GUIO_GAMEOPTIONS2 "\042"
|
||||
|
@ -224,12 +224,13 @@ enum {
|
||||
KBD_CTRL = 1 << 0,
|
||||
KBD_ALT = 1 << 1,
|
||||
KBD_SHIFT = 1 << 2,
|
||||
KBD_NON_STICKY = (KBD_CTRL|KBD_ALT|KBD_SHIFT),
|
||||
KBD_META = 1 << 3,
|
||||
KBD_NON_STICKY = (KBD_CTRL|KBD_ALT|KBD_SHIFT|KBD_META),
|
||||
|
||||
// Sticky modifier flags
|
||||
KBD_NUM = 1 << 3,
|
||||
KBD_CAPS = 1 << 4,
|
||||
KBD_SCRL = 1 << 5,
|
||||
KBD_NUM = 1 << 4,
|
||||
KBD_CAPS = 1 << 5,
|
||||
KBD_SCRL = 1 << 6,
|
||||
KBD_STICKY = (KBD_NUM|KBD_CAPS|KBD_SCRL)
|
||||
|
||||
};
|
||||
|
@ -124,7 +124,7 @@ bool MacResManager::open(String filename) {
|
||||
File *file = new File();
|
||||
|
||||
// First, let's try to see if the Mac converted name exists
|
||||
if (file->open("._" + filename) && loadFromAppleDouble(*file)) {
|
||||
if (file->open(constructAppleDoubleName(filename)) && loadFromAppleDouble(*file)) {
|
||||
_baseFileName = filename;
|
||||
return true;
|
||||
}
|
||||
@ -185,7 +185,7 @@ bool MacResManager::open(FSNode path, String filename) {
|
||||
#endif
|
||||
|
||||
// First, let's try to see if the Mac converted name exists
|
||||
FSNode fsNode = path.getChild("._" + filename);
|
||||
FSNode fsNode = path.getChild(constructAppleDoubleName(filename));
|
||||
if (fsNode.exists() && !fsNode.isDirectory()) {
|
||||
SeekableReadStream *stream = fsNode.createReadStream();
|
||||
if (loadFromAppleDouble(*stream)) {
|
||||
@ -253,7 +253,7 @@ bool MacResManager::exists(const String &filename) {
|
||||
return true;
|
||||
|
||||
// Check if we have an AppleDouble file
|
||||
if (tempFile.open("._" + filename) && tempFile.readUint32BE() == 0x00051607)
|
||||
if (tempFile.open(constructAppleDoubleName(filename)) && tempFile.readUint32BE() == 0x00051607)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -574,4 +574,20 @@ void MacResManager::readMap() {
|
||||
}
|
||||
}
|
||||
|
||||
Common::String MacResManager::constructAppleDoubleName(Common::String name) {
|
||||
// Insert "._" before the last portion of a path name
|
||||
for (int i = name.size() - 1; i >= 0; i--) {
|
||||
if (i == 0) {
|
||||
name.insertChar('_', 0);
|
||||
name.insertChar('.', 0);
|
||||
} else if (name[i] == '/') {
|
||||
name.insertChar('_', i + 1);
|
||||
name.insertChar('.', i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
} // End of namespace Common
|
||||
|
@ -25,6 +25,7 @@
|
||||
* Macintosh resource fork manager used in engines:
|
||||
* - groovie
|
||||
* - mohawk
|
||||
* - pegasus
|
||||
* - sci
|
||||
* - scumm
|
||||
*/
|
||||
@ -175,6 +176,8 @@ private:
|
||||
bool loadFromMacBinary(SeekableReadStream &stream);
|
||||
bool loadFromAppleDouble(SeekableReadStream &stream);
|
||||
|
||||
static Common::String constructAppleDoubleName(Common::String name);
|
||||
|
||||
enum {
|
||||
kResForkNone = 0,
|
||||
kResForkRaw,
|
||||
|
@ -92,13 +92,17 @@ private:
|
||||
byte *_ptr;
|
||||
const uint32 _bufSize;
|
||||
uint32 _pos;
|
||||
bool _err;
|
||||
public:
|
||||
MemoryWriteStream(byte *buf, uint32 len) : _ptr(buf), _bufSize(len), _pos(0) {}
|
||||
MemoryWriteStream(byte *buf, uint32 len) : _ptr(buf), _bufSize(len), _pos(0), _err(false) {}
|
||||
|
||||
uint32 write(const void *dataPtr, uint32 dataSize) {
|
||||
// Write at most as many bytes as are still available...
|
||||
if (dataSize > _bufSize - _pos)
|
||||
if (dataSize > _bufSize - _pos) {
|
||||
dataSize = _bufSize - _pos;
|
||||
// We couldn't write all the data => set error indicator
|
||||
_err = true;
|
||||
}
|
||||
memcpy(_ptr, dataPtr, dataSize);
|
||||
_ptr += dataSize;
|
||||
_pos += dataSize;
|
||||
@ -107,6 +111,9 @@ public:
|
||||
|
||||
uint32 pos() const { return _pos; }
|
||||
uint32 size() const { return _bufSize; }
|
||||
|
||||
virtual bool err() const { return _err; }
|
||||
virtual void clearErr() { _err = false; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -80,6 +80,9 @@ public:
|
||||
double toDouble() const;
|
||||
frac_t toFrac() const;
|
||||
|
||||
int getNumerator() const { return _num; }
|
||||
int getDenominator() const { return _denom; }
|
||||
|
||||
void debugPrint(int debuglevel = 0, const char *caption = "Rational:") const;
|
||||
|
||||
private:
|
||||
|
@ -169,6 +169,20 @@ struct Rect {
|
||||
return (left < r.right) && (r.left < right) && (top < r.bottom) && (r.top < bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the intersecting rectangle between this rectangle and the given rectangle
|
||||
*
|
||||
* @param r the intersecting rectangle
|
||||
*
|
||||
* @return the intersection of the rectangles or an empty rectangle if not intersecting
|
||||
*/
|
||||
Rect findIntersectingRect(const Rect &r) const {
|
||||
if (!intersects(r))
|
||||
return Rect();
|
||||
|
||||
return Rect(MAX(r.left, left), MAX(r.top, top), MIN(r.right, right), MIN(r.bottom, bottom));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend this rectangle so that it contains r
|
||||
*
|
||||
|
@ -109,12 +109,12 @@ public:
|
||||
*
|
||||
* Saved games are compressed by default, and engines are expected to
|
||||
* always write compressed saves.
|
||||
*
|
||||
*
|
||||
* A notable exception is if uncompressed files are needed for
|
||||
* compatibility with games not supported by ScummVM, such as character
|
||||
* exports from the Quest for Glory series. QfG5 is a 3D game and won't be
|
||||
* supported by ScummVM.
|
||||
*
|
||||
*
|
||||
* @param name the name of the savefile
|
||||
* @param compress toggles whether to compress the resulting save file
|
||||
* (default) or not.
|
||||
|
@ -36,7 +36,7 @@ SineTable::SineTable(int bitPrecision) {
|
||||
double freq = 2 * M_PI / m;
|
||||
_table = new float[m];
|
||||
|
||||
// Table contains sin(2*pi*x/n) for 0<=x<=n/4,
|
||||
// Table contains sin(2*pi*x/n) for 0<=x<=n/4,
|
||||
// followed by its reverse
|
||||
for (int i = 0; i <= m / 4; i++)
|
||||
_table[i] = sin(i * freq);
|
||||
|
@ -114,7 +114,7 @@ bool inflateZlibInstallShield(byte *dst, uint dstLen, const byte *src, uint srcL
|
||||
* returned).
|
||||
*
|
||||
* @param toBeWrapped the stream to be wrapped (if it is in gzip-format)
|
||||
* @param knownSize a supplied length of the compressed data (if not available directly)
|
||||
* @param knownSize a supplied length of the compressed data (if not available directly)
|
||||
*/
|
||||
SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped, uint32 knownSize = 0);
|
||||
|
||||
|
209
configure
vendored
209
configure
vendored
@ -62,7 +62,7 @@ get_var() {
|
||||
eval echo \$${1}
|
||||
}
|
||||
|
||||
# Add an engine: id name build subengines dependencies
|
||||
# Add an engine: id name build subengines base-games dependencies
|
||||
add_engine() {
|
||||
_engines="${_engines} ${1}"
|
||||
if test "${3}" = "no" ; then
|
||||
@ -72,9 +72,11 @@ add_engine() {
|
||||
set_var _engine_${1}_build "${3}"
|
||||
set_var _engine_${1}_build_default "${3}"
|
||||
set_var _engine_${1}_subengines "${4}"
|
||||
set_var _engine_${1}_deps "${5}"
|
||||
set_var _engine_${1}_base "${5}"
|
||||
set_var _engine_${1}_deps "${6}"
|
||||
for sub in ${4}; do
|
||||
set_var _engine_${sub}_sub "yes"
|
||||
set_var _engine_${sub}_parent "${1}"
|
||||
done
|
||||
}
|
||||
|
||||
@ -95,7 +97,7 @@ _srcdir=`dirname $0`
|
||||
# Default settings
|
||||
#
|
||||
#ResidualVM defaults: mpeg2=auto, faad=no, opengles=no, vorbis=no, tremor=no
|
||||
# mt32emu=no, translation=no, flac=no, seq_midi=no, timidity=no, png=no
|
||||
# mt32emu=no, translation=no, flac=no, seq_midi=no, snd_io=no, timidity=no, png=no
|
||||
# theoradec=no, fluidsynth=no
|
||||
#
|
||||
# Default lib behaviour yes/no/auto
|
||||
@ -106,6 +108,7 @@ _flac=no
|
||||
_mad=auto
|
||||
_alsa=auto
|
||||
_seq_midi=no
|
||||
_sndio=no
|
||||
_timidity=no
|
||||
_zlib=auto
|
||||
_sparkle=auto
|
||||
@ -121,7 +124,7 @@ _freetype2=auto
|
||||
_taskbar=yes
|
||||
_updates=no
|
||||
_libunity=auto
|
||||
# Default option behaviour yes/no
|
||||
# Default option behavior yes/no
|
||||
_debug_build=auto
|
||||
_release_build=auto
|
||||
_optimizations=auto
|
||||
@ -513,6 +516,11 @@ get_engine_dependencies() {
|
||||
get_var _engine_$1_deps
|
||||
}
|
||||
|
||||
# Get the base engine game support description
|
||||
get_engine_base() {
|
||||
get_var _engine_$1_base
|
||||
}
|
||||
|
||||
# Ask if this is a subengine
|
||||
get_engine_sub() {
|
||||
sub=`get_var _engine_$1_sub`
|
||||
@ -522,6 +530,11 @@ get_engine_sub() {
|
||||
echo $sub
|
||||
}
|
||||
|
||||
# Get a subengine's parent (undefined for non-subengines)
|
||||
get_subengine_parent() {
|
||||
get_var _engine_$1_parent
|
||||
}
|
||||
|
||||
# Enable *all* engines
|
||||
engine_enable_all() {
|
||||
for engine in $_engines; do
|
||||
@ -549,9 +562,15 @@ engine_enable() {
|
||||
engine=`echo $eng | sed 's/-/_/g'`
|
||||
|
||||
# Filter the parameter for the subengines
|
||||
if test "`get_engine_sub ${engine}`" != "no" -a "$opt" != "yes" ; then
|
||||
subengine_option_error ${engine}
|
||||
return
|
||||
if test "`get_engine_sub ${engine}`" != "no" ; then
|
||||
if test "$opt" != "yes" ; then
|
||||
subengine_option_error ${engine}
|
||||
return
|
||||
fi
|
||||
parent=`get_subengine_parent ${engine}`
|
||||
if test `get_engine_build ${parent}` = "no" ; then
|
||||
set_var _engine_${parent}_build "yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then
|
||||
@ -587,7 +606,7 @@ check_engine_deps() {
|
||||
unmet_deps=""
|
||||
|
||||
# Check whether the engine is enabled
|
||||
if test `get_engine_build $1` = yes ; then
|
||||
if test `get_engine_build $1` != "no" ; then
|
||||
# Collect unmet dependencies
|
||||
for dep in `get_engine_dependencies $1`; do
|
||||
if test `get_feature_state $dep` = "no"; then
|
||||
@ -646,27 +665,37 @@ prepare_engine_build_strings() {
|
||||
|
||||
# Get the string about building an engine
|
||||
get_engine_build_string() {
|
||||
engine=$1
|
||||
request_status=$2
|
||||
engine_string=""
|
||||
engine_build=`get_engine_build $1`
|
||||
engine_build_default=`get_engine_build_default $1`
|
||||
engine_build_default=`get_engine_build_default $engine`
|
||||
show=no
|
||||
|
||||
# Convert static/dynamic to yes to ease the check of subengines
|
||||
if test $engine_build = no; then
|
||||
subengine_filter=no
|
||||
else
|
||||
subengine_filter=yes
|
||||
fi
|
||||
|
||||
# Check if the current engine should be shown for the current status
|
||||
if test $engine_build = $2 ; then
|
||||
if test $engine_build = $request_status ; then
|
||||
show=yes
|
||||
else
|
||||
# Test for disabled sub-engines
|
||||
if test $2 = no ; then
|
||||
for subeng in `get_engine_subengines $1` ; do
|
||||
if test $request_status = no ; then
|
||||
for subeng in `get_engine_subengines $engine` ; do
|
||||
if test `get_engine_build $subeng` = no ; then
|
||||
engine_build=no
|
||||
# In this case we to display _disabled_ subengines
|
||||
subengine_filter=no
|
||||
show=yes
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# Test for enabled wip sub-engines
|
||||
if test $2 = wip ; then
|
||||
for subeng in `get_engine_subengines $1` ; do
|
||||
if test $request_status = wip ; then
|
||||
for subeng in `get_engine_subengines $engine` ; do
|
||||
if test `get_engine_build $subeng` != no -a `get_engine_build_default $subeng` = no ; then
|
||||
show=yes
|
||||
fi
|
||||
@ -674,85 +703,82 @@ get_engine_build_string() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Convert static/dynamic to yes to ease the check of subengines
|
||||
if test $engine_build != no ; then
|
||||
engine_build=yes
|
||||
fi
|
||||
|
||||
# Check if it is a wip engine
|
||||
if test "$2" = "wip" -a "$engine_build" != "no" -a "$engine_build_default" = no; then
|
||||
if test "$request_status" = "wip" -a "$engine_build" != "no" -a "$engine_build_default" = no; then
|
||||
show=yes
|
||||
fi
|
||||
|
||||
# The engine should be shown, build the string
|
||||
if test $show = yes ; then
|
||||
build_string_func=get_${1}_build_string
|
||||
if ( type $build_string_func | grep function ) 2> /dev/null > /dev/null ; then
|
||||
engine_string=`$build_string_func $1 $engine_build $2`
|
||||
else
|
||||
engine_string=`get_subengines_build_string $1 $engine_build "" $2`
|
||||
fi
|
||||
|
||||
engine_string="`get_engine_name $1` $engine_string"
|
||||
engine_string=`get_subengines_build_string $engine $subengine_filter $request_status`
|
||||
engine_string="`get_engine_name $engine` $engine_string"
|
||||
fi
|
||||
|
||||
echo $engine_string
|
||||
echo "$engine_string"
|
||||
}
|
||||
|
||||
# Get the string about building subengines
|
||||
get_subengines_build_string() {
|
||||
all=yes
|
||||
parent_engine=$1
|
||||
subengine_string=$3
|
||||
parent_status=$4
|
||||
subengine_filter=$2
|
||||
request_status=$3
|
||||
parent_engine_build_default=`get_engine_build_default $parent_engine`
|
||||
subengine_string=""
|
||||
|
||||
# If the base engine isn't built at all, no need to list subengines
|
||||
# in any of the possible categories.
|
||||
if test `get_engine_build $parent_engine` = no; then
|
||||
return
|
||||
fi
|
||||
|
||||
all=yes
|
||||
# If there are no subengines, never display "[all games]" (for brevity).
|
||||
if test -z "`get_engine_subengines $parent_engine`"; then
|
||||
all=no
|
||||
fi
|
||||
# If the base engine does not fit the category we're displaying here
|
||||
# (WIP or Skipped), we should never show "[all games]"
|
||||
if test "$request_status" = wip; then
|
||||
if test $parent_engine_build_default = yes; then
|
||||
all=no
|
||||
fi
|
||||
fi
|
||||
if test "$request_status" = no; then
|
||||
# If we're here, the parent engine is built, so no need to check that.
|
||||
all=no
|
||||
fi
|
||||
|
||||
|
||||
# In the static/dynamic categories, also display the engine's base games.
|
||||
if test -n "`get_engine_subengines $parent_engine`" -a $request_status != no -a $request_status != wip; then
|
||||
subengine_string="[`get_engine_base $parent_engine`]"
|
||||
fi
|
||||
|
||||
for subeng in `get_engine_subengines $parent_engine` ; do
|
||||
subengine_build=`get_engine_build $subeng`
|
||||
subengine_build_default=`get_engine_build_default $subeng`
|
||||
if test \( $subengine_build = $2 -a "$parent_status" != wip \) -o \( "$parent_status" = wip -a $subengine_build != no -a "$subengine_build_default" = no \) ; then
|
||||
subengine_string="$subengine_string [`get_engine_name $subeng`]"
|
||||
|
||||
# Display this subengine if it matches the filter, unless it is
|
||||
# a stable subengine in the WIP request.
|
||||
if test $subengine_build = $subengine_filter -a \! \( "$request_status" = wip -a "$subengine_build_default" = yes \) ; then
|
||||
s="[`get_engine_name $subeng`]"
|
||||
if test -n "$subengine_string"; then
|
||||
subengine_string="$subengine_string $s"
|
||||
else
|
||||
subengine_string="$s"
|
||||
fi
|
||||
else
|
||||
all=no
|
||||
fi
|
||||
|
||||
# handle engines that are on by default and have a single subengine that is off by default
|
||||
if test "$parent_status" = wip ; then
|
||||
if test $parent_engine_build_default = yes -a subengine ; then
|
||||
all=no
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if test $2 != no ; then
|
||||
if test -n "$subengine_string" ; then
|
||||
if test $all = yes ; then
|
||||
subengine_string="[all games]"
|
||||
fi
|
||||
fi
|
||||
# Summarize the full list, where applicable
|
||||
if test $all = yes ; then
|
||||
subengine_string="[all games]"
|
||||
fi
|
||||
|
||||
echo $subengine_string
|
||||
}
|
||||
|
||||
# Engine specific build strings
|
||||
get_scumm_build_string() {
|
||||
if test `get_engine_build $1` != no ; then
|
||||
if test $2 != no -a "$3" != wip ; then
|
||||
base="[v0-v6 games]"
|
||||
fi
|
||||
get_subengines_build_string $1 $2 "$base" $3
|
||||
fi
|
||||
}
|
||||
|
||||
get_saga_build_string() {
|
||||
if test `get_engine_build $1` != no ; then
|
||||
if test $2 != no -a "$3" != wip; then
|
||||
base="[ITE]"
|
||||
fi
|
||||
get_subengines_build_string $1 $2 "$base" $3
|
||||
fi
|
||||
echo "$subengine_string"
|
||||
}
|
||||
|
||||
#
|
||||
@ -945,6 +971,7 @@ for ac_option in $@; do
|
||||
--disable-sparkle) _sparkle=no ;;
|
||||
--enable-nasm) _nasm=yes ;;
|
||||
--disable-nasm) _nasm=no ;;
|
||||
#ResidualVM specific option:
|
||||
--enable-mpeg2) _mpeg2=yes ;;
|
||||
--disable-mpeg2) _mpeg2=no ;;
|
||||
--disable-png) _png=no ;;
|
||||
@ -988,6 +1015,7 @@ for ac_option in $@; do
|
||||
FLUIDSYNTH_CFLAGS="-I$arg/include"
|
||||
FLUIDSYNTH_LIBS="-L$arg/lib"
|
||||
;;
|
||||
#ResidualVM specific option:
|
||||
--with-mpeg2-prefix=*)
|
||||
arg=`echo $ac_option | cut -d '=' -f 2`
|
||||
MPEG2_CFLAGS="-I$arg/include"
|
||||
@ -1063,6 +1091,12 @@ for ac_option in $@; do
|
||||
LIBUNITY_CFLAGS="-I$arg/include"
|
||||
LIBUNITY_LIBS="-L$arg/lib"
|
||||
;;
|
||||
// ResidualVM don't use that
|
||||
// --with-opengl-prefix=*)
|
||||
// arg=`echo $ac_option | cut -d '=' -f 2`
|
||||
// OPENGL_CFLAGS="-I$arg/include"
|
||||
// OPENGL_LIBS="-L$arg/lib"
|
||||
// ;;
|
||||
--backend=*)
|
||||
_backend=`echo $ac_option | cut -d '=' -f 2`
|
||||
;;
|
||||
@ -2484,10 +2518,13 @@ if test -n "$_host"; then
|
||||
# Use -O3 on the OpenPandora for non-debug builds.
|
||||
_optimization_level=-O3
|
||||
fi
|
||||
define_in_config_if_yes yes 'USE_ARM_NEON_ASPECT_CORRECTOR'
|
||||
CXXFLAGS="$CXXFLAGS -march=armv7-a"
|
||||
CXXFLAGS="$CXXFLAGS -mtune=cortex-a8"
|
||||
CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp"
|
||||
CXXFLAGS="$CXXFLAGS -mfpu=neon"
|
||||
ASFLAGS="$ASFLAGS -mfloat-abi=soft"
|
||||
CXXFLAGS="$CXXFLAGS -fsingle-precision-constant"
|
||||
ASFLAGS="$ASFLAGS -mfloat-abi=softfp"
|
||||
_backend="openpandora"
|
||||
_build_hq_scalers=yes
|
||||
_vkeybd=no
|
||||
@ -2496,6 +2533,16 @@ if test -n "$_host"; then
|
||||
_port_mk="backends/platform/openpandora/op-bundle.mk"
|
||||
;;
|
||||
ppc-amigaos)
|
||||
# Only static builds link successfully on buildbot
|
||||
LDFLAGS=`echo $LDFLAGS | sed 's/-use-dynld//'`
|
||||
LDFLAGS="$LDFLAGS -static"
|
||||
|
||||
# toolchain binaries prefixed by host
|
||||
_ranlib=$_host-ranlib
|
||||
_strip=$_host-strip
|
||||
_ar="$_host-ar cru"
|
||||
_as="$_host-as"
|
||||
_windres=$_host-windres
|
||||
;;
|
||||
ps2)
|
||||
DEFINES="$DEFINES -DDISABLE_TEXT_CONSOLE"
|
||||
@ -2936,7 +2983,7 @@ PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/ds/plugin.ld -mthumb-interwo
|
||||
freebsd*)
|
||||
_plugin_prefix="lib"
|
||||
_plugin_suffix=".so"
|
||||
CXXFLAGS="$CXXFLAGS -fpic"
|
||||
CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
_mak_plugins='
|
||||
PLUGIN_EXTRA_DEPS =
|
||||
PLUGIN_LDFLAGS += -shared
|
||||
@ -2980,7 +3027,7 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive
|
||||
linux*)
|
||||
_plugin_prefix="lib"
|
||||
_plugin_suffix=".so"
|
||||
CXXFLAGS="$CXXFLAGS -fpic"
|
||||
CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
LIBS="$LIBS -ldl"
|
||||
_mak_plugins='
|
||||
PLUGIN_EXTRA_DEPS =
|
||||
@ -3391,6 +3438,7 @@ fi
|
||||
echo "$_sparkle"
|
||||
|
||||
#
|
||||
# ResidualVM specific
|
||||
# Check for LibMPEG2
|
||||
#
|
||||
echocheck "libmpeg2 >= 0.3.2"
|
||||
@ -4006,9 +4054,6 @@ for engine in $_engines; do
|
||||
isbuilt=STATIC_PLUGIN
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prepare the information to be shown
|
||||
prepare_engine_build_strings $engine
|
||||
else
|
||||
# It's a subengine, just say yes or no
|
||||
if test "`get_engine_build $engine`" = "no" ; then
|
||||
@ -4027,6 +4072,14 @@ for engine in $_engines; do
|
||||
fi
|
||||
done
|
||||
|
||||
# Prepare the information to be shown
|
||||
for engine in $_engines; do
|
||||
if test "`get_engine_sub $engine`" = "no" ; then
|
||||
# It's a main engine
|
||||
prepare_engine_build_strings $engine
|
||||
fi
|
||||
done
|
||||
|
||||
#
|
||||
# Detection of WIP/unstable engines
|
||||
#
|
||||
@ -4054,28 +4107,28 @@ fi
|
||||
echo
|
||||
if test -n "$_engines_built_static" ; then
|
||||
echo "Engines (builtin):"
|
||||
echo $_engines_built_static | sed 's/@/\
|
||||
echo "$_engines_built_static" | sed 's/@/\
|
||||
/g
|
||||
s/#/ /g'
|
||||
fi
|
||||
|
||||
if test -n "$_engines_built_dynamic" ; then
|
||||
echo "Engines (plugins):"
|
||||
echo $_engines_built_dynamic | sed 's/@/\
|
||||
echo "$_engines_built_dynamic" | sed 's/@/\
|
||||
/g
|
||||
s/#/ /g'
|
||||
fi
|
||||
|
||||
if test -n "$_engines_skipped" ; then
|
||||
echo "Engines Skipped:"
|
||||
echo $_engines_skipped | sed 's/@/\
|
||||
echo "$_engines_skipped" | sed 's/@/\
|
||||
/g
|
||||
s/#/ /g'
|
||||
fi
|
||||
|
||||
if test -n "$_engines_built_wip" ; then
|
||||
echo "WARNING: This ResidualVM build contains the following UNSTABLE engines:"
|
||||
echo $_engines_built_wip | sed 's/@/\
|
||||
echo "$_engines_built_wip" | sed 's/@/\
|
||||
/g
|
||||
s/#/ /g'
|
||||
fi
|
||||
|
@ -206,7 +206,7 @@ void XCodeProvider::writeFileListToProject(const FileNode &dir, std::ofstream &p
|
||||
// Create group
|
||||
std::string name = getLastPathComponent(dir.name);
|
||||
Object *group = new Object(this, "PBXGroup_" + name , "PBXGroup", "PBXGroup", "", name);
|
||||
|
||||
|
||||
// List of children
|
||||
Property children;
|
||||
children.hasOrder = true;
|
||||
@ -225,7 +225,7 @@ void XCodeProvider::writeFileListToProject(const FileNode &dir, std::ofstream &p
|
||||
ADD_SETTING_ORDER_NOVALUE(children, getHash(id), node->name, order++);
|
||||
ADD_BUILD_FILE(id, node->name, node->name + " in Sources");
|
||||
ADD_FILE_REFERENCE(node->name, property);
|
||||
|
||||
|
||||
// Process child nodes
|
||||
if (!node->children.empty())
|
||||
writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/');
|
||||
|
@ -194,7 +194,7 @@ protected:
|
||||
|
||||
/**
|
||||
* A map containing all the extra game GUI options the engine supports.
|
||||
*/
|
||||
*/
|
||||
const ADExtraGuiOptionsMap * const _extraGuiOptions;
|
||||
|
||||
/**
|
||||
@ -212,7 +212,7 @@ protected:
|
||||
*
|
||||
* Used to override gameid.
|
||||
* This is a recommended setting to prevent global gameid pollution.
|
||||
* With this option set, the gameid effectively turns into engineid.
|
||||
* With this option set, the gameid effectively turns into engineid.
|
||||
*
|
||||
* FIXME: This field actually removes a feature (gameid) in order to
|
||||
* address a more generic problem. We should find a better way to
|
||||
|
@ -1,4 +1,5 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
|
||||
add_engine grim "Grim" yes "monkey4" "zlib"
|
||||
add_engine monkey4 "Escape from Monkey Island" yes
|
||||
add_engine myst3 "Myst 3" yes
|
||||
|
@ -229,7 +229,7 @@ void MainMenuDialog::save() {
|
||||
"Please consult the README for basic information, and for "
|
||||
"instructions on how to obtain further assistance."), status.getDesc().c_str());
|
||||
GUI::MessageDialog dialog(failMessage);
|
||||
dialog.runModal();
|
||||
dialog.runModal();
|
||||
}
|
||||
|
||||
close();
|
||||
|
@ -276,6 +276,7 @@ public:
|
||||
|
||||
/**
|
||||
* Run the Global Main Menu Dialog
|
||||
* added 'virtual' ResidualVM specific
|
||||
*/
|
||||
virtual void openMainMenuDialog();
|
||||
|
||||
|
@ -80,7 +80,7 @@ void VectorRenderer::stepGetPositions(const DrawStep &step, const Common::Rect &
|
||||
case Graphics::DrawStep::kVectorAlignManual:
|
||||
if (step.x >= 0)
|
||||
in_x = area.left + step.x + step.padding.left;
|
||||
else
|
||||
else
|
||||
in_x = area.left + area.width() + step.x + step.padding.left; // value relative to the opposite corner.
|
||||
break;
|
||||
|
||||
|
@ -55,7 +55,7 @@ struct DrawStep {
|
||||
bool autoWidth, autoHeight;
|
||||
int16 x, y, w, h; /**< width, height and position, if not measured automatically.
|
||||
negative values mean counting from the opposite direction */
|
||||
|
||||
|
||||
Common::Rect padding;
|
||||
|
||||
enum VectorAlignment {
|
||||
|
@ -369,12 +369,12 @@ gradientFill(PixelType *ptr, int width, int x, int y) {
|
||||
int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize;
|
||||
|
||||
// Dithering:
|
||||
// +--+ +--+ +--+ +--+
|
||||
// | | | | | *| | *|
|
||||
// | | | *| |* | |**|
|
||||
// +--+ +--+ +--+ +--+
|
||||
// +--+ +--+ +--+ +--+
|
||||
// | | | | | *| | *|
|
||||
// | | | *| |* | |**|
|
||||
// +--+ +--+ +--+ +--+
|
||||
// 0 1 2 3
|
||||
if (grad == 0 ||
|
||||
if (grad == 0 ||
|
||||
_gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change
|
||||
stripSize < 2) { // the stip is small
|
||||
colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad]);
|
||||
@ -873,7 +873,7 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
|
||||
case kTriangleDown:
|
||||
drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
|
||||
break;
|
||||
|
||||
|
||||
case kTriangleLeft:
|
||||
case kTriangleRight:
|
||||
case kTriangleAuto:
|
||||
@ -1206,14 +1206,14 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
pitch = -pitch;
|
||||
y1 += h;
|
||||
}
|
||||
|
||||
|
||||
PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
|
||||
PixelType *floor = ptr_right - 1;
|
||||
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
|
||||
|
||||
int x2 = x1 + w / 2;
|
||||
int y2 = y1 + h;
|
||||
|
||||
|
||||
#if FIXED_POINT
|
||||
int dx = (x2 - x1) << 8;
|
||||
int dy = (y2 - y1) << 8;
|
||||
@ -1227,7 +1227,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
#endif
|
||||
while (floor++ != ptr_left)
|
||||
blendPixelPtr(floor, color, 50);
|
||||
|
||||
|
||||
#if FIXED_POINT
|
||||
int gradient = (dy << 8) / dx;
|
||||
int intery = (y1 << 8) + gradient;
|
||||
@ -1250,7 +1250,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
ptr_right += pitch;
|
||||
|
||||
intery += gradient;
|
||||
|
||||
|
||||
switch (fill_m) {
|
||||
case kFillDisabled:
|
||||
*ptr_left = *ptr_right = color;
|
||||
@ -1262,16 +1262,16 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
blendPixelPtr(ptr_left, color, rfpart(intery));
|
||||
break;
|
||||
case kFillGradient:
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
|
||||
blendPixelPtr(ptr_right, color, rfpart(intery));
|
||||
blendPixelPtr(ptr_left, color, rfpart(intery));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#if FIXED_POINT
|
||||
if (abs(dx) < abs(dy)) {
|
||||
#else
|
||||
@ -1280,7 +1280,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
ptr_left--;
|
||||
while (floor++ != ptr_left)
|
||||
blendPixelPtr(floor, color, 50);
|
||||
|
||||
|
||||
#if FIXED_POINT
|
||||
int gradient = (dx << 8) / (dy + 0x100);
|
||||
int interx = (x1 << 8) + gradient;
|
||||
@ -1303,7 +1303,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
ptr_right += pitch;
|
||||
|
||||
interx += gradient;
|
||||
|
||||
|
||||
switch (fill_m) {
|
||||
case kFillDisabled:
|
||||
*ptr_left = *ptr_right = color;
|
||||
@ -1315,18 +1315,18 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
blendPixelPtr(ptr_left, color, rfpart(interx));
|
||||
break;
|
||||
case kFillGradient:
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
|
||||
blendPixelPtr(ptr_right, color, rfpart(interx));
|
||||
blendPixelPtr(ptr_left, color, rfpart(interx));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ptr_left--;
|
||||
|
||||
|
||||
while (floor++ != ptr_left)
|
||||
blendPixelPtr(floor, color, 50);
|
||||
|
||||
@ -1341,12 +1341,12 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
for (int y = y1 + 1; y < y2; y++) {
|
||||
ptr_right++;
|
||||
ptr_left--;
|
||||
|
||||
|
||||
ptr_left += pitch;
|
||||
ptr_right += pitch;
|
||||
|
||||
interx += gradient;
|
||||
|
||||
|
||||
switch (fill_m) {
|
||||
case kFillDisabled:
|
||||
*ptr_left = *ptr_right = color;
|
||||
@ -1358,13 +1358,13 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
|
||||
blendPixelPtr(ptr_left, color, rfpart(interx));
|
||||
break;
|
||||
case kFillGradient:
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
|
||||
blendPixelPtr(ptr_right, color, rfpart(interx));
|
||||
blendPixelPtr(ptr_left, color, rfpart(interx));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
|
||||
@ -1372,12 +1372,12 @@ template<typename PixelType>
|
||||
void VectorRendererSpec<PixelType>::
|
||||
drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
|
||||
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
|
||||
|
||||
|
||||
if (!inverted) {
|
||||
pitch = -pitch;
|
||||
y1 += size;
|
||||
}
|
||||
|
||||
|
||||
int gradient_h = 0;
|
||||
PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
|
||||
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + size, y1);
|
||||
@ -1388,9 +1388,9 @@ drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, Vecto
|
||||
int signX = x1 < x2 ? 1 : -1;
|
||||
int signY = y1 < y2 ? 1 : -1;
|
||||
int error = deltaX - deltaY;
|
||||
|
||||
|
||||
colorFill<PixelType>(ptr_right, ptr_left, color);
|
||||
|
||||
|
||||
while (1) {
|
||||
switch (fill_m) {
|
||||
case kFillDisabled:
|
||||
@ -1401,22 +1401,22 @@ drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, Vecto
|
||||
colorFill<PixelType>(ptr_right, ptr_left, color);
|
||||
break;
|
||||
case kFillGradient:
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, size));
|
||||
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, size));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (x1 == x2 && y1 == y2)
|
||||
break;
|
||||
|
||||
|
||||
int error2 = error * 2;
|
||||
|
||||
|
||||
if (error2 > -deltaY) {
|
||||
error -= deltaY;
|
||||
x1 += signX;
|
||||
ptr_right += signX;
|
||||
ptr_left += -signX;
|
||||
}
|
||||
|
||||
|
||||
if (error2 < deltaX) {
|
||||
error += deltaX;
|
||||
y1 += signY;
|
||||
|
@ -22,123 +22,143 @@
|
||||
#include "graphics/conversion.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
// TODO: YUV to RGB conversion function
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename SrcColor, typename DstColor, bool backward>
|
||||
inline void crossBlitLogic(byte *dst, const byte *src, const uint w, const uint h,
|
||||
const PixelFormat &srcFmt, const PixelFormat &dstFmt,
|
||||
const uint srcDelta, const uint dstDelta) {
|
||||
for (uint y = 0; y < h; ++y) {
|
||||
for (uint x = 0; x < w; ++x) {
|
||||
const uint32 color = *(const SrcColor *)src;
|
||||
byte a, r, g, b;
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
*(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b);
|
||||
|
||||
if (backward) {
|
||||
src -= sizeof(SrcColor);
|
||||
dst -= sizeof(DstColor);
|
||||
} else {
|
||||
src += sizeof(SrcColor);
|
||||
dst += sizeof(DstColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (backward) {
|
||||
src -= srcDelta;
|
||||
dst -= dstDelta;
|
||||
} else {
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DstColor, bool backward>
|
||||
inline void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint w, const uint h,
|
||||
const PixelFormat &srcFmt, const PixelFormat &dstFmt,
|
||||
const uint srcDelta, const uint dstDelta) {
|
||||
uint32 color;
|
||||
byte r, g, b, a;
|
||||
uint8 *col = (uint8 *)&color;
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
col++;
|
||||
#endif
|
||||
for (uint y = 0; y < h; ++y) {
|
||||
for (uint x = 0; x < w; ++x) {
|
||||
memcpy(col, src, 3);
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
*(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b);
|
||||
|
||||
if (backward) {
|
||||
src -= 3;
|
||||
dst -= sizeof(DstColor);
|
||||
} else {
|
||||
src += 3;
|
||||
dst += sizeof(DstColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (backward) {
|
||||
src -= srcDelta;
|
||||
dst -= dstDelta;
|
||||
} else {
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
// Function to blit a rect from one color format to another
|
||||
bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch,
|
||||
int w, int h, const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
|
||||
bool crossBlit(byte *dst, const byte *src,
|
||||
const uint dstPitch, const uint srcPitch,
|
||||
const uint w, const uint h,
|
||||
const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
|
||||
// Error out if conversion is impossible
|
||||
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
|
||||
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel)
|
||||
|| (srcFmt.bytesPerPixel > dstFmt.bytesPerPixel))
|
||||
|| (dstFmt.bytesPerPixel == 3)
|
||||
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
|
||||
return false;
|
||||
|
||||
// Don't perform unnecessary conversion
|
||||
if (srcFmt == dstFmt) {
|
||||
if (dst == src)
|
||||
return true;
|
||||
if (dstpitch == srcpitch && ((w * dstFmt.bytesPerPixel) == dstpitch)) {
|
||||
memcpy(dst,src,dstpitch * h);
|
||||
return true;
|
||||
} else {
|
||||
for (int i = 0; i < h; i++) {
|
||||
memcpy(dst,src,w * dstFmt.bytesPerPixel);
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
if (dst != src) {
|
||||
if (dstPitch == srcPitch && ((w * dstFmt.bytesPerPixel) == dstPitch)) {
|
||||
memcpy(dst, src, dstPitch * h);
|
||||
} else {
|
||||
for (uint i = 0; i < h; ++i) {
|
||||
memcpy(dst, src, w * dstFmt.bytesPerPixel);
|
||||
dst += dstPitch;
|
||||
src += srcPitch;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Faster, but larger, to provide optimized handling for each case.
|
||||
int srcDelta, dstDelta;
|
||||
srcDelta = (srcpitch - w * srcFmt.bytesPerPixel);
|
||||
dstDelta = (dstpitch - w * dstFmt.bytesPerPixel);
|
||||
const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
|
||||
const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
|
||||
|
||||
// TODO: optimized cases for dstDelta of 0
|
||||
uint8 r, g, b, a;
|
||||
if (dstFmt.bytesPerPixel == 2) {
|
||||
uint16 color;
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++, src += 2, dst += 2) {
|
||||
color = *(const uint16 *)src;
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
color = dstFmt.ARGBToColor(a, r, g, b);
|
||||
*(uint16 *)dst = color;
|
||||
}
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
} else if (dstFmt.bytesPerPixel == 3) {
|
||||
uint32 color;
|
||||
uint8 *col = (uint8 *) &color;
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
col++;
|
||||
#endif
|
||||
if (srcFmt.bytesPerPixel == 2) {
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++, src += 2, dst += 3) {
|
||||
color = *(const uint16 *)src;
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
color = dstFmt.ARGBToColor(a, r, g, b);
|
||||
memcpy(dst, col, 3);
|
||||
}
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
crossBlitLogic<uint16, uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
|
||||
} else if (srcFmt.bytesPerPixel == 3) {
|
||||
crossBlitLogic3BppSource<uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
|
||||
} else {
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++, src += 3, dst += 3) {
|
||||
memcpy(col, src, 3);
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
color = dstFmt.ARGBToColor(a, r, g, b);
|
||||
memcpy(dst, col, 3);
|
||||
}
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
crossBlitLogic<uint32, uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
|
||||
}
|
||||
} else if (dstFmt.bytesPerPixel == 4) {
|
||||
uint32 color;
|
||||
if (srcFmt.bytesPerPixel == 2) {
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++, src += 2, dst += 4) {
|
||||
color = *(const uint16 *)src;
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
color = dstFmt.ARGBToColor(a, r, g, b);
|
||||
*(uint32 *)dst = color;
|
||||
}
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
// We need to blit the surface from bottom right to top left here.
|
||||
// This is neeeded, because when we convert to the same memory
|
||||
// buffer copying the surface from top left to bottom right would
|
||||
// overwrite the source, since we have more bits per destination
|
||||
// color than per source color.
|
||||
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
|
||||
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
|
||||
crossBlitLogic<uint16, uint32, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
|
||||
} else if (srcFmt.bytesPerPixel == 3) {
|
||||
uint8 *col = (uint8 *)&color;
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
col++;
|
||||
#endif
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++, src += 2, dst += 4) {
|
||||
memcpy(col, src, 3);
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
color = dstFmt.ARGBToColor(a, r, g, b);
|
||||
*(uint32 *)dst = color;
|
||||
}
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
// We need to blit the surface from bottom right to top left here.
|
||||
// This is neeeded, because when we convert to the same memory
|
||||
// buffer copying the surface from top left to bottom right would
|
||||
// overwrite the source, since we have more bits per destination
|
||||
// color than per source color.
|
||||
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
|
||||
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
|
||||
crossBlitLogic3BppSource<uint32, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
|
||||
} else {
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++, src += 4, dst += 4) {
|
||||
color = *(const uint32 *)src;
|
||||
srcFmt.colorToARGB(color, a, r, g, b);
|
||||
color = dstFmt.ARGBToColor(a, r, g, b);
|
||||
*(uint32 *)dst = color;
|
||||
}
|
||||
src += srcDelta;
|
||||
dst += dstDelta;
|
||||
}
|
||||
crossBlitLogic<uint32, uint32, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
@ -59,15 +59,18 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) {
|
||||
* @return true if conversion completes successfully,
|
||||
* false if there is an error.
|
||||
*
|
||||
* @note This implementation currently arbitrarily requires that the
|
||||
* destination's format have at least as high a bytedepth as
|
||||
* the source's.
|
||||
* @note This can convert a rectangle in place, if the source and
|
||||
* destination format have the same bytedepth.
|
||||
*
|
||||
* @note Blitting to a 3Bpp destination is not supported
|
||||
* @note This can convert a surface in place, regardless of the
|
||||
* source and destination format, as long as there is enough
|
||||
* space for the destination. The dstPitch / srcPitch ratio
|
||||
* must at least equal the dstBpp / srcBpp ratio for
|
||||
* dstPitch >= srcPitch and at most dstBpp / srcBpp for
|
||||
* dstPitch < srcPitch though.
|
||||
*/
|
||||
bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch,
|
||||
int w, int h, const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt);
|
||||
bool crossBlit(byte *dst, const byte *src,
|
||||
const uint dstPitch, const uint srcPitch,
|
||||
const uint w, const uint h,
|
||||
const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt);
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
|
@ -100,10 +100,10 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
|
||||
_paletteColorCount = stream.readUint32LE();
|
||||
/* uint32 colorsImportant = */ stream.readUint32LE();
|
||||
|
||||
if (_paletteColorCount == 0)
|
||||
_paletteColorCount = 256;
|
||||
|
||||
if (bitsPerPixel == 8) {
|
||||
if (_paletteColorCount == 0)
|
||||
_paletteColorCount = 256;
|
||||
|
||||
// Read the palette
|
||||
_palette = new byte[_paletteColorCount * 3];
|
||||
for (uint16 i = 0; i < _paletteColorCount; i++) {
|
||||
@ -155,7 +155,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
|
||||
}
|
||||
} else { // 32 bpp
|
||||
byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch;
|
||||
|
||||
|
||||
for (int32 i = 0; i < height; i++) {
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
byte b = stream.readByte();
|
||||
@ -166,11 +166,11 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
|
||||
// ref: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx
|
||||
stream.readByte();
|
||||
uint32 color = format.RGBToColor(r, g, b);
|
||||
|
||||
|
||||
*((uint32 *)dst) = color;
|
||||
dst += format.bytesPerPixel;
|
||||
}
|
||||
|
||||
|
||||
stream.skip(extraDataLength);
|
||||
dst -= _surface->pitch * 2;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
* Image decoder used in engines:
|
||||
* - hugo
|
||||
* - mohawk
|
||||
* - wintermute
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_DECODERS_BMP_H
|
||||
|
@ -78,10 +78,15 @@ public:
|
||||
* The palette's format is the same as PaletteManager's palette
|
||||
* (interleaved RGB values).
|
||||
*
|
||||
* @return the decoded palette, or 0 if no palette is present
|
||||
* @return the decoded palette, or undefined if no palette is present
|
||||
*/
|
||||
virtual const byte *getPalette() const { return 0; }
|
||||
|
||||
/**
|
||||
* Query if the decoded image has a palette.
|
||||
*/
|
||||
virtual bool hasPalette() const { return getPaletteColorCount() != 0; }
|
||||
|
||||
/** Return the starting index of the palette. */
|
||||
virtual byte getPaletteStartIndex() const { return 0; }
|
||||
/** Return the number of colors in the palette. */
|
||||
|
@ -81,7 +81,7 @@ const Surface *JPEGDecoder::getSurface() const {
|
||||
const Graphics::Surface *uComponent = getComponent(2);
|
||||
const Graphics::Surface *vComponent = getComponent(3);
|
||||
|
||||
convertYUV444ToRGB(_rgbSurface, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch);
|
||||
YUVToRGBMan.convert444(_rgbSurface, Graphics::YUVToRGBManager::kScaleFull, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch);
|
||||
|
||||
return _rgbSurface;
|
||||
}
|
||||
@ -452,7 +452,7 @@ bool JPEGDecoder::readSOS() {
|
||||
_bitsNumber = 0;
|
||||
|
||||
for (byte i = 0; i < _numScanComp; i++)
|
||||
_scanComp[i]->DCpredictor = 0;
|
||||
_scanComp[i]->DCpredictor = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
* Image decoder used in engines:
|
||||
* - groovie
|
||||
* - mohawk
|
||||
* - wintermute
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_JPEG_H
|
||||
|
@ -145,7 +145,10 @@ bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, by
|
||||
if (pixelDepth == 24) {
|
||||
_format = PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0);
|
||||
} else if (pixelDepth == 32) {
|
||||
_format = PixelFormat(4, 8, 8, 8, attributeBits, 16, 8, 0, 24);
|
||||
// HACK: According to the spec, attributeBits should determine the amount
|
||||
// of alpha-bits, however, as the game files that use this decoder seems
|
||||
// to ignore that fact, we force the amount to 8 for 32bpp files for now.
|
||||
_format = PixelFormat(4, 8, 8, 8, /* attributeBits */ 8, 16, 8, 0, 24);
|
||||
} else if (pixelDepth == 16 && imageType == TYPE_TRUECOLOR) {
|
||||
// 16bpp TGA is ARGB1555
|
||||
_format = PixelFormat(2, 5, 5, 5, attributeBits, 10, 5, 0, 15);
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
/*
|
||||
* TGA decoder used in engines:
|
||||
* - none
|
||||
* - wintermute
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_DECODERS_TGA_H
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Generated by convbdf on Fri Jan 6 14:32:21 2012
|
||||
#include "graphics/fonts/bdf.h"
|
||||
|
||||
// Font information:
|
||||
// Font information:
|
||||
// Name: -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-1
|
||||
// Size: 5x8
|
||||
// Box: 5 8 0 -1
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Generated by convbdf on Fri Jan 6 14:33:07 2012
|
||||
#include "graphics/fonts/bdf.h"
|
||||
|
||||
// Font information:
|
||||
// Font information:
|
||||
// Name: -Schumacher-Clean-Medium-R-Normal--12-120-75-75-C-60-ISO8859-1
|
||||
// Size: 6x12
|
||||
// Box: 6 12 0 -3
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Generated by convbdf on Fri Jan 6 14:33:14 2012
|
||||
#include "graphics/fonts/bdf.h"
|
||||
|
||||
// Font information:
|
||||
// Font information:
|
||||
// Name: -Adobe-Helvetica-Bold-R-Normal--12-120-75-75-P-70-ISO8859-1
|
||||
// Size: 13x14
|
||||
// Box: 13 15 -1 -3
|
||||
|
@ -61,59 +61,21 @@ void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, i
|
||||
}
|
||||
}
|
||||
|
||||
void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data) {
|
||||
assert(penX > 0 && penY > 0);
|
||||
|
||||
// FIXME: This is a limited version of thick line drawing
|
||||
// it draws striped lines at some angles. Better algorithm could
|
||||
// be found here:
|
||||
//
|
||||
// http://homepages.enterprise.net/murphy/thickline/index.html
|
||||
//
|
||||
// Feel free to replace it with better implementation
|
||||
void drawThickLine(int x0, int y0, int x1, int y1, int thickness, int color, void (*plotProc)(int, int, int, void *), void *data) {
|
||||
const bool steep = ABS(y1 - y0) > ABS(x1 - x0);
|
||||
|
||||
if (steep) {
|
||||
SWAP(x0, y0);
|
||||
SWAP(x1, y1);
|
||||
}
|
||||
|
||||
float dx = x1 - x0;
|
||||
float dy = y1 - y0;
|
||||
float d = (float)sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (!d)
|
||||
// Shortcut
|
||||
if (penX == 1 && penY == 1) {
|
||||
drawLine(x0, y0, x1, y1, color, plotProc, data);
|
||||
return;
|
||||
|
||||
int thickX = (int)((float)thickness * dy / d / 2);
|
||||
int thickY = (int)((float)thickness * dx / d / 2);
|
||||
|
||||
const int delta_x = ABS(x1 - x0);
|
||||
const int delta_y = ABS(y1 - y0);
|
||||
const int delta_err = delta_y;
|
||||
int x = x0;
|
||||
int y = y0;
|
||||
int err = 0;
|
||||
|
||||
const int x_step = (x0 < x1) ? 1 : -1;
|
||||
const int y_step = (y0 < y1) ? 1 : -1;
|
||||
|
||||
if (steep)
|
||||
drawLine(y - thickY, x + thickX, y + thickY, x - thickX, color, plotProc, data);
|
||||
else
|
||||
drawLine(x - thickX, y + thickY, x + thickX, y - thickY, color, plotProc, data);
|
||||
|
||||
while (x != x1) {
|
||||
x += x_step;
|
||||
err += delta_err;
|
||||
if (2 * err > delta_x) {
|
||||
y += y_step;
|
||||
err -= delta_x;
|
||||
}
|
||||
if (steep)
|
||||
drawLine(y - thickY, x + thickX, y + thickY, x - thickX, color, plotProc, data);
|
||||
else
|
||||
drawLine(x - thickX, y + thickY, x + thickX, y - thickY, color, plotProc, data);
|
||||
}
|
||||
|
||||
// TODO: Optimize this. It currently is a very naive way of handling
|
||||
// thick lines since quite often it will be drawing to the same pixel
|
||||
// multiple times.
|
||||
for (int x = 0; x < penX; x++)
|
||||
for (int y = 0; y < penY; y++)
|
||||
drawLine(x0 + x, y0 + y, x1 + x, y1 + y, color, plotProc, data);
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
@ -25,7 +25,7 @@
|
||||
namespace Graphics {
|
||||
|
||||
void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, int, int, void *), void *data);
|
||||
void drawThickLine(int x0, int y0, int x1, int y1, int thickness, int color, void (*plotProc)(int, int, int, void *), void *data);
|
||||
void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data);
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/primitives.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/conversion.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
@ -49,6 +50,17 @@ void Surface::drawLine(int x0, int y0, int x1, int y1, uint32 color) {
|
||||
error("Surface::drawLine: bytesPerPixel must be 1, 2, or 4");
|
||||
}
|
||||
|
||||
void Surface::drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, uint32 color) {
|
||||
if (format.bytesPerPixel == 1)
|
||||
Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint<byte>, this);
|
||||
else if (format.bytesPerPixel == 2)
|
||||
Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint<uint16>, this);
|
||||
else if (format.bytesPerPixel == 4)
|
||||
Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint<uint32>, this);
|
||||
else
|
||||
error("Surface::drawThickLine: bytesPerPixel must be 1, 2, or 4");
|
||||
}
|
||||
|
||||
void Surface::create(uint16 width, uint16 height, const PixelFormat &f) {
|
||||
free();
|
||||
|
||||
@ -271,6 +283,72 @@ void Surface::move(int dx, int dy, int height) {
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::convertToInPlace(const PixelFormat &dstFormat, const byte *palette) {
|
||||
// Do not convert to the same format and ignore empty surfaces.
|
||||
if (format == dstFormat || pixels == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (format.bytesPerPixel == 0 || format.bytesPerPixel > 4)
|
||||
error("Surface::convertToInPlace(): Can only convert from 1Bpp, 2Bpp, 3Bpp, and 4Bpp");
|
||||
|
||||
if (dstFormat.bytesPerPixel != 2 && dstFormat.bytesPerPixel != 4)
|
||||
error("Surface::convertToInPlace(): Can only convert to 2Bpp and 4Bpp");
|
||||
|
||||
// In case the surface data needs more space allocate it.
|
||||
if (dstFormat.bytesPerPixel > format.bytesPerPixel) {
|
||||
void *const newPixels = realloc(pixels, w * h * dstFormat.bytesPerPixel);
|
||||
if (!newPixels) {
|
||||
error("Surface::convertToInPlace(): Out of memory");
|
||||
}
|
||||
pixels = newPixels;
|
||||
}
|
||||
|
||||
// We take advantage of the fact that pitch is always w * format.bytesPerPixel.
|
||||
// This is assured by the logic of Surface::create.
|
||||
|
||||
// We need to handle 1 Bpp surfaces special here.
|
||||
if (format.bytesPerPixel == 1) {
|
||||
assert(palette);
|
||||
|
||||
for (int y = h; y > 0; --y) {
|
||||
const byte *srcRow = (const byte *)pixels + y * pitch - 1;
|
||||
byte *dstRow = (byte *)pixels + y * w * dstFormat.bytesPerPixel - dstFormat.bytesPerPixel;
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
byte index = *srcRow--;
|
||||
byte r = palette[index * 3];
|
||||
byte g = palette[index * 3 + 1];
|
||||
byte b = palette[index * 3 + 2];
|
||||
|
||||
uint32 color = dstFormat.RGBToColor(r, g, b);
|
||||
|
||||
if (dstFormat.bytesPerPixel == 2)
|
||||
*((uint16 *)dstRow) = color;
|
||||
else
|
||||
*((uint32 *)dstRow) = color;
|
||||
|
||||
dstRow -= dstFormat.bytesPerPixel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
crossBlit((byte *)pixels, (const byte *)pixels, w * dstFormat.bytesPerPixel, pitch, w, h, dstFormat, format);
|
||||
}
|
||||
|
||||
// In case the surface data got smaller, free up some memory.
|
||||
if (dstFormat.bytesPerPixel < format.bytesPerPixel) {
|
||||
void *const newPixels = realloc(pixels, w * h * dstFormat.bytesPerPixel);
|
||||
if (!newPixels) {
|
||||
error("Surface::convertToInPlace(): Freeing memory failed");
|
||||
}
|
||||
pixels = newPixels;
|
||||
}
|
||||
|
||||
// Update the surface specific data.
|
||||
format = dstFormat;
|
||||
pitch = w * dstFormat.bytesPerPixel;
|
||||
}
|
||||
|
||||
Graphics::Surface *Surface::convertTo(const PixelFormat &dstFormat, const byte *palette) const {
|
||||
assert(pixels);
|
||||
|
||||
|
@ -134,6 +134,20 @@ struct Surface {
|
||||
*/
|
||||
void copyFrom(const Surface &surf);
|
||||
|
||||
/**
|
||||
* Convert the data to another pixel format.
|
||||
*
|
||||
* This works in-place. This means it will not create an additional buffer
|
||||
* for the conversion process. The value of pixels might change though.
|
||||
*
|
||||
* Note that you should only use this, when you created the Surface data via
|
||||
* create! Otherwise this function has undefined behavior.
|
||||
*
|
||||
* @param dstFormat The desired format
|
||||
* @param palette The palette (in RGB888), if the source format has a Bpp of 1
|
||||
*/
|
||||
void convertToInPlace(const PixelFormat &dstFormat, const byte *palette = 0);
|
||||
|
||||
/**
|
||||
* Convert the data to another pixel format.
|
||||
*
|
||||
@ -153,9 +167,25 @@ struct Surface {
|
||||
* @param x1 The x coordinate of the end point.
|
||||
* @param y1 The y coordinate of the end point.
|
||||
* @param color The color of the line.
|
||||
* @note This is just a wrapper around Graphics::drawLine
|
||||
*/
|
||||
void drawLine(int x0, int y0, int x1, int y1, uint32 color);
|
||||
|
||||
/**
|
||||
* Draw a thick line.
|
||||
*
|
||||
* @param x0 The x coordinate of the start point.
|
||||
* @param y0 The y coordiante of the start point.
|
||||
* @param x1 The x coordinate of the end point.
|
||||
* @param y1 The y coordinate of the end point.
|
||||
* @param penX The width of the pen (thickness in the x direction)
|
||||
* @param penY The height of the pen (thickness in the y direction)
|
||||
* @param color The color of the line.
|
||||
* @note This is just a wrapper around Graphics::drawThickLine
|
||||
* @note The x/y coordinates of the start and end points are the upper-left most part of the pen
|
||||
*/
|
||||
void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, uint32 color);
|
||||
|
||||
/**
|
||||
* Draw a horizontal line.
|
||||
*
|
||||
|
@ -83,129 +83,127 @@
|
||||
// BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
|
||||
// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/singleton.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/yuv_to_rgb.h"
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(Graphics::YUVToRGBManager);
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
class YUVToRGBLookup {
|
||||
public:
|
||||
YUVToRGBLookup(Graphics::PixelFormat format);
|
||||
~YUVToRGBLookup();
|
||||
YUVToRGBLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale);
|
||||
|
||||
int16 *_colorTab;
|
||||
uint32 *_rgbToPix;
|
||||
Graphics::PixelFormat getFormat() const { return _format; }
|
||||
YUVToRGBManager::LuminanceScale getScale() const { return _scale; }
|
||||
const uint32 *getRGBToPix() const { return _rgbToPix; }
|
||||
|
||||
private:
|
||||
Graphics::PixelFormat _format;
|
||||
YUVToRGBManager::LuminanceScale _scale;
|
||||
uint32 _rgbToPix[3 * 768]; // 9216 bytes
|
||||
};
|
||||
|
||||
YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) {
|
||||
_colorTab = new int16[4 * 256]; // 2048 bytes
|
||||
YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale) {
|
||||
_format = format;
|
||||
_scale = scale;
|
||||
|
||||
uint32 *r_2_pix_alloc = &_rgbToPix[0 * 768];
|
||||
uint32 *g_2_pix_alloc = &_rgbToPix[1 * 768];
|
||||
uint32 *b_2_pix_alloc = &_rgbToPix[2 * 768];
|
||||
|
||||
if (scale == YUVToRGBManager::kScaleFull) {
|
||||
// Set up entries 0-255 in rgb-to-pixel value tables.
|
||||
for (int i = 0; i < 256; i++) {
|
||||
r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0);
|
||||
g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0);
|
||||
b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i);
|
||||
}
|
||||
|
||||
// Spread out the values we have to the rest of the array so that we do
|
||||
// not need to check for overflow.
|
||||
for (int i = 0; i < 256; i++) {
|
||||
r_2_pix_alloc[i] = r_2_pix_alloc[256];
|
||||
r_2_pix_alloc[i + 512] = r_2_pix_alloc[511];
|
||||
g_2_pix_alloc[i] = g_2_pix_alloc[256];
|
||||
g_2_pix_alloc[i + 512] = g_2_pix_alloc[511];
|
||||
b_2_pix_alloc[i] = b_2_pix_alloc[256];
|
||||
b_2_pix_alloc[i + 512] = b_2_pix_alloc[511];
|
||||
}
|
||||
} else {
|
||||
// Set up entries 16-235 in rgb-to-pixel value tables
|
||||
for (int i = 16; i < 236; i++) {
|
||||
int scaledValue = (i - 16) * 255 / 219;
|
||||
r_2_pix_alloc[i + 256] = format.RGBToColor(scaledValue, 0, 0);
|
||||
g_2_pix_alloc[i + 256] = format.RGBToColor(0, scaledValue, 0);
|
||||
b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, scaledValue);
|
||||
}
|
||||
|
||||
// Spread out the values we have to the rest of the array so that we do
|
||||
// not need to check for overflow. We have to do it here in two steps.
|
||||
for (int i = 0; i < 256 + 16; i++) {
|
||||
r_2_pix_alloc[i] = r_2_pix_alloc[256 + 16];
|
||||
g_2_pix_alloc[i] = g_2_pix_alloc[256 + 16];
|
||||
b_2_pix_alloc[i] = b_2_pix_alloc[256 + 16];
|
||||
}
|
||||
|
||||
for (int i = 256 + 236; i < 768; i++) {
|
||||
r_2_pix_alloc[i] = r_2_pix_alloc[256 + 236 - 1];
|
||||
g_2_pix_alloc[i] = g_2_pix_alloc[256 + 236 - 1];
|
||||
b_2_pix_alloc[i] = b_2_pix_alloc[256 + 236 - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
YUVToRGBManager::YUVToRGBManager() {
|
||||
_lookup = 0;
|
||||
|
||||
int16 *Cr_r_tab = &_colorTab[0 * 256];
|
||||
int16 *Cr_g_tab = &_colorTab[1 * 256];
|
||||
int16 *Cb_g_tab = &_colorTab[2 * 256];
|
||||
int16 *Cb_b_tab = &_colorTab[3 * 256];
|
||||
|
||||
_rgbToPix = new uint32[3 * 768]; // 9216 bytes
|
||||
|
||||
uint32 *r_2_pix_alloc = &_rgbToPix[0 * 768];
|
||||
uint32 *g_2_pix_alloc = &_rgbToPix[1 * 768];
|
||||
uint32 *b_2_pix_alloc = &_rgbToPix[2 * 768];
|
||||
|
||||
int16 CR, CB;
|
||||
int i;
|
||||
|
||||
// Generate the tables for the display surface
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
// Gamma correction (luminescence table) and chroma correction
|
||||
// would be done here. See the Berkeley mpeg_play sources.
|
||||
|
||||
CR = CB = (i - 128);
|
||||
int16 CR = (i - 128), CB = CR;
|
||||
Cr_r_tab[i] = (int16) ( (0.419 / 0.299) * CR) + 0 * 768 + 256;
|
||||
Cr_g_tab[i] = (int16) (-(0.299 / 0.419) * CR) + 1 * 768 + 256;
|
||||
Cb_g_tab[i] = (int16) (-(0.114 / 0.331) * CB);
|
||||
Cb_b_tab[i] = (int16) ( (0.587 / 0.331) * CB) + 2 * 768 + 256;
|
||||
}
|
||||
|
||||
// Set up entries 0-255 in rgb-to-pixel value tables.
|
||||
for (i = 0; i < 256; i++) {
|
||||
r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0);
|
||||
g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0);
|
||||
b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i);
|
||||
}
|
||||
|
||||
// Spread out the values we have to the rest of the array so that we do
|
||||
// not need to check for overflow.
|
||||
for (i = 0; i < 256; i++) {
|
||||
r_2_pix_alloc[i] = r_2_pix_alloc[256];
|
||||
r_2_pix_alloc[i + 512] = r_2_pix_alloc[511];
|
||||
g_2_pix_alloc[i] = g_2_pix_alloc[256];
|
||||
g_2_pix_alloc[i + 512] = g_2_pix_alloc[511];
|
||||
b_2_pix_alloc[i] = b_2_pix_alloc[256];
|
||||
b_2_pix_alloc[i + 512] = b_2_pix_alloc[511];
|
||||
}
|
||||
}
|
||||
|
||||
YUVToRGBLookup::~YUVToRGBLookup() {
|
||||
delete[] _rgbToPix;
|
||||
delete[] _colorTab;
|
||||
}
|
||||
|
||||
class YUVToRGBManager : public Common::Singleton<YUVToRGBManager> {
|
||||
public:
|
||||
const YUVToRGBLookup *getLookup(Graphics::PixelFormat format);
|
||||
|
||||
private:
|
||||
friend class Common::Singleton<SingletonBaseType>;
|
||||
YUVToRGBManager();
|
||||
~YUVToRGBManager();
|
||||
|
||||
Graphics::PixelFormat _lastFormat;
|
||||
YUVToRGBLookup *_lookup;
|
||||
};
|
||||
|
||||
YUVToRGBManager::YUVToRGBManager() {
|
||||
_lookup = 0;
|
||||
}
|
||||
|
||||
YUVToRGBManager::~YUVToRGBManager() {
|
||||
delete _lookup;
|
||||
}
|
||||
|
||||
const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format) {
|
||||
if (_lastFormat == format)
|
||||
const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale) {
|
||||
if (_lookup && _lookup->getFormat() == format && _lookup->getScale() == scale)
|
||||
return _lookup;
|
||||
|
||||
delete _lookup;
|
||||
_lookup = new YUVToRGBLookup(format);
|
||||
_lastFormat = format;
|
||||
_lookup = new YUVToRGBLookup(format, scale);
|
||||
return _lookup;
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(Graphics::YUVToRGBManager);
|
||||
}
|
||||
|
||||
#define YUVToRGBMan (Graphics::YUVToRGBManager::instance())
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
#define PUT_PIXEL(s, d) \
|
||||
L = &rgbToPix[(s)]; \
|
||||
*((PixelInt *)(d)) = (L[cr_r] | L[crb_g] | L[cb_b])
|
||||
|
||||
template<typename PixelInt>
|
||||
void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
// Keep the tables in pointers here to avoid a dereference on each pixel
|
||||
const int16 *Cr_r_tab = lookup->_colorTab;
|
||||
const int16 *Cr_r_tab = colorTab;
|
||||
const int16 *Cr_g_tab = Cr_r_tab + 256;
|
||||
const int16 *Cb_g_tab = Cr_g_tab + 256;
|
||||
const int16 *Cb_b_tab = Cb_g_tab + 256;
|
||||
const uint32 *rgbToPix = lookup->_rgbToPix;
|
||||
const uint32 *rgbToPix = lookup->getRGBToPix();
|
||||
|
||||
for (int h = 0; h < yHeight; h++) {
|
||||
for (int w = 0; w < yWidth; w++) {
|
||||
@ -229,32 +227,32 @@ void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup
|
||||
}
|
||||
}
|
||||
|
||||
void convertYUV444ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
void YUVToRGBManager::convert444(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
// Sanity checks
|
||||
assert(dst && dst->pixels);
|
||||
assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
|
||||
assert(ySrc && uSrc && vSrc);
|
||||
|
||||
const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format);
|
||||
const YUVToRGBLookup *lookup = getLookup(dst->format, scale);
|
||||
|
||||
// Use a templated function to avoid an if check on every pixel
|
||||
if (dst->format.bytesPerPixel == 2)
|
||||
convertYUV444ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
convertYUV444ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
else
|
||||
convertYUV444ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
convertYUV444ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
}
|
||||
|
||||
template<typename PixelInt>
|
||||
void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
int halfHeight = yHeight >> 1;
|
||||
int halfWidth = yWidth >> 1;
|
||||
|
||||
// Keep the tables in pointers here to avoid a dereference on each pixel
|
||||
const int16 *Cr_r_tab = lookup->_colorTab;
|
||||
const int16 *Cr_r_tab = colorTab;
|
||||
const int16 *Cr_g_tab = Cr_r_tab + 256;
|
||||
const int16 *Cb_g_tab = Cr_g_tab + 256;
|
||||
const int16 *Cb_b_tab = Cb_g_tab + 256;
|
||||
const uint32 *rgbToPix = lookup->_rgbToPix;
|
||||
const uint32 *rgbToPix = lookup->getRGBToPix();
|
||||
|
||||
for (int h = 0; h < halfHeight; h++) {
|
||||
for (int w = 0; w < halfWidth; w++) {
|
||||
@ -283,7 +281,7 @@ void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup
|
||||
}
|
||||
}
|
||||
|
||||
void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
void YUVToRGBManager::convert420(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
// Sanity checks
|
||||
assert(dst && dst->pixels);
|
||||
assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
|
||||
@ -291,13 +289,13 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS
|
||||
assert((yWidth & 1) == 0);
|
||||
assert((yHeight & 1) == 0);
|
||||
|
||||
const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format);
|
||||
const YUVToRGBLookup *lookup = getLookup(dst->format, scale);
|
||||
|
||||
// Use a templated function to avoid an if check on every pixel
|
||||
if (dst->format.bytesPerPixel == 2)
|
||||
convertYUV420ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
convertYUV420ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
else
|
||||
convertYUV420ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
convertYUV420ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
}
|
||||
|
||||
#define READ_QUAD(ptr, prefix) \
|
||||
@ -325,13 +323,13 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS
|
||||
xDiff++
|
||||
|
||||
template<typename PixelInt>
|
||||
void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
// Keep the tables in pointers here to avoid a dereference on each pixel
|
||||
const int16 *Cr_r_tab = lookup->_colorTab;
|
||||
const int16 *Cr_r_tab = colorTab;
|
||||
const int16 *Cr_g_tab = Cr_r_tab + 256;
|
||||
const int16 *Cb_g_tab = Cr_g_tab + 256;
|
||||
const int16 *Cb_b_tab = Cb_g_tab + 256;
|
||||
const uint32 *rgbToPix = lookup->_rgbToPix;
|
||||
const uint32 *rgbToPix = lookup->getRGBToPix();
|
||||
|
||||
int quarterWidth = yWidth >> 2;
|
||||
|
||||
@ -368,7 +366,7 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup
|
||||
#undef DO_INTERPOLATION
|
||||
#undef DO_YUV410_PIXEL
|
||||
|
||||
void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
void YUVToRGBManager::convert410(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
// Sanity checks
|
||||
assert(dst && dst->pixels);
|
||||
assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
|
||||
@ -376,13 +374,13 @@ void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS
|
||||
assert((yWidth & 3) == 0);
|
||||
assert((yHeight & 3) == 0);
|
||||
|
||||
const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format);
|
||||
const YUVToRGBLookup *lookup = getLookup(dst->format, scale);
|
||||
|
||||
// Use a templated function to avoid an if check on every pixel
|
||||
if (dst->format.bytesPerPixel == 2)
|
||||
convertYUV410ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
convertYUV410ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
else
|
||||
convertYUV410ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
convertYUV410ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
@ -32,57 +32,85 @@
|
||||
#define GRAPHICS_YUV_TO_RGB_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/singleton.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
/**
|
||||
* Convert a YUV444 image to an RGB surface
|
||||
*
|
||||
* @param dst the destination surface
|
||||
* @param ySrc the source of the y component
|
||||
* @param uSrc the source of the u component
|
||||
* @param vSrc the source of the v component
|
||||
* @param yWidth the width of the y surface
|
||||
* @param yHeight the height of the y surface
|
||||
* @param yPitch the pitch of the y surface
|
||||
* @param uvPitch the pitch of the u and v surfaces
|
||||
*/
|
||||
void convertYUV444ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
|
||||
class YUVToRGBLookup;
|
||||
|
||||
/**
|
||||
* Convert a YUV420 image to an RGB surface
|
||||
*
|
||||
* @param dst the destination surface
|
||||
* @param ySrc the source of the y component
|
||||
* @param uSrc the source of the u component
|
||||
* @param vSrc the source of the v component
|
||||
* @param yWidth the width of the y surface (must be divisible by 2)
|
||||
* @param yHeight the height of the y surface (must be divisible by 2)
|
||||
* @param yPitch the pitch of the y surface
|
||||
* @param uvPitch the pitch of the u and v surfaces
|
||||
*/
|
||||
void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
|
||||
class YUVToRGBManager : public Common::Singleton<YUVToRGBManager> {
|
||||
public:
|
||||
/** The scale of the luminance values */
|
||||
enum LuminanceScale {
|
||||
kScaleFull, /** Luminance values range from [0, 255] */
|
||||
kScaleITU /** Luminance values range from [16, 235], the range from ITU-R BT.601 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a YUV410 image to an RGB surface
|
||||
*
|
||||
* Since the chroma has a very low resolution in 410, we perform bilinear scaling
|
||||
* on the two chroma planes to produce the image. The chroma planes must have
|
||||
* at least one extra row that can be read from in order to produce a proper
|
||||
* image (filled with 0x80). This is required in order to speed up this function.
|
||||
*
|
||||
* @param dst the destination surface
|
||||
* @param ySrc the source of the y component
|
||||
* @param uSrc the source of the u component
|
||||
* @param vSrc the source of the v component
|
||||
* @param yWidth the width of the y surface (must be divisible by 4)
|
||||
* @param yHeight the height of the y surface (must be divisible by 4)
|
||||
* @param yPitch the pitch of the y surface
|
||||
* @param uvPitch the pitch of the u and v surfaces
|
||||
*/
|
||||
void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
|
||||
/**
|
||||
* Convert a YUV444 image to an RGB surface
|
||||
*
|
||||
* @param dst the destination surface
|
||||
* @param scale the scale of the luminance values
|
||||
* @param ySrc the source of the y component
|
||||
* @param uSrc the source of the u component
|
||||
* @param vSrc the source of the v component
|
||||
* @param yWidth the width of the y surface
|
||||
* @param yHeight the height of the y surface
|
||||
* @param yPitch the pitch of the y surface
|
||||
* @param uvPitch the pitch of the u and v surfaces
|
||||
*/
|
||||
void convert444(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
|
||||
|
||||
/**
|
||||
* Convert a YUV420 image to an RGB surface
|
||||
*
|
||||
* @param dst the destination surface
|
||||
* @param scale the scale of the luminance values
|
||||
* @param ySrc the source of the y component
|
||||
* @param uSrc the source of the u component
|
||||
* @param vSrc the source of the v component
|
||||
* @param yWidth the width of the y surface (must be divisible by 2)
|
||||
* @param yHeight the height of the y surface (must be divisible by 2)
|
||||
* @param yPitch the pitch of the y surface
|
||||
* @param uvPitch the pitch of the u and v surfaces
|
||||
*/
|
||||
void convert420(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
|
||||
|
||||
/**
|
||||
* Convert a YUV410 image to an RGB surface
|
||||
*
|
||||
* Since the chroma has a very low resolution in 410, we perform bilinear scaling
|
||||
* on the two chroma planes to produce the image. The chroma planes must have
|
||||
* at least one extra row and one extra column that can be read from in order to
|
||||
* produce a proper image. It is suggested that you fill these in with the previous
|
||||
* row and column's data. This is required in order to speed up this function.
|
||||
*
|
||||
* @param dst the destination surface
|
||||
* @param scale the scale of the luminance values
|
||||
* @param ySrc the source of the y component
|
||||
* @param uSrc the source of the u component
|
||||
* @param vSrc the source of the v component
|
||||
* @param yWidth the width of the y surface (must be divisible by 4)
|
||||
* @param yHeight the height of the y surface (must be divisible by 4)
|
||||
* @param yPitch the pitch of the y surface
|
||||
* @param uvPitch the pitch of the u and v surfaces
|
||||
*/
|
||||
void convert410(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
|
||||
|
||||
private:
|
||||
friend class Common::Singleton<SingletonBaseType>;
|
||||
YUVToRGBManager();
|
||||
~YUVToRGBManager();
|
||||
|
||||
const YUVToRGBLookup *getLookup(Graphics::PixelFormat format, LuminanceScale scale);
|
||||
|
||||
YUVToRGBLookup *_lookup;
|
||||
int16 _colorTab[4 * 256]; // 2048 bytes
|
||||
};
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
#define YUVToRGBMan (::Graphics::YUVToRGBManager::instance())
|
||||
|
||||
#endif
|
||||
|
@ -548,11 +548,11 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
|
||||
else
|
||||
return parserError("'" + stepNode->values["fill"] + "' is not a valid fill mode for a shape.");
|
||||
}
|
||||
|
||||
|
||||
if (stepNode->values.contains("padding")) {
|
||||
val = stepNode->values["padding"];
|
||||
int pr, pt, pl, pb;
|
||||
if (parseIntegerKey(val, 4, &pl, &pt, &pr, &pb))
|
||||
if (parseIntegerKey(val, 4, &pl, &pt, &pr, &pb))
|
||||
drawstep->padding.left = pl,
|
||||
drawstep->padding.top = pt,
|
||||
drawstep->padding.right = pr,
|
||||
|
@ -139,7 +139,7 @@ protected:
|
||||
XML_PROP(height, false)
|
||||
XML_PROP(xpos, false)
|
||||
XML_PROP(ypos, false)
|
||||
XML_PROP(padding, false)
|
||||
XML_PROP(padding, false)
|
||||
XML_PROP(orientation, false)
|
||||
XML_PROP(file, false)
|
||||
KEY_END()
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
protected:
|
||||
#ifdef MACOSX
|
||||
const void *_titleRef;
|
||||
const void *_chooseRef;
|
||||
#else
|
||||
ListWidget *_fileList;
|
||||
StaticTextWidget *_currentPath;
|
||||
|
@ -28,20 +28,39 @@
|
||||
#include "common/config-manager.h"
|
||||
#include "common/system.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include <AppKit/NSOpenPanel.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSURL.h>
|
||||
|
||||
namespace GUI {
|
||||
|
||||
BrowserDialog::BrowserDialog(const char *title, bool dirBrowser)
|
||||
: Dialog("Browser") {
|
||||
_titleRef = CFStringCreateWithCString(0, title, CFStringGetSystemEncoding());
|
||||
|
||||
// remember whether this is a file browser or a directory browser.
|
||||
_isDirBrowser = dirBrowser;
|
||||
|
||||
// Get current encoding
|
||||
#ifdef USE_TRANSLATION
|
||||
CFStringRef encStr = CFStringCreateWithCString(NULL, TransMan.getCurrentCharset().c_str(), kCFStringEncodingASCII);
|
||||
CFStringEncoding stringEncoding = CFStringConvertIANACharSetNameToEncoding(encStr);
|
||||
CFRelease(encStr);
|
||||
#else
|
||||
CFStringEncoding stringEncoding = kCFStringEncodingASCII;
|
||||
#endif
|
||||
|
||||
// Convert title to NSString
|
||||
_titleRef = CFStringCreateWithCString(0, title, stringEncoding);
|
||||
|
||||
// Convert button text to NSString
|
||||
_chooseRef = CFStringCreateWithCString(0, _("Choose"), stringEncoding);
|
||||
}
|
||||
|
||||
BrowserDialog::~BrowserDialog() {
|
||||
CFRelease(_titleRef);
|
||||
CFRelease(_chooseRef);
|
||||
}
|
||||
|
||||
int BrowserDialog::runModal() {
|
||||
@ -58,16 +77,20 @@ int BrowserDialog::runModal() {
|
||||
// Temporarily show the real mouse
|
||||
CGDisplayShowCursor(kCGDirectMainDisplay);
|
||||
|
||||
|
||||
NSOpenPanel * panel = [NSOpenPanel openPanel];
|
||||
[panel setCanChooseDirectories:YES];
|
||||
if ([panel runModalForTypes:nil] == NSOKButton) {
|
||||
const char *filename = [[panel filename] UTF8String];
|
||||
_choice = Common::FSNode(filename);
|
||||
choiceMade = true;
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setCanChooseFiles:!_isDirBrowser];
|
||||
[panel setCanChooseDirectories:_isDirBrowser];
|
||||
[panel setTitle:(NSString *)_titleRef];
|
||||
[panel setPrompt:(NSString *)_chooseRef];
|
||||
if ([panel runModal] == NSOKButton) {
|
||||
NSURL *url = [panel URL];
|
||||
if ([url isFileURL]) {
|
||||
const char *filename = [[url path] UTF8String];
|
||||
_choice = Common::FSNode(filename);
|
||||
choiceMade = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If we were in fullscreen mode, switch back
|
||||
if (wasFullscreen) {
|
||||
g_system->beginGFXTransaction();
|
||||
|
@ -166,7 +166,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
} else {
|
||||
warning("Plugin for target \"%s\" not found! Game specific settings might be missing", domain.c_str());
|
||||
}
|
||||
|
||||
|
||||
// GAME: Path to game data (r/o), extra data (r/o), and save data (r/w)
|
||||
String gamePath(ConfMan.get("path", _domain));
|
||||
String extraPath(ConfMan.get("extrapath", _domain));
|
||||
|
@ -898,7 +898,7 @@ void OptionsDialog::addEngineControls(GuiObject *boss, const Common::String &pre
|
||||
ExtraGuiOptions::const_iterator iter;
|
||||
for (iter = engineOptions.begin(); iter != engineOptions.end(); ++iter, ++i) {
|
||||
Common::String id = Common::String::format("%d", i);
|
||||
_engineCheckboxes.push_back(new CheckboxWidget(boss,
|
||||
_engineCheckboxes.push_back(new CheckboxWidget(boss,
|
||||
prefix + "customOption" + id + "Checkbox", _(iter->label), _(iter->tooltip)));
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
|
||||
|
||||
_btns = (ButtonWidget **)calloc(1, sizeof(ButtonWidget *) * 16);
|
||||
|
||||
_btns[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd);
|
||||
_btns[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd);
|
||||
_btns[kOkAct] = new ButtonWidget(this, "Predictive.OK", _("Ok") , 0, kOkCmd);
|
||||
_btns[kBtn1Act] = new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , 0, kBut1Cmd);
|
||||
_btns[kBtn2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , 0, kBut2Cmd);
|
||||
@ -84,10 +84,10 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
|
||||
_btns[kBtn9Act] = new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , 0, kBut9Cmd);
|
||||
_btns[kBtn0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , 0, kBut0Cmd);
|
||||
// I18N: You must leave "#" as is, only word 'next' is translatable
|
||||
_btns[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , 0, kNextCmd);
|
||||
_btns[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , 0, kNextCmd);
|
||||
_btns[kAddAct] = new ButtonWidget(this, "Predictive.Add", _("add") , 0, kAddCmd);
|
||||
_btns[kAddAct]->setEnabled(false);
|
||||
|
||||
|
||||
#ifndef DISABLE_FANCY_THEMES
|
||||
_btns[kDelAct] = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd);
|
||||
((PicButtonWidget *)_btns[kDelAct])->useThemeTransparency(true);
|
||||
@ -214,7 +214,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
|
||||
_navigationwithkeys = true;
|
||||
if (_lastbutton == kBtn1Act || _lastbutton == kBtn4Act || _lastbutton == kBtn7Act)
|
||||
_currBtn = ButtonId(_lastbutton + 2);
|
||||
else if (_lastbutton == kDelAct)
|
||||
else if (_lastbutton == kDelAct)
|
||||
_currBtn = kBtn1Act;
|
||||
else if (_lastbutton == kModeAct)
|
||||
_currBtn = kNextAct;
|
||||
@ -227,7 +227,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
|
||||
else
|
||||
_currBtn = ButtonId(_lastbutton - 1);
|
||||
|
||||
|
||||
|
||||
if (_mode != kModeAbc && _lastbutton == kCancelAct)
|
||||
_currBtn = kOkAct;
|
||||
|
||||
@ -237,7 +237,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
|
||||
_navigationwithkeys = true;
|
||||
if (_lastbutton == kBtn3Act || _lastbutton == kBtn6Act || _lastbutton == kBtn9Act || _lastbutton == kOkAct)
|
||||
_currBtn = ButtonId(_lastbutton - 2);
|
||||
else if (_lastbutton == kDelAct)
|
||||
else if (_lastbutton == kDelAct)
|
||||
_currBtn = kBtn3Act;
|
||||
else if (_lastbutton == kBtn0Act)
|
||||
_currBtn = kNextAct;
|
||||
@ -249,7 +249,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
|
||||
_currBtn = kAddAct;
|
||||
else
|
||||
_currBtn = ButtonId(_lastbutton + 1);
|
||||
|
||||
|
||||
if (_mode != kModeAbc && _lastbutton == kOkAct)
|
||||
_currBtn = kCancelAct;
|
||||
_needRefresh = true;
|
||||
@ -260,7 +260,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
|
||||
_currBtn = kDelAct;
|
||||
else if (_lastbutton == kDelAct)
|
||||
_currBtn = kOkAct;
|
||||
else if (_lastbutton == kModeAct)
|
||||
else if (_lastbutton == kModeAct)
|
||||
_currBtn = kBtn7Act;
|
||||
else if (_lastbutton == kBtn0Act)
|
||||
_currBtn = kBtn8Act;
|
||||
@ -286,7 +286,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
|
||||
_currBtn = kBtn0Act;
|
||||
else if (_lastbutton == kBtn9Act)
|
||||
_currBtn = kNextAct;
|
||||
else if (_lastbutton == kModeAct)
|
||||
else if (_lastbutton == kModeAct)
|
||||
_currBtn = kAddAct;
|
||||
else if (_lastbutton == kBtn0Act)
|
||||
_currBtn = kCancelAct;
|
||||
|
@ -35,6 +35,14 @@ namespace GUI {
|
||||
#ifndef DISABLE_SAVELOADCHOOSER_GRID
|
||||
SaveLoadChooserType getRequestedSaveLoadDialog(const MetaEngine &metaEngine) {
|
||||
const Common::String &userConfig = ConfMan.get("gui_saveload_chooser", Common::ConfigManager::kApplicationDomain);
|
||||
|
||||
// Check (and update if necessary) the theme config here. This catches
|
||||
// resolution changes, which happened after the GUI was closed. This
|
||||
// should assure that the correct GUI width/height are returned below and
|
||||
// prevent the logic from picking the grid dialog, even though it is not
|
||||
// possible to use it.
|
||||
g_gui.checkScreenChange();
|
||||
|
||||
if (g_gui.getWidth() >= 640 && g_gui.getHeight() >= 400
|
||||
&& metaEngine.hasFeature(MetaEngine::kSavesSupportMetaInfo)
|
||||
&& metaEngine.hasFeature(MetaEngine::kSavesSupportThumbnail)
|
||||
@ -422,7 +430,28 @@ void SaveLoadChooserSimple::updateSelection(bool redraw) {
|
||||
}
|
||||
}
|
||||
|
||||
void SaveLoadChooserSimple::open() {
|
||||
SaveLoadChooserDialog::open();
|
||||
|
||||
// Scroll the list to the last used entry.
|
||||
_list->scrollTo(ConfMan.getInt("gui_saveload_last_pos"));
|
||||
}
|
||||
|
||||
void SaveLoadChooserSimple::close() {
|
||||
// Save the current scroll position/used entry.
|
||||
const int result = getResult();
|
||||
if (result >= 0) {
|
||||
ConfMan.setInt("gui_saveload_last_pos", result);
|
||||
} else {
|
||||
// Use the current scroll position here.
|
||||
// TODO: This means we canceled the dialog (or switch to the grid). Do
|
||||
// we want to save this position here? Does the user want that?
|
||||
// TODO: Do we want to save the current scroll position or the
|
||||
// currently selected item here? The scroll position is what the user
|
||||
// currently sees and seems to make more sense.
|
||||
ConfMan.setInt("gui_saveload_last_pos", _list->getCurrentScrollPos());
|
||||
}
|
||||
|
||||
_metaEngine = 0;
|
||||
_target.clear();
|
||||
_saveList.clear();
|
||||
@ -590,10 +619,29 @@ void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) {
|
||||
void SaveLoadChooserGrid::open() {
|
||||
SaveLoadChooserDialog::open();
|
||||
|
||||
_curPage = 0;
|
||||
_saveList = _metaEngine->listSaves(_target.c_str());
|
||||
_resultString.clear();
|
||||
|
||||
// Load information to restore the last page the user had open.
|
||||
assert(_entriesPerPage != 0);
|
||||
const uint lastPos = ConfMan.getInt("gui_saveload_last_pos");
|
||||
const uint listSize = _saveList.size();
|
||||
uint bestMatch = 0;
|
||||
uint diff = 0xFFFFFFFF;
|
||||
|
||||
// We look for the nearest available slot, since a slot might be missing
|
||||
// due to the user deleting it via the list based chooser, by deleting
|
||||
// it by hand, etc.
|
||||
for (uint i = 0; i < listSize; ++i) {
|
||||
uint curDiff = ABS(_saveList[i].getSaveSlot() - (int)lastPos);
|
||||
if (curDiff < diff) {
|
||||
diff = curDiff;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
|
||||
_curPage = bestMatch / _entriesPerPage;
|
||||
|
||||
// Determine the next free save slot for save mode
|
||||
if (_saveMode) {
|
||||
int lastSlot = -1;
|
||||
@ -703,7 +751,7 @@ void SaveLoadChooserGrid::reflowLayout() {
|
||||
if (!_saveMode) {
|
||||
buttonCmd += 1;
|
||||
}
|
||||
|
||||
|
||||
PicButtonWidget *button = new PicButtonWidget(container, dstX, dstY, buttonWidth, buttonHeight, 0, buttonCmd);
|
||||
dstY += buttonHeight;
|
||||
|
||||
@ -718,6 +766,24 @@ void SaveLoadChooserGrid::reflowLayout() {
|
||||
}
|
||||
|
||||
void SaveLoadChooserGrid::close() {
|
||||
// Save the current page.
|
||||
const int result = getResult();
|
||||
if (result >= 0 && result != _nextFreeSaveSlot) {
|
||||
// If the user selected a slot we use that one. We ignore new slots
|
||||
// here, since otherwise the dialog would reset to page 0 when the
|
||||
// user cancels the savename dialog.
|
||||
ConfMan.setInt("gui_saveload_last_pos", result);
|
||||
} else {
|
||||
// Otherwise save the first entry on the current page.
|
||||
// This is less precise than the solution above, since the number of
|
||||
// entries shown differs between save and load version of the dialog,
|
||||
// thus it might wrap to a different page than expected.
|
||||
// Similar things happen on resolution changes.
|
||||
// TODO: Should we ignore this here? Is the user likely to be
|
||||
// interested in having this page restored when he canceled?
|
||||
ConfMan.setInt("gui_saveload_last_pos", !_saveList.empty() ? _saveList[_curPage * _entriesPerPage].getSaveSlot() : 0);
|
||||
}
|
||||
|
||||
SaveLoadChooserDialog::close();
|
||||
hideButtons();
|
||||
}
|
||||
@ -737,6 +803,12 @@ int SaveLoadChooserGrid::runIntern() {
|
||||
slot = runModal();
|
||||
} while (_saveMode && slot >= 0 && !selectDescription());
|
||||
|
||||
// Special case for new save games. We need to handle this here, since
|
||||
// we cannot handle it in close() without problems.
|
||||
if (slot == _nextFreeSaveSlot) {
|
||||
ConfMan.setInt("gui_saveload_last_pos", slot);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
@ -826,7 +898,7 @@ void SaveLoadChooserGrid::updateSaves() {
|
||||
}
|
||||
}
|
||||
|
||||
const uint numPages = (_entriesPerPage != 0) ? (_saveList.size() / _entriesPerPage + 1) : 1;
|
||||
const uint numPages = (_entriesPerPage != 0 && !_saveList.empty()) ? ((_saveList.size() + _entriesPerPage - 1) / _entriesPerPage) : 1;
|
||||
_pageDisplay->setLabel(Common::String::format("%u/%u", _curPage + 1, numPages));
|
||||
|
||||
if (_curPage > 0)
|
||||
|
@ -103,6 +103,7 @@ public:
|
||||
virtual SaveLoadChooserType getType() const { return kSaveLoadDialogList; }
|
||||
#endif // !DISABLE_SAVELOADCHOOSER_GRID
|
||||
|
||||
virtual void open();
|
||||
virtual void close();
|
||||
private:
|
||||
virtual int runIntern();
|
||||
|
@ -366,7 +366,7 @@ void ButtonWidget::startAnimatePressedState() {
|
||||
}
|
||||
|
||||
void ButtonWidget::wantTickle(bool tickled) {
|
||||
if (tickled)
|
||||
if (tickled)
|
||||
((GUI::Dialog *)_boss)->setTickleWidget(this);
|
||||
else
|
||||
((GUI::Dialog *)_boss)->unSetTickleWidget();
|
||||
@ -376,7 +376,7 @@ void ButtonWidget::wantTickle(bool tickled) {
|
||||
|
||||
PicButtonWidget::PicButtonWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip, uint32 cmd, uint8 hotkey)
|
||||
: ButtonWidget(boss, x, y, w, h, "", tooltip, cmd, hotkey),
|
||||
_gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
|
||||
_gfx(), _alpha(256), _transparency(false) {
|
||||
|
||||
setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
|
||||
_type = kButtonWidget;
|
||||
@ -384,18 +384,17 @@ PicButtonWidget::PicButtonWidget(GuiObject *boss, int x, int y, int w, int h, co
|
||||
|
||||
PicButtonWidget::PicButtonWidget(GuiObject *boss, const Common::String &name, const char *tooltip, uint32 cmd, uint8 hotkey)
|
||||
: ButtonWidget(boss, name, "", tooltip, cmd, hotkey),
|
||||
_gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
|
||||
_gfx(), _alpha(256), _transparency(false) {
|
||||
setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
|
||||
_type = kButtonWidget;
|
||||
}
|
||||
|
||||
PicButtonWidget::~PicButtonWidget() {
|
||||
_gfx->free();
|
||||
delete _gfx;
|
||||
_gfx.free();
|
||||
}
|
||||
|
||||
void PicButtonWidget::setGfx(const Graphics::Surface *gfx) {
|
||||
_gfx->free();
|
||||
_gfx.free();
|
||||
|
||||
if (!gfx || !gfx->pixels)
|
||||
return;
|
||||
@ -411,7 +410,7 @@ void PicButtonWidget::setGfx(const Graphics::Surface *gfx) {
|
||||
return;
|
||||
}
|
||||
|
||||
_gfx->copyFrom(*gfx);
|
||||
_gfx.copyFrom(*gfx);
|
||||
}
|
||||
|
||||
void PicButtonWidget::setGfx(int w, int h, int r, int g, int b) {
|
||||
@ -422,29 +421,26 @@ void PicButtonWidget::setGfx(int w, int h, int r, int g, int b) {
|
||||
|
||||
const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
|
||||
|
||||
_gfx->free();
|
||||
_gfx->create(w, h, requiredFormat);
|
||||
_gfx->fillRect(Common::Rect(0, 0, w, h), _gfx->format.RGBToColor(r, g, b));
|
||||
_gfx.free();
|
||||
_gfx.create(w, h, requiredFormat);
|
||||
_gfx.fillRect(Common::Rect(0, 0, w, h), _gfx.format.RGBToColor(r, g, b));
|
||||
}
|
||||
|
||||
void PicButtonWidget::drawWidget() {
|
||||
g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), "", _state, getFlags());
|
||||
|
||||
if (_gfx->pixels) {
|
||||
if (_gfx.pixels) {
|
||||
// Check whether the set up surface needs to be converted to the GUI
|
||||
// color format.
|
||||
const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
|
||||
if (_gfx->format != requiredFormat) {
|
||||
Graphics::Surface *converted = _gfx->convertTo(requiredFormat);
|
||||
_gfx->free();
|
||||
delete _gfx;
|
||||
_gfx = converted;
|
||||
if (_gfx.format != requiredFormat) {
|
||||
_gfx.convertToInPlace(requiredFormat);
|
||||
}
|
||||
|
||||
const int x = _x + (_w - _gfx->w) / 2;
|
||||
const int y = _y + (_h - _gfx->h) / 2;
|
||||
const int x = _x + (_w - _gfx.w) / 2;
|
||||
const int y = _y + (_h - _gfx.h) / 2;
|
||||
|
||||
g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx->w, y + _gfx->h), *_gfx, _state, _alpha, _transparency);
|
||||
g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency);
|
||||
}
|
||||
}
|
||||
|
||||
@ -632,24 +628,23 @@ int SliderWidget::posToValue(int pos) {
|
||||
#pragma mark -
|
||||
|
||||
GraphicsWidget::GraphicsWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip)
|
||||
: Widget(boss, x, y, w, h, tooltip), _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
|
||||
: Widget(boss, x, y, w, h, tooltip), _gfx(), _alpha(256), _transparency(false) {
|
||||
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG);
|
||||
_type = kGraphicsWidget;
|
||||
}
|
||||
|
||||
GraphicsWidget::GraphicsWidget(GuiObject *boss, const Common::String &name, const char *tooltip)
|
||||
: Widget(boss, name, tooltip), _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
|
||||
: Widget(boss, name, tooltip), _gfx(), _alpha(256), _transparency(false) {
|
||||
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG);
|
||||
_type = kGraphicsWidget;
|
||||
}
|
||||
|
||||
GraphicsWidget::~GraphicsWidget() {
|
||||
_gfx->free();
|
||||
delete _gfx;
|
||||
_gfx.free();
|
||||
}
|
||||
|
||||
void GraphicsWidget::setGfx(const Graphics::Surface *gfx) {
|
||||
_gfx->free();
|
||||
_gfx.free();
|
||||
|
||||
if (!gfx || !gfx->pixels)
|
||||
return;
|
||||
@ -664,7 +659,7 @@ void GraphicsWidget::setGfx(const Graphics::Surface *gfx) {
|
||||
return;
|
||||
}
|
||||
|
||||
_gfx->copyFrom(*gfx);
|
||||
_gfx.copyFrom(*gfx);
|
||||
}
|
||||
|
||||
void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) {
|
||||
@ -675,27 +670,24 @@ void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) {
|
||||
|
||||
const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
|
||||
|
||||
_gfx->free();
|
||||
_gfx->create(w, h, requiredFormat);
|
||||
_gfx->fillRect(Common::Rect(0, 0, w, h), _gfx->format.RGBToColor(r, g, b));
|
||||
_gfx.free();
|
||||
_gfx.create(w, h, requiredFormat);
|
||||
_gfx.fillRect(Common::Rect(0, 0, w, h), _gfx.format.RGBToColor(r, g, b));
|
||||
}
|
||||
|
||||
void GraphicsWidget::drawWidget() {
|
||||
if (_gfx->pixels) {
|
||||
if (_gfx.pixels) {
|
||||
// Check whether the set up surface needs to be converted to the GUI
|
||||
// color format.
|
||||
const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
|
||||
if (_gfx->format != requiredFormat) {
|
||||
Graphics::Surface *converted = _gfx->convertTo(requiredFormat);
|
||||
_gfx->free();
|
||||
delete _gfx;
|
||||
_gfx = converted;
|
||||
if (_gfx.format != requiredFormat) {
|
||||
_gfx.convertToInPlace(requiredFormat);
|
||||
}
|
||||
|
||||
const int x = _x + (_w - _gfx->w) / 2;
|
||||
const int y = _y + (_h - _gfx->h) / 2;
|
||||
const int x = _x + (_w - _gfx.w) / 2;
|
||||
const int y = _y + (_h - _gfx.h) / 2;
|
||||
|
||||
g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx->w, y + _gfx->h), *_gfx, _state, _alpha, _transparency);
|
||||
g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,7 +230,7 @@ public:
|
||||
protected:
|
||||
void drawWidget();
|
||||
|
||||
Graphics::Surface *_gfx;
|
||||
Graphics::Surface _gfx;
|
||||
int _alpha;
|
||||
bool _transparency;
|
||||
};
|
||||
@ -358,7 +358,7 @@ public:
|
||||
protected:
|
||||
void drawWidget();
|
||||
|
||||
Graphics::Surface *_gfx;
|
||||
Graphics::Surface _gfx;
|
||||
int _alpha;
|
||||
bool _transparency;
|
||||
};
|
||||
|
@ -77,10 +77,10 @@ public:
|
||||
protected:
|
||||
virtual void startEditMode() = 0;
|
||||
virtual void endEditMode() = 0;
|
||||
virtual void abortEditMode() = 0;
|
||||
virtual void abortEditMode() = 0;
|
||||
virtual Common::Rect getEditRect() const = 0;
|
||||
virtual int getCaretOffset() const;
|
||||
void drawCaret(bool erase);
|
||||
void drawCaret(bool erase);
|
||||
bool adjustOffset();
|
||||
void makeCaretVisible();
|
||||
|
||||
|
@ -105,6 +105,7 @@ public:
|
||||
|
||||
void scrollTo(int item);
|
||||
void scrollToEnd();
|
||||
int getCurrentScrollPos() const { return _currentPos; }
|
||||
|
||||
void enableQuickSelect(bool enable) { _quickSelect = enable; }
|
||||
String getQuickSelectString() const { return _quickSelectStr; }
|
||||
|
26
ports.mk
26
ports.mk
@ -7,6 +7,22 @@
|
||||
# POSIX specific
|
||||
#
|
||||
install:
|
||||
$(INSTALL) -d "$(DESTDIR)$(bindir)"
|
||||
$(INSTALL) -c -m 755 "./$(EXECUTABLE)" "$(DESTDIR)$(bindir)/$(EXECUTABLE)"
|
||||
$(INSTALL) -d "$(DESTDIR)$(mandir)/man6/"
|
||||
$(INSTALL) -c -m 644 "$(srcdir)/dists/residualvm.6" "$(DESTDIR)$(mandir)/man6/residualvm.6"
|
||||
$(INSTALL) -d "$(DESTDIR)$(datarootdir)/pixmaps/"
|
||||
$(INSTALL) -c -m 644 "$(srcdir)/icons/residualvm.xpm" "$(DESTDIR)$(datarootdir)/pixmaps/residualvm.xpm"
|
||||
$(INSTALL) -d "$(DESTDIR)$(docdir)"
|
||||
$(INSTALL) -c -m 644 $(DIST_FILES_DOCS) "$(DESTDIR)$(docdir)"
|
||||
$(INSTALL) -d "$(DESTDIR)$(datadir)"
|
||||
$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) "$(DESTDIR)$(datadir)/"
|
||||
ifdef DYNAMIC_MODULES
|
||||
$(INSTALL) -d "$(DESTDIR)$(libdir)/residualvm/"
|
||||
$(INSTALL) -c -m 644 $(PLUGINS) "$(DESTDIR)$(libdir)/residualvm/"
|
||||
endif
|
||||
|
||||
install-strip:
|
||||
$(INSTALL) -d "$(DESTDIR)$(bindir)"
|
||||
$(INSTALL) -c -s -m 755 "./$(EXECUTABLE)" "$(DESTDIR)$(bindir)/$(EXECUTABLE)"
|
||||
$(INSTALL) -d "$(DESTDIR)$(mandir)/man6/"
|
||||
@ -292,8 +308,10 @@ endif
|
||||
# Special target to create an AmigaOS snapshot installation
|
||||
aos4dist: $(EXECUTABLE)
|
||||
mkdir -p $(AOS4PATH)
|
||||
mkdir -p $(AOS4PATH)/themes
|
||||
mkdir -p $(AOS4PATH)/extras
|
||||
$(STRIP) $(EXECUTABLE) -o $(AOS4PATH)/$(EXECUTABLE)
|
||||
cp icons/residualvm.info $(AOS4PATH)/$(EXECUTABLE).info
|
||||
cp ${srcdir}/icons/residualvm.info $(AOS4PATH)/$(EXECUTABLE).info
|
||||
cp $(DIST_FILES_THEMES) $(AOS4PATH)/themes/
|
||||
ifdef DIST_FILES_ENGINEDATA
|
||||
cp $(DIST_FILES_ENGINEDATA) $(AOS4PATH)/extras/
|
||||
@ -303,8 +321,10 @@ endif
|
||||
# Special target to cross create an AmigaOS snapshot installation
|
||||
aos4dist-cross: $(EXECUTABLE)
|
||||
mkdir -p ResidualVM
|
||||
$(STRIP) $(EXECUTABLE) -o ResidualVM/ResidualVM
|
||||
cp icons/residualvm.info ResidualVM/ResidualVM.info
|
||||
mkdir -p $(AOS4PATH)/themes
|
||||
mkdir -p $(AOS4PATH)/extras
|
||||
$(STRIP) $(EXECUTABLE) -o $(AOS4PATH)/$(EXECUTABLE)
|
||||
cp ${srcdir}/icons/residualvm.info $(AOS4PATH)/$(EXECUTABLE).info
|
||||
cp $(DIST_FILES_THEMES) ResidualVM
|
||||
ifdef DIST_FILES_ENGINEDATA
|
||||
cp $(DIST_FILES_ENGINEDATA) ResidualVM
|
||||
|
@ -305,7 +305,7 @@ void BinkDecoder::videoPacket(VideoFrame &video) {
|
||||
// Convert the YUV data we have to our format
|
||||
// We're ignoring alpha for now
|
||||
assert(_curPlanes[0] && _curPlanes[1] && _curPlanes[2]);
|
||||
Graphics::convertYUV420ToRGB(&_surface, _curPlanes[0], _curPlanes[1], _curPlanes[2],
|
||||
YUVToRGBMan.convert420(&_surface, Graphics::YUVToRGBManager::kScaleITU, _curPlanes[0], _curPlanes[1], _curPlanes[2],
|
||||
_surface.w, _surface.h, _surface.w, _surface.w >> 1);
|
||||
|
||||
// And swap the planes with the reference planes
|
||||
|
Loading…
Reference in New Issue
Block a user